1using System.Runtime.CompilerServices;
10public static class Serializer
15 public static ISerializer<object?> Dynamic => DynamicSerializer.Singleton;
17 private static readonly Dictionary<Type, ISerializer> _reg =
new();
19 internal static readonly HashSet<string> Tags =
new()
21 "@int",
"@long",
"@double",
"@date",
"@time",
"@mod",
"@stream",
"@ref",
"@doc",
"@set",
"@object",
"@bytes"
24 private static readonly DynamicSerializer s_object = DynamicSerializer.Singleton;
25 private static readonly StringSerializer s_string =
new();
26 private static readonly ByteSerializer s_byte =
new();
27 private static readonly BytesSerializer s_bytes =
new();
28 private static readonly SByteSerializer s_sbyte =
new();
29 private static readonly ShortSerializer s_short =
new();
30 private static readonly UShortSerializer s_ushort =
new();
31 private static readonly IntSerializer s_int =
new();
32 private static readonly UIntSerializer s_uint =
new();
33 private static readonly LongSerializer s_long =
new();
34 private static readonly FloatSerializer s_float =
new();
35 private static readonly DoubleSerializer s_double =
new();
36 private static readonly DateOnlySerializer s_dateOnly =
new();
37 private static readonly DateTimeSerializer s_dateTime =
new();
38 private static readonly DateTimeOffsetSerializer s_dateTimeOffset =
new();
39 private static readonly BooleanSerializer s_bool =
new();
40 private static readonly ModuleSerializer s_module =
new();
41 private static readonly EventSourceSerializer s_eventSource =
new();
42 private static readonly QuerySerializer s_query =
new();
43 private static readonly QueryExprSerializer s_queryExpr =
new();
44 private static readonly QueryLiteralSerializer s_queryLiteral =
new();
45 private static readonly QueryArrSerializer s_queryArr =
new();
46 private static readonly QueryObjSerializer s_queryObj =
new();
47 private static readonly QueryValSerializer s_queryVal =
new();
56 public static ISerializer<T> Generate<T>(
MappingContext context) where T : notnull
58 var targetType = typeof(T);
59 var ser = (ISerializer<T>)Generate(context, targetType);
69 public static ISerializer Generate(
MappingContext context, Type targetType)
71 if (_reg.TryGetValue(targetType, out var s))
return s;
73 if (IsAnonymousType(targetType))
75 var info = context.
GetInfo(targetType);
76 return info.ClassSerializer;
79 if (targetType == typeof(
object))
return s_object;
80 if (targetType == typeof(
string))
return s_string;
81 if (targetType == typeof(
byte))
return s_byte;
82 if (targetType == typeof(
byte[]))
return s_bytes;
83 if (targetType == typeof(sbyte))
return s_sbyte;
84 if (targetType == typeof(
short))
return s_short;
85 if (targetType == typeof(ushort))
return s_ushort;
86 if (targetType == typeof(
int))
return s_int;
87 if (targetType == typeof(uint))
return s_uint;
88 if (targetType == typeof(
long))
return s_long;
89 if (targetType == typeof(
float))
return s_float;
90 if (targetType == typeof(
double))
return s_double;
91 if (targetType == typeof(DateOnly))
return s_dateOnly;
92 if (targetType == typeof(DateTime))
return s_dateTime;
93 if (targetType == typeof(DateTimeOffset))
return s_dateTimeOffset;
94 if (targetType == typeof(
bool))
return s_bool;
95 if (targetType == typeof(
Module))
return s_module;
96 if (targetType == typeof(
EventSource))
return s_eventSource;
97 if (targetType == typeof(
Query))
return s_query;
98 if (targetType == typeof(
QueryExpr))
return s_queryExpr;
99 if (targetType == typeof(
QueryLiteral))
return s_queryLiteral;
100 if (targetType == typeof(QueryArr))
return s_queryArr;
101 if (targetType == typeof(
QueryObj))
return s_queryObj;
102 if (targetType == typeof(
QueryVal))
return s_queryVal;
104 if (targetType.IsGenericType)
106 if (targetType.GetGenericTypeDefinition() == typeof(Nullable<>))
108 var args = targetType.GetGenericArguments();
109 if (args.Length == 1)
111 var inner = (ISerializer)Generate(context, args[0]);
112 var serType = typeof(NullableStructSerializer<>).MakeGenericType(
new[] { args[0] });
113 object? ser = Activator.CreateInstance(serType,
new[] { inner });
115 return (ISerializer)ser!;
118 throw new ArgumentException($
"Unsupported nullable type. Generic arguments > 1: {args}");
122 if (targetType.GetGenericTypeDefinition() == typeof(Dictionary<,>))
124 var argTypes = targetType.GetGenericArguments();
125 var keyType = argTypes[0];
126 var valueType = argTypes[1];
128 if (keyType != typeof(
string))
130 $
"Unsupported Dictionary key type. Key must be of type string, but was a {keyType}");
132 var valueSerializer = Generate(context, valueType);
134 var serType = typeof(DictionarySerializer<>).MakeGenericType(
new[] { valueType });
135 object? ser = Activator.CreateInstance(serType,
new[] { valueSerializer });
137 return (ISerializer)ser!;
140 if (targetType.GetGenericTypeDefinition() == typeof(List<>) || targetType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
142 var elemType = targetType.GetGenericArguments()[0];
143 var elemSerializer = Generate(context, elemType);
145 var serType = typeof(ListSerializer<>).MakeGenericType(
new[] { elemType });
146 object? ser = Activator.CreateInstance(serType,
new[] { elemSerializer });
148 return (ISerializer)ser!;
151 if (targetType.GetGenericTypeDefinition() == typeof(Page<>))
153 var elemType = targetType.GetGenericArguments()[0];
154 var elemSerializer = Generate(context, elemType);
156 var serType = typeof(PageSerializer<>).MakeGenericType(
new[] { elemType });
157 object? ser = Activator.CreateInstance(serType,
new[] { elemSerializer });
159 return (ISerializer)ser!;
162 if (targetType.GetGenericTypeDefinition() == typeof(
BaseRef<>))
164 var docType = targetType.GetGenericArguments()[0];
165 var docSerializer = Generate(context, docType);
167 var serType = typeof(BaseRefSerializer<>).MakeGenericType(
new[] { docType });
168 object? ser = Activator.CreateInstance(serType,
new[] { docSerializer });
170 return (ISerializer)ser!;
173 if (targetType.GetGenericTypeDefinition() == typeof(
Ref<>))
175 var docType = targetType.GetGenericArguments()[0];
176 var docSerializer = Generate(context, docType);
178 var serType = typeof(RefSerializer<>).MakeGenericType(
new[] { docType });
179 object? ser = Activator.CreateInstance(serType,
new[] { docSerializer });
181 return (ISerializer)ser!;
184 if (targetType.GetGenericTypeDefinition() == typeof(
NamedRef<>))
186 var docType = targetType.GetGenericArguments()[0];
187 var docSerializer = Generate(context, docType);
189 var serType = typeof(NamedRefSerializer<>).MakeGenericType(
new[] { docType });
190 object? ser = Activator.CreateInstance(serType,
new[] { docSerializer });
192 return (ISerializer)ser!;
195 if (targetType.IsGenericType && targetType.Name.Contains(
"AnonymousType"))
197 return DynamicSerializer.Singleton;
202 if (targetType.IsClass)
204 var info = context.
GetInfo(targetType);
205 return info.ClassSerializer;
208 throw new ArgumentException($
"Unsupported deserialization target type {targetType}");
217 public static ISerializer<T?> GenerateNullable<T>(
MappingContext context)
219 var targetType = typeof(T);
220 var ser = (ISerializer<T>)Generate(context, targetType);
221 return new NullableSerializer<T>(ser);
230 public static ISerializer GenerateNullable(
MappingContext context, Type targetType)
232 var inner = (ISerializer)Generate(context, targetType);
233 var serType = typeof(NullableSerializer<>).MakeGenericType(
new[] { targetType });
234 var ser = Activator.CreateInstance(serType,
new[] { inner });
236 return (ISerializer)ser!;
245 public static void Register(Type t, ISerializer s)
247 if (!_reg.TryAdd(t, s))
throw new ArgumentException($
"Serializer for type `{t}` already registered");
255 public static void Register<T>(ISerializer<T> s)
258 foreach (var i
in s.GetType().GetInterfaces())
260 if (!i.IsGenericType || i.GetGenericTypeDefinition() != typeof(ISerializer<>))
continue;
262 var t = i.GetGenericArguments()[0];
263 success = _reg.TryAdd(t, s);
264 if (!success)
throw new ArgumentException($
"Serializer for type `{t}` already registered");
268 if (!success)
throw new ArgumentException($
"Could not infer associated type for `{s.GetType()}`. Use Register(type, serializer).");
275 public static void Deregister(Type t)
277 if (_reg.ContainsKey(t)) _reg.Remove(t);
280 private static bool IsAnonymousType(
this Type type)
282 bool hasCompilerGeneratedAttribute = type.GetCustomAttributes(typeof(CompilerGeneratedAttribute),
false).Any();
283 bool nameContainsAnonymousType = type?.FullName?.Contains(
"AnonymousType") ??
false;
284 return hasCompilerGeneratedAttribute && nameContainsAnonymousType;
System.ArgumentException ArgumentException
A class representing the mapping context to be used during serialization and deserialization.
MappingInfo GetInfo(Type ty, string? colName=null)
Gets the MappingInfo for a given Type.
Represents an FQL query expression. This class encapsulates a list of IQueryFragment instances,...
Represents the abstract base class for constructing FQL queries.
Represents a literal part of an FQL query. This class is used for embedding raw string values directl...
Represents a dictionary of FQL queries.
Represents a generic value holder for FQL queries. This class allows embedding values of various type...
An abstract class representing a reference that can wrap an instance of the referenced document.
Represents a Fauna EventSource for initializing Streams and Feeds.
Represents a module, a singleton object grouping related functionalities. Modules are serialized as @...
Represents a document ref that has a "name" instead of an "id". For example, a Role document referenc...
Represents a document ref.