Ferrite.TL.Schema/LayerSchema.cs
Rama main · réplica de lectura del repositorio original.
// SPDX-License-Identifier: AGPL-3.0-or-later
// Copyright (C) 2022-2026 Aykut Alparslan KOC
using System.Collections.ObjectModel;
namespace Ferrite.TL.Schema;
public enum LayerWireKind
{
Int32,
Int64,
Double,
Int128,
Int256,
Int512,
Bytes,
String,
Flags,
True,
Object,
Vector
}
public sealed class LayerType
{
public LayerWireKind Kind { get; }
public string? Name { get; }
public bool IsBare { get; }
public LayerType? ElementType { get; }
public LayerType(LayerWireKind kind, string? name = null,
bool isBare = false, LayerType? elementType = null)
{
Kind = kind;
Name = name;
IsBare = isBare;
ElementType = elementType;
}
public bool HasSameWireType(LayerType other)
{
if (Kind != other.Kind || IsBare != other.IsBare ||
!string.Equals(Name, other.Name, StringComparison.Ordinal))
{
return false;
}
if (ElementType == null || other.ElementType == null)
{
return ElementType == null && other.ElementType == null;
}
return ElementType.HasSameWireType(other.ElementType);
}
}
public sealed class LayerField
{
public string Name { get; }
public LayerType Type { get; }
public string? FlagsField { get; }
public int? FlagBit { get; }
public bool IsConditional => FlagsField != null && FlagBit != null;
public LayerField(string name, LayerType type,
string? flagsField = null, int? flagBit = null)
{
Name = name;
Type = type;
FlagsField = flagsField;
FlagBit = flagBit;
}
}
public sealed class LayerConstructor
{
private readonly IReadOnlyList<LayerField> _fields;
public string Name { get; }
public int Id { get; }
public string ResultType { get; }
public IReadOnlyList<LayerField> Fields => _fields;
public LayerConstructor(string name, int id, string resultType,
IEnumerable<LayerField> fields)
{
Name = name;
Id = id;
ResultType = resultType;
_fields = Array.AsReadOnly(fields.ToArray());
}
public LayerField? FindField(string name)
{
for (int i = 0; i < _fields.Count; i++)
{
if (string.Equals(_fields[i].Name, name, StringComparison.Ordinal))
{
return _fields[i];
}
}
return null;
}
public bool HasSameShape(LayerConstructor other)
{
if (Id != other.Id ||
!string.Equals(Name, other.Name, StringComparison.Ordinal) ||
!string.Equals(ResultType, other.ResultType, StringComparison.Ordinal) ||
_fields.Count != other._fields.Count)
{
return false;
}
for (int i = 0; i < _fields.Count; i++)
{
LayerField left = _fields[i];
LayerField right = other._fields[i];
if (!string.Equals(left.Name, right.Name, StringComparison.Ordinal) ||
!left.Type.HasSameWireType(right.Type) ||
!string.Equals(left.FlagsField, right.FlagsField,
StringComparison.Ordinal) ||
left.FlagBit != right.FlagBit)
{
return false;
}
}
return true;
}
}
public sealed class LayerSchema
{
private readonly IReadOnlyList<LayerConstructor> _constructors;
private readonly IReadOnlyDictionary<int, LayerConstructor> _byId;
private readonly IReadOnlyDictionary<string, LayerConstructor> _byName;
private readonly IReadOnlyDictionary<string, IReadOnlyList<LayerConstructor>> _byResultType;
private readonly IReadOnlyDictionary<int, string> _vectorResults;
private readonly IReadOnlyList<LayerConstructor> _methods;
private readonly IReadOnlyDictionary<int, LayerConstructor> _methodsById;
private readonly IReadOnlyDictionary<string, LayerConstructor> _methodsByName;
public int Layer { get; }
public IReadOnlyList<LayerConstructor> Constructors => _constructors;
public IReadOnlyList<LayerConstructor> Methods => _methods;
public IReadOnlyDictionary<int, string> VectorResults => _vectorResults;
public LayerSchema(int layer, IEnumerable<LayerConstructor> constructors,
IEnumerable<KeyValuePair<int, string>>? vectorResults = null,
IEnumerable<LayerConstructor>? methods = null)
{
Layer = layer;
LayerConstructor[] values = constructors.ToArray();
var byId = new Dictionary<int, LayerConstructor>();
var byName = new Dictionary<string, LayerConstructor>(StringComparer.Ordinal);
var byResult = new Dictionary<string, List<LayerConstructor>>(StringComparer.Ordinal);
foreach (LayerConstructor constructor in values)
{
if (byId.ContainsKey(constructor.Id))
{
throw new ArgumentException("Duplicate constructor id.", nameof(constructors));
}
if (byName.ContainsKey(constructor.Name))
{
throw new ArgumentException("Duplicate constructor name.", nameof(constructors));
}
byId.Add(constructor.Id, constructor);
byName.Add(constructor.Name, constructor);
if (!byResult.TryGetValue(constructor.ResultType, out List<LayerConstructor>? result))
{
result = new List<LayerConstructor>();
byResult.Add(constructor.ResultType, result);
}
result.Add(constructor);
}
var readOnlyResult = new Dictionary<string, IReadOnlyList<LayerConstructor>>(
StringComparer.Ordinal);
foreach (KeyValuePair<string, List<LayerConstructor>> pair in byResult)
{
readOnlyResult.Add(pair.Key, Array.AsReadOnly(pair.Value.ToArray()));
}
_constructors = Array.AsReadOnly(values);
_byId = new ReadOnlyDictionary<int, LayerConstructor>(byId);
_byName = new ReadOnlyDictionary<string, LayerConstructor>(byName);
_byResultType = new ReadOnlyDictionary<string, IReadOnlyList<LayerConstructor>>(
readOnlyResult);
var vectors = new Dictionary<int, string>();
if (vectorResults != null)
{
foreach (KeyValuePair<int, string> entry in vectorResults)
{
vectors.Add(entry.Key, entry.Value);
}
}
_vectorResults = new ReadOnlyDictionary<int, string>(vectors);
LayerConstructor[] methodValues = methods == null
? Array.Empty<LayerConstructor>()
: methods.ToArray();
var methodsById = new Dictionary<int, LayerConstructor>();
var methodsByName = new Dictionary<string, LayerConstructor>(StringComparer.Ordinal);
foreach (LayerConstructor method in methodValues)
{
if (methodsById.ContainsKey(method.Id))
{
throw new ArgumentException("Duplicate method id.", nameof(methods));
}
if (methodsByName.ContainsKey(method.Name))
{
throw new ArgumentException("Duplicate method name.", nameof(methods));
}
methodsById.Add(method.Id, method);
methodsByName.Add(method.Name, method);
}
_methods = Array.AsReadOnly(methodValues);
_methodsById = new ReadOnlyDictionary<int, LayerConstructor>(methodsById);
_methodsByName = new ReadOnlyDictionary<string, LayerConstructor>(methodsByName);
}
public bool TryGetMethod(int id, out LayerConstructor method)
{
return _methodsById.TryGetValue(id, out method!);
}
public bool TryGetMethod(string name, out LayerConstructor method)
{
return _methodsByName.TryGetValue(name, out method!);
}
public LayerConstructor GetMethod(string name)
{
if (!_methodsByName.TryGetValue(name, out LayerConstructor? method))
{
throw new ArgumentException("Unknown method.", nameof(name));
}
return method;
}
public bool TryGetVectorResultElement(int methodId, out string elementType)
{
return _vectorResults.TryGetValue(methodId, out elementType!);
}
public bool TryGetConstructor(int id, out LayerConstructor constructor)
{
return _byId.TryGetValue(id, out constructor!);
}
public bool TryGetConstructor(string name, out LayerConstructor constructor)
{
return _byName.TryGetValue(name, out constructor!);
}
public LayerConstructor GetConstructor(string name)
{
if (!_byName.TryGetValue(name, out LayerConstructor? constructor))
{
throw new ArgumentException("Unknown constructor.", nameof(name));
}
return constructor;
}
public bool TryGetBareConstructor(string resultType,
out LayerConstructor constructor)
{
constructor = null!;
return _byResultType.TryGetValue(resultType, out IReadOnlyList<LayerConstructor>? values) &&
values.Count == 1 &&
(constructor = values[0]) != null;
}
}
public sealed class LayerObjectValue
{
private readonly IReadOnlyDictionary<string, object?> _fields;
public LayerConstructor Constructor { get; }
public IReadOnlyDictionary<string, object?> Fields => _fields;
public LayerObjectValue(LayerConstructor constructor,
IEnumerable<KeyValuePair<string, object?>> fields)
{
Constructor = constructor;
var values = new Dictionary<string, object?>(StringComparer.Ordinal);
foreach (KeyValuePair<string, object?> field in fields)
{
values.Add(field.Key, field.Value);
}
_fields = new ReadOnlyDictionary<string, object?>(values);
}
public LayerObjectValue(LayerConstructor constructor,
IReadOnlyDictionary<string, object?> fields)
: this(constructor, fields.Select(x => x))
{
}
public bool TryGetValue(string name, out object? value)
{
return _fields.TryGetValue(name, out value);
}
public T Get<T>(string name)
{
if (!TryGetValue(name, out object? value) || value is not T typed)
{
throw new InvalidOperationException("The field " + name + " is absent.");
}
return typed;
}
}