Ctrl K
ComunidadGuías…

Ferrite.TL.Schema/PublishedRequestMappers.cs

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
// SPDX-License-Identifier: AGPL-3.0-or-later
// Copyright (C) 2022-2026 Aykut Alparslan KOC

namespace Ferrite.TL.Schema;

public static class PublishedRequestMappers
{
    private static readonly object Gate = new object();
    private static readonly Dictionary<int, LayerRequestMapper> Mappers =
        new Dictionary<int, LayerRequestMapper>();
    private static readonly Dictionary<LayerEdge, LayerRequestEdge> Edges =
        new Dictionary<LayerEdge, LayerRequestEdge>();

    public static IReadOnlyList<LayerEdge> Route { get; } = CreateRoute();

    public static bool TryCreate(int layer, out LayerRequestMapper mapper)
    {
        int start = IndexOfSource(layer);
        if (start < 0)
        {
            mapper = null!;
            return false;
        }

        lock (Gate)
        {
            if (Mappers.TryGetValue(layer, out LayerRequestMapper? cached))
            {
                mapper = cached;
                return true;
            }

            var edges = new List<LayerRequestEdge>();
            for (int index = start; index < Route.Count; index++)
            {
                edges.Add(GetEdge(Route[index]));
            }
            mapper = new LayerRequestMapper(edges, LayerSchemaCatalog.CompatMethods);
            Mappers.Add(layer, mapper);
            return true;
        }
    }

    public static LayerRequestEdge GetEdge(LayerEdge edge)
    {
        lock (Gate)
        {
            if (Edges.TryGetValue(edge, out LayerRequestEdge? cached))
            {
                return cached;
            }
            if (!Route.Contains(edge))
            {
                throw new ArgumentException("The request route has no edge " + edge + ".",
                    nameof(edge));
            }

            var value = new LayerRequestEdge(LayerSchemaCatalog.Create(edge.Source),
                LayerSchemaCatalog.Create(edge.Target),
                PublishedRequestConverters.Defaults.Where(x => x.Edge.Equals(edge)),
                PublishedRequestConverters.Converters.Where(x => x.Edge.Equals(edge)));
            Edges.Add(edge, value);
            return value;
        }
    }

    private static IReadOnlyList<LayerEdge> CreateRoute()
    {
        IReadOnlyList<int> layers = LayerSchemaCatalog.Layers;
        var route = new List<LayerEdge>();
        for (int index = 1; index < layers.Count &&
                            layers[index - 1] < LayerSchemaCatalog.BaseLayer; index++)
        {
            route.Add(new LayerEdge(layers[index - 1], layers[index]));
        }
        RequireDeclarationsOnRoute(route);
        return route.AsReadOnly();
    }

    private static void RequireDeclarationsOnRoute(List<LayerEdge> route)
    {
        IEnumerable<LayerEdge> declared = PublishedRequestConverters.Defaults
            .Select(x => x.Edge)
            .Concat(PublishedRequestConverters.Converters.Select(x => x.Edge));
        foreach (LayerEdge edge in declared)
        {
            if (!route.Contains(edge))
            {
                throw new InvalidOperationException(
                    "A request declaration names an edge off the request route: " +
                    edge + ".");
            }
        }
    }

    private static int IndexOfSource(int layer)
    {
        for (int index = 0; index < Route.Count; index++)
        {
            if (Route[index].Source == layer)
            {
                return index;
            }
        }
        return -1;
    }
}