diff --git a/src/serde-xml/XmlSerializer.cs b/src/serde-xml/XmlSerializer.cs index f1c99296..b3960af9 100644 --- a/src/serde-xml/XmlSerializer.cs +++ b/src/serde-xml/XmlSerializer.cs @@ -72,6 +72,9 @@ public void SerializeDouble(double d) { } + void ISerializer.SerializeEnumValue(string enumName, string? valueName, T value, U serialize) + {} + public void SerializeFloat(float f) => SerializeDouble(f); public void SerializeI16(short i16) => SerializeI64(i16); @@ -94,6 +97,9 @@ public void SerializeI64(long i64) public void SerializeNotNull(T t) where T : notnull, ISerialize => t.Serialize(this); + void ISerializer.SerializeNotNull(T t, U u) + => u.Serialize(t, this); + public void SerializeNull() { // Default behavior is to skip serialization of null values @@ -182,6 +188,8 @@ void ISerializeEnumerable.SerializeElement(T value) { value.Serialize(_serializer); } + void ISerializeEnumerable.SerializeElement(T value, U serialize) + => serialize.Serialize(value, _serializer); void ISerializeEnumerable.End() { @@ -262,6 +270,13 @@ public void SerializeField(ReadOnlySpan name, T value, ReadOnlySpan(string name, T value, U serialize) + { + _parent._writer.WriteStartElement(name); + serialize.Serialize(value, _parent); + _parent._writer.WriteEndElement(); + } + public void End() { if (_writeEnd) diff --git a/src/serde/ISerialize.cs b/src/serde/ISerialize.cs index 9650696c..1592270a 100644 --- a/src/serde/ISerialize.cs +++ b/src/serde/ISerialize.cs @@ -8,19 +8,26 @@ public interface ISerialize void Serialize(ISerializer serializer); } +public interface ISerialize +{ + void Serialize(T value, ISerializer serializer); +} + public interface ISerializeType { void SerializeField(string name, T value) where T : ISerialize { SerializeField(Encoding.UTF8.GetBytes(name), value); } - void SerializeField(ReadOnlySpan name, T value) where T : ISerialize; + void SerializeField(Utf8Span name, T value) where T : ISerialize; void SerializeField(string name, T value, ReadOnlySpan attributes) where T : ISerialize => SerializeField(name, value); - void SerializeField(ReadOnlySpan name, T value, ReadOnlySpan attributes) where T : ISerialize + void SerializeField(Utf8Span name, T value, ReadOnlySpan attributes) where T : ISerialize => SerializeField(name, value); void SkipField(string name) { SkipField(Encoding.UTF8.GetBytes(name)); } - void SkipField(ReadOnlySpan name) { } + void SkipField(Utf8Span name) { } + + void SerializeField(string name, T value, U serialize) where U : ISerialize; void End(); } @@ -35,7 +42,7 @@ public static class ISerializeTypeExt public static void SerializeFieldIfNotNull( this ISerializeType serializeType, - ReadOnlySpan name, + Utf8Span name, T value, U rawValue) where T : ISerialize => SerializeFieldIfNotNull(serializeType, name, value, rawValue, ReadOnlySpan.Empty); @@ -59,7 +66,7 @@ public static class ISerializeTypeExt public static void SerializeFieldIfNotNull( this ISerializeType serializeType, - ReadOnlySpan name, + Utf8Span name, T value, U rawValue, ReadOnlySpan attributes) where T : ISerialize @@ -78,13 +85,16 @@ public static class ISerializeTypeExt public interface ISerializeEnumerable { void SerializeElement(T value) where T : ISerialize; + void SerializeElement(T value, U serialize) where U : ISerialize; void End(); } public interface ISerializeDictionary { void SerializeKey(T key) where T : ISerialize; + void SerializeKey(T key, U serialize) where U : ISerialize; void SerializeValue(T value) where T : ISerialize; + void SerializeValue(T value, U serialize) where U : ISerialize; void End(); } @@ -106,7 +116,13 @@ public interface ISerializer void SerializeString(string s); void SerializeNull(); void SerializeNotNull(T t) where T : notnull, ISerialize; + void SerializeNotNull(T t, U u) + where T : notnull + where U : ISerialize; void SerializeEnumValue(string enumName, string? valueName, T value) where T : notnull, ISerialize; + void SerializeEnumValue(string enumName, string? valueName, T value, U serialize) + where T : struct, Enum + where U : ISerialize; ISerializeType SerializeType(string name, int numFields); ISerializeEnumerable SerializeEnumerable(string typeName, int? length); diff --git a/src/serde/Utf8Span.cs b/src/serde/Utf8Span.cs new file mode 100644 index 00000000..42642e73 --- /dev/null +++ b/src/serde/Utf8Span.cs @@ -0,0 +1,2 @@ + +global using Utf8Span = System.ReadOnlySpan; \ No newline at end of file diff --git a/src/serde/json/JsonSerializerImpl.cs b/src/serde/json/JsonSerializerImpl.cs index db93e142..856dcdfd 100644 --- a/src/serde/json/JsonSerializerImpl.cs +++ b/src/serde/json/JsonSerializerImpl.cs @@ -54,6 +54,13 @@ partial class JsonSerializer : ISerializer t.Serialize(this); } + public void SerializeNotNull(T t, U u) + where T : notnull + where U : ISerialize + { + u.Serialize(t, this); + } + public void SerializeEnumValue(string enumName, string? valueName, T value) where T : notnull, ISerialize { if (valueName is null) @@ -63,6 +70,17 @@ partial class JsonSerializer : ISerializer _writer.WriteStringValue(valueName); } + public void SerializeEnumValue(string enumName, string? valueName, T value, U serialize) + where T : struct, Enum + where U : ISerialize + { + 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(); @@ -83,6 +101,8 @@ void ISerializeEnumerable.SerializeElement(T value) { value.Serialize(_s); } + void ISerializeEnumerable.SerializeElement(T value, U serialize) + => serialize.Serialize(value, _s); void ISerializeEnumerable.End() { @@ -99,12 +119,18 @@ public ISerializeDictionary SerializeDictionary(int? count) partial class JsonSerializer : ISerializeType { - void ISerializeType.SerializeField(ReadOnlySpan name, T value) + void ISerializeType.SerializeField(Utf8Span name, T value) { _writer.WritePropertyName(name); value.Serialize(this); } + void ISerializeType.SerializeField(string name, T value, U serialize) + { + _writer.WritePropertyName(name); + serialize.Serialize(value, this); + } + void ISerializeType.End() { _writer.WriteEndObject(); @@ -117,6 +143,10 @@ void ISerializeDictionary.SerializeValue(T value) { value.Serialize(this); } + + void ISerializeDictionary.SerializeValue(T value, U serialize) + => serialize.Serialize(value, this); + void ISerializeDictionary.End() { _writer.WriteEndObject(); @@ -124,15 +154,18 @@ void ISerializeDictionary.End() void ISerializeDictionary.SerializeKey(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 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(); @@ -159,21 +192,20 @@ private class KeySerializer : ISerializer public void SerializeString(string s) { - StringResult = s; + _parent._writer.WritePropertyName(s); } public void SerializeEnumValue(string enumName, string? valueName, T value) where T : notnull, ISerialize => throw new KeyNotStringException(); + void ISerializer.SerializeEnumValue(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) where T : notnull, ISerialize => throw new KeyNotStringException(); + void ISerializer.SerializeNotNull(T t, U u) => throw new KeyNotStringException(); } } } \ No newline at end of file