1using System.Diagnostics;
8internal interface IClassDocumentSerializer : ISerializer
10 public object DeserializeDocument(
MappingContext context,
string?
id,
string? name, ref Utf8FaunaReader reader);
13internal class ClassSerializer<T> : BaseSerializer<T>, IClassDocumentSerializer
15 private const string IdField =
"id";
16 private const string NameField =
"name";
18 private readonly
bool _isDocument;
22 Debug.Assert(info.
Type == typeof(T));
26 public ClassSerializer(
MappingInfo info,
bool isDocument)
28 Debug.Assert(info.
Type == typeof(T));
30 _isDocument = isDocument;
33 public object DeserializeDocument(
MappingContext context,
string?
id,
string? name, ref Utf8FaunaReader reader)
35 object instance = CreateInstance();
36 if (
id is not
null) TrySetId(instance,
id);
37 if (name is not
null) TrySetName(instance, name);
38 SetFields(instance, context, ref reader,
TokenType.EndDocument);
42 public override T Deserialize(
MappingContext context, ref Utf8FaunaReader reader)
44 var endToken = reader.CurrentTokenType
switch
46 TokenType.StartDocument =>
TokenType.EndDocument,
47 TokenType.StartObject =>
TokenType.EndObject,
49 var other =>
throw UnexpectedToken(other),
60 while (reader.Read() && reader.CurrentTokenType !=
TokenType.EndRef)
62 if (reader.CurrentTokenType !=
TokenType.FieldName)
63 throw new SerializationException(
64 $
"Unexpected token while deserializing into DocumentRef: {reader.CurrentTokenType}");
66 string fieldName = reader.GetString()!;
71 id = reader.GetString();
74 name = reader.GetString();
77 coll = reader.GetModule();
80 cause = reader.GetString();
83 exists = reader.GetBoolean();
88 if ((
id !=
null || name !=
null) && coll !=
null && exists)
90 throw new SerializationException(
"Cannot deserialize refs into classes.");
93 throw new NullDocumentException((
id ?? name)!, coll!, cause!);
96 object instance = CreateInstance();
97 SetFields(instance, context, ref reader, endToken);
101 public override void Serialize(
MappingContext ctx, Utf8FaunaWriter w,
object? o)
103 var skipFields =
new HashSet<string>();
109 if (fi.
Name.ToLowerInvariant() ==
"id" && fi.
Property.GetValue(o) is
null) skipFields.Add(
"id");
110 if (fi.
Name.ToLowerInvariant() ==
"coll" && fi.
Property.GetValue(o) is
null) skipFields.Add(
"coll");
111 if (fi.
Name.ToLowerInvariant() ==
"ts" && fi.
Property.GetValue(o) is
null) skipFields.Add(
"ts");
115 SerializeInternal(ctx, w, o, skipFields);
118 private static void SerializeInternal(
MappingContext ctx, Utf8FaunaWriter w,
object? o, IReadOnlySet<string> skipFields)
128 bool shouldEscape = info.ShouldEscapeObject;
130 if (shouldEscape) w.WriteStartEscapedObject();
else w.WriteStartObject();
131 foreach (var field
in info.Fields)
133 if (skipFields.Contains(field.Name.ToLowerInvariant()))
continue;
135 w.WriteFieldName(field.Name);
136 object? v = field.Property.GetValue(o);
137 field.Serializer.Serialize(ctx, w, v);
139 if (shouldEscape) w.WriteEndEscapedObject();
else w.WriteEndObject();
142 private object CreateInstance() => Activator.CreateInstance(_info.Type)!;
144 private void SetFields(
object instance,
MappingContext context, ref Utf8FaunaReader reader,
TokenType endToken)
146 while (reader.Read() && reader.CurrentTokenType != endToken)
148 if (reader.CurrentTokenType !=
TokenType.FieldName)
149 throw UnexpectedToken(reader.CurrentTokenType);
151 string fieldName = reader.GetString()!;
154 if (fieldName == IdField && reader.CurrentTokenType ==
TokenType.String)
156 TrySetId(instance, reader.GetString()!);
158 else if (fieldName == NameField && reader.CurrentTokenType ==
TokenType.String)
160 TrySetName(instance, reader.GetString()!);
162 else if (_info.FieldsByName.TryGetValue(fieldName, out var field))
164 field.Property.SetValue(instance, field.Serializer.Deserialize(context, ref reader));
173 private void TrySetId(
object instance,
string id)
175 if (!_info.FieldsByName.TryGetValue(IdField, out var field))
180 if (field.Type == typeof(
long))
182 field.Property.SetValue(instance,
long.Parse(
id));
184 else if (field.Type == typeof(
string))
186 field.Property.SetValue(instance,
id);
194 private void TrySetName(
object instance,
string name)
196 if (_info.FieldsByName.TryGetValue(NameField, out var field))
198 if (field.Type == typeof(
string))
200 field.Property.SetValue(instance, name);
209 private new SerializationException UnexpectedToken(
TokenType tokenType) =>
210 new($
"Unexpected token while deserializing into class {_info.Type.Name}: {tokenType}");
A class that encapsulates the field mapping, serialization, and deserialization of a particular field...
PropertyInfo Property
The property info of an associated class.
string Name
The name of the field.
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.
A class that encapsulates the class mapping, serialization, and deserialization of a Fauna object,...
Type Type
The associated type.
Represents a module, a singleton object grouping related functionalities. Modules are serialized as @...
TokenType
Enumerates the types of tokens used in Fauna serialization.