Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add generic ISerialize #144

Merged
merged 1 commit into from
Oct 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/serde-xml/XmlSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ public void SerializeDouble(double d)
{
}

void ISerializer.SerializeEnumValue<T, U>(string enumName, string? valueName, T value, U serialize)
{}

public void SerializeFloat(float f) => SerializeDouble(f);

public void SerializeI16(short i16) => SerializeI64(i16);
Expand All @@ -94,6 +97,9 @@ public void SerializeI64(long i64)
public void SerializeNotNull<T>(T t) where T : notnull, ISerialize
=> t.Serialize(this);

void ISerializer.SerializeNotNull<T, U>(T t, U u)
=> u.Serialize(t, this);

public void SerializeNull()
{
// Default behavior is to skip serialization of null values
Expand Down Expand Up @@ -182,6 +188,8 @@ void ISerializeEnumerable.SerializeElement<T>(T value)
{
value.Serialize(_serializer);
}
void ISerializeEnumerable.SerializeElement<T, U>(T value, U serialize)
=> serialize.Serialize(value, _serializer);

void ISerializeEnumerable.End()
{
Expand Down Expand Up @@ -262,6 +270,13 @@ public void SerializeField<T>(ReadOnlySpan<byte> name, T value, ReadOnlySpan<Att
SerializeField(Encoding.UTF8.GetString(name), value, attributes);
}

void ISerializeType.SerializeField<T, U>(string name, T value, U serialize)
{
_parent._writer.WriteStartElement(name);
serialize.Serialize(value, _parent);
_parent._writer.WriteEndElement();
}

public void End()
{
if (_writeEnd)
Expand Down
26 changes: 21 additions & 5 deletions src/serde/ISerialize.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,26 @@ public interface ISerialize
void Serialize(ISerializer serializer);
}

public interface ISerialize<T>
{
void Serialize(T value, ISerializer serializer);
}

public interface ISerializeType
{
void SerializeField<T>(string name, T value) where T : ISerialize
{
SerializeField(Encoding.UTF8.GetBytes(name), value);
}
void SerializeField<T>(ReadOnlySpan<byte> name, T value) where T : ISerialize;
void SerializeField<T>(Utf8Span name, T value) where T : ISerialize;
void SerializeField<T>(string name, T value, ReadOnlySpan<Attribute> attributes) where T : ISerialize
=> SerializeField(name, value);
void SerializeField<T>(ReadOnlySpan<byte> name, T value, ReadOnlySpan<Attribute> attributes) where T : ISerialize
void SerializeField<T>(Utf8Span name, T value, ReadOnlySpan<Attribute> attributes) where T : ISerialize
=> SerializeField(name, value);
void SkipField(string name) { SkipField(Encoding.UTF8.GetBytes(name)); }
void SkipField(ReadOnlySpan<byte> name) { }
void SkipField(Utf8Span name) { }

void SerializeField<T, U>(string name, T value, U serialize) where U : ISerialize<T>;
void End();
}

Expand All @@ -35,7 +42,7 @@ public static class ISerializeTypeExt

public static void SerializeFieldIfNotNull<T, U>(
this ISerializeType serializeType,
ReadOnlySpan<byte> name,
Utf8Span name,
T value,
U rawValue) where T : ISerialize
=> SerializeFieldIfNotNull(serializeType, name, value, rawValue, ReadOnlySpan<Attribute>.Empty);
Expand All @@ -59,7 +66,7 @@ public static class ISerializeTypeExt

public static void SerializeFieldIfNotNull<T, U>(
this ISerializeType serializeType,
ReadOnlySpan<byte> name,
Utf8Span name,
T value,
U rawValue,
ReadOnlySpan<Attribute> attributes) where T : ISerialize
Expand All @@ -78,13 +85,16 @@ public static class ISerializeTypeExt
public interface ISerializeEnumerable
{
void SerializeElement<T>(T value) where T : ISerialize;
void SerializeElement<T, U>(T value, U serialize) where U : ISerialize<T>;
void End();
}

public interface ISerializeDictionary
{
void SerializeKey<T>(T key) where T : ISerialize;
void SerializeKey<T, U>(T key, U serialize) where U : ISerialize<T>;
void SerializeValue<T>(T value) where T : ISerialize;
void SerializeValue<T, U>(T value, U serialize) where U : ISerialize<T>;
void End();
}

Expand All @@ -106,7 +116,13 @@ public interface ISerializer
void SerializeString(string s);
void SerializeNull();
void SerializeNotNull<T>(T t) where T : notnull, ISerialize;
void SerializeNotNull<T, U>(T t, U u)
where T : notnull
where U : ISerialize<T>;
void SerializeEnumValue<T>(string enumName, string? valueName, T value) where T : notnull, ISerialize;
void SerializeEnumValue<T, U>(string enumName, string? valueName, T value, U serialize)
where T : struct, Enum
where U : ISerialize<T>;

ISerializeType SerializeType(string name, int numFields);
ISerializeEnumerable SerializeEnumerable(string typeName, int? length);
Expand Down
2 changes: 2 additions & 0 deletions src/serde/Utf8Span.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

global using Utf8Span = System.ReadOnlySpan<byte>;
56 changes: 44 additions & 12 deletions src/serde/json/JsonSerializerImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ partial class JsonSerializer : ISerializer
t.Serialize(this);
}

public void SerializeNotNull<T, U>(T t, U u)
where T : notnull
where U : ISerialize<T>
{
u.Serialize(t, this);
}

public void SerializeEnumValue<T>(string enumName, string? valueName, T value) where T : notnull, ISerialize
{
if (valueName is null)
Expand All @@ -63,6 +70,17 @@ partial class JsonSerializer : ISerializer
_writer.WriteStringValue(valueName);
}

public void SerializeEnumValue<T, U>(string enumName, string? valueName, T value, U serialize)
where T : struct, Enum
where U : ISerialize<T>
{
if (valueName is null)
{
throw new InvalidOperationException($"Cannot serialize unnamed enum value '{value}' of enum '{enumName}'");
}
_writer.WriteStringValue(valueName);
}

public ISerializeType SerializeType(string name, int numFields)
{
_writer.WriteStartObject();
Expand All @@ -83,6 +101,8 @@ void ISerializeEnumerable.SerializeElement<T>(T value)
{
value.Serialize(_s);
}
void ISerializeEnumerable.SerializeElement<T, U>(T value, U serialize)
=> serialize.Serialize(value, _s);

void ISerializeEnumerable.End()
{
Expand All @@ -99,12 +119,18 @@ public ISerializeDictionary SerializeDictionary(int? count)

partial class JsonSerializer : ISerializeType
{
void ISerializeType.SerializeField<T>(ReadOnlySpan<byte> name, T value)
void ISerializeType.SerializeField<T>(Utf8Span name, T value)
{
_writer.WritePropertyName(name);
value.Serialize(this);
}

void ISerializeType.SerializeField<T, U>(string name, T value, U serialize)
{
_writer.WritePropertyName(name);
serialize.Serialize(value, this);
}

void ISerializeType.End()
{
_writer.WriteEndObject();
Expand All @@ -117,22 +143,29 @@ void ISerializeDictionary.SerializeValue<T>(T value)
{
value.Serialize(this);
}

void ISerializeDictionary.SerializeValue<T, U>(T value, U serialize)
=> serialize.Serialize(value, this);

void ISerializeDictionary.End()
{
_writer.WriteEndObject();
}

void ISerializeDictionary.SerializeKey<T>(T key)
{
// Grab a string value. Box to prevent internal copying and losing side-effects
ISerializer keySerializer = new KeySerializer();
key.Serialize(keySerializer);
_writer.WritePropertyName(((KeySerializer)keySerializer).StringResult!);
key.Serialize(new KeySerializer(this));
}

void ISerializeDictionary.SerializeKey<T, U>(T key, U serialize)
{
serialize.Serialize(key, new KeySerializer(this));
}

private class KeySerializer : ISerializer
private readonly struct KeySerializer : ISerializer
{
public string? StringResult = null;
private readonly JsonSerializer _parent;
public KeySerializer(JsonSerializer parent) => this._parent = parent;

public void SerializeBool(bool b) => throw new KeyNotStringException();
public void SerializeChar(char c) => throw new KeyNotStringException();
Expand All @@ -159,21 +192,20 @@ private class KeySerializer : ISerializer

public void SerializeString(string s)
{
StringResult = s;
_parent._writer.WritePropertyName(s);
}

public void SerializeEnumValue<T>(string enumName, string? valueName, T value) where T : notnull, ISerialize
=> throw new KeyNotStringException();
void ISerializer.SerializeEnumValue<T, U>(string enumName, string? valueName, T value, U serialize)
=> throw new KeyNotStringException();

public ISerializeDictionary SerializeDictionary(int? length) => throw new KeyNotStringException();

public ISerializeEnumerable SerializeEnumerable(string typeName, int? length) => throw new KeyNotStringException();

public ISerializeType SerializeType(string name, int numFields) => throw new KeyNotStringException();

public void SerializeNull() => throw new KeyNotStringException();

public void SerializeNotNull<T>(T t) where T : notnull, ISerialize => throw new KeyNotStringException();
void ISerializer.SerializeNotNull<T, U>(T t, U u) => throw new KeyNotStringException();
}
}
}