Skip to content

Commit

Permalink
UnsafeWriter: migrate whole RD to explicit type APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
controlflow committed Feb 19, 2024
1 parent 02e35d3 commit e6c1dcb
Show file tree
Hide file tree
Showing 37 changed files with 436 additions and 408 deletions.
49 changes: 24 additions & 25 deletions rd-net/Lifetimes/Serialization/UnsafeWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ namespace JetBrains.Serialization
/// It is <see cref="IDisposable"/> so must be used only with (possibly nested) <c>using</c> in stack-like way.
/// <see cref="Cookie"/> contains start position and length of currently serialized data (start + len = position), so when disposed it reverts writer
/// position to the cookie's start position.
///
///
/// <seealso cref="UnsafeReader"/>
/// </summary>
[PublicAPI]
Expand Down Expand Up @@ -116,7 +114,7 @@ public byte* Data

/// <summary>
/// Writes `<see cref="Count"/><c> - sizeof(int)</c>` into the <see cref="Data"/> pointer.
/// Cookie must be prepared by invoking `<see cref="UnsafeWriter.Write(int)"/><c>(0)</c>` as first cookie call.
/// Cookie must be prepared by invoking `<see cref="UnsafeWriter.WriteInt32(int)"/><c>(0)</c>` as first cookie call.
/// </summary>
public void WriteIntLength()
{
Expand Down Expand Up @@ -645,36 +643,38 @@ public void WriteDateTime(DateTime value)
{
if (Mode.IsAssertion) Assertion.Assert(value.Kind != DateTimeKind.Local, "Use UTC time");

Write(value.Ticks);
WriteInt64(value.Ticks);
}

[MethodImpl(MethodImplAdvancedOptions.AggressiveInlining)]
public void WriteTimeSpan(TimeSpan value)
{
Write(value.Ticks);
WriteInt64(value.Ticks);
}

[MethodImpl(MethodImplAdvancedOptions.AggressiveInlining)]
public void WriteUri(Uri value)
{
Write(Uri.EscapeUriString(value.OriginalString));
WriteString(Uri.EscapeUriString(value.OriginalString));
}

[MethodImpl(MethodImplAdvancedOptions.AggressiveInlining)]
public void WriteString(string? value)
{
if (value == null) Write(-1);
if (value == null)
{
WriteInt32(-1);
}
else
{
Write(value.Length);
WriteInt32(value.Length);
WriteStringContentInternal(this, value, 0, value.Length);
}
}

/// <summary>
/// Doesn't write length prefix, only string contents. If value == null, does nothing.
/// Doesn't write length prefix, only string contents. If <paramref name="value"/> is <c>value</c>, does nothing.
/// </summary>
/// <param name="value"></param>
[MethodImpl(MethodImplAdvancedOptions.AggressiveInlining)]
public void WriteStringContent(string? value)
{
Expand All @@ -683,11 +683,8 @@ public void WriteStringContent(string? value)
}

/// <summary>
/// Doesn't write length prefix, only string contents. If value == null, does nothing.
/// Doesn't write length prefix, only string contents. If <paramref name="value"/> is <c>value</c>, does nothing.
/// </summary>
/// <param name="value"></param>
/// <param name="offset"></param>
/// <param name="count"></param>
[MethodImpl(MethodImplAdvancedOptions.AggressiveInlining)]
public void WriteStringContent(string? value, int offset, int count)
{
Expand Down Expand Up @@ -792,11 +789,11 @@ public void WriteArray(int[]? value)
{
if (value == null)
{
Write(-1);
WriteInt32(-1);
}
else
{
Write(value.Length);
WriteInt32(value.Length);
fixed (int* c = value)
{
Write((byte*)c, value.Length * sizeof(int));
Expand All @@ -808,12 +805,12 @@ public void WriteByteArray(byte[]? value)
{
if (value == null)
{
Write(-1);
WriteInt32(-1);
}
else
{
var size = value.Length;
Write(size);
WriteInt32(size);
Prepare(size);
Marshal.Copy(value, 0, (IntPtr)myPtr, size); // Unlike MemoryUtil::CopyMemory, this is a CLR intrinsic call
myPtr += size;
Expand Down Expand Up @@ -884,28 +881,30 @@ public void WriteCollection<T, TCollection>(WriteDelegate<T> writeDelegate, TCol
{
if (value == null)
{
Write(-1);
WriteInt32(-1);
}
else
{
Write(value.Count);
WriteInt32(value.Count);
foreach (var x in value)
{
writeDelegate(this, x);
}
}
}

public void Write<TK, TV, TDictionary>(WriteDelegate<TK> writeKeyDelegate, WriteDelegate<TV> writeValueDelegate, TDictionary? value)
public void Write<TK, TV, TDictionary>(
WriteDelegate<TK> writeKeyDelegate, WriteDelegate<TV> writeValueDelegate, TDictionary? value)
where TDictionary : IDictionary<TK, TV>
{
if (value == null)
{
Write(-1);
WriteInt32(-1);
}
else
{
Write(value.Count);
WriteInt32(value.Count);

foreach (var kv in value)
{
writeKeyDelegate(this, kv.Key);
Expand All @@ -920,15 +919,15 @@ public void Write<TK, TV, TDictionary>(WriteDelegate<TK> writeKeyDelegate, Write
public bool WriteNullness<T>([NotNullWhen(true)] T? value) where T : struct
{
var res = value != null;
Write(res);
WriteBoolean(res);
return res;
}

[ContractAnnotation("null=>false")]
public bool WriteNullness<T>([NotNullWhen(true)] T? value) where T : class
{
var res = value != null;
Write(res);
WriteBoolean(res);
return res;
}
}
Expand Down
71 changes: 46 additions & 25 deletions rd-net/RdFramework.Reflection/CollectionSerializers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,83 +12,104 @@ internal class CollectionSerializers
{
public static SerializerPair CreateListSerializerPair<T>(SerializerPair itemSerializer)
{
CtxReadDelegate<List<T>?> readListSerializer = (ctx, reader) => reader.ReadList(itemSerializer.GetReader<T>(), ctx);
CtxWriteDelegate<IEnumerable<T>> writeListSerializer =(ctx, writer, value) => writer.WriteEnumerable(itemSerializer.GetWriter<T>(), ctx, value);
CtxReadDelegate<List<T>?> readListSerializer =
(ctx, reader) => reader.ReadList(itemSerializer.GetReader<T>(), ctx);

CtxWriteDelegate<IEnumerable<T>> writeListSerializer =
(ctx, writer, value) => writer.WriteEnumerable(itemSerializer.GetWriter<T>(), ctx, value);

return new SerializerPair(readListSerializer, writeListSerializer);
}

public static SerializerPair CreateDictionarySerializerPair<TKey, TValue>(SerializerPair keySerializer, SerializerPair valueSerializer)
public static SerializerPair CreateDictionarySerializerPair<TKey, TValue>(
SerializerPair keySerializer, SerializerPair valueSerializer)
{
var read = CreateReadDictionary<TKey, TValue>(keySerializer, valueSerializer);

CtxWriteDelegate<IDictionary<TKey, TValue>?> write = (ctx, writer, value) =>
{
if (value is Dictionary<TKey, TValue> val && !Equals(val.Comparer, EqualityComparer<TKey>.Default))
throw new Exception($"Unable to serialize {value.GetType().ToString(true)}. Custom equality comparers are not supported");
if (value == null)
{
writer.Write(-1);
writer.WriteInt32(-1);
return;
}
writer.Write(value.Count);
var keyw = keySerializer.GetWriter<TKey>();
var valuew = valueSerializer.GetWriter<TValue>();
writer.WriteInt32(value.Count);
var keyWriter = keySerializer.GetWriter<TKey>();
var valueWriter = valueSerializer.GetWriter<TValue>();
foreach (var kvp in value)
{
keyw(ctx, writer, kvp.Key);
valuew(ctx, writer, kvp.Value);
keyWriter(ctx, writer, kvp.Key);
valueWriter(ctx, writer, kvp.Value);
}
};

return new SerializerPair(read, write);
}

public static SerializerPair CreateReadOnlyDictionarySerializerPair<TKey, TValue>(SerializerPair keySerializer, SerializerPair valueSerializer)
public static SerializerPair CreateReadOnlyDictionarySerializerPair<TKey, TValue>(
SerializerPair keySerializer, SerializerPair valueSerializer)
{
#if NET35
throw new NotSupportedException();
#else
var read = CreateReadDictionary<TKey, TValue>(keySerializer, valueSerializer);
CtxWriteDelegate<IReadOnlyDictionary<TKey, TValue>?> write = (ctx, writer, value) =>

CtxWriteDelegate<IReadOnlyDictionary<TKey, TValue>?> write = (context, writer, value) =>
{
if (value is Dictionary<TKey, TValue> val && !Equals(val.Comparer, EqualityComparer<TKey>.Default))
throw new Exception($"Unable to serialize {value.GetType().ToString(true)}. Custom equality comparers are not supported");
if (value == null)
{
writer.Write(-1);
writer.WriteInt32(-1);
return;
}
writer.Write(value.Count);
var keyw = keySerializer.GetWriter<TKey>();
var valuew = valueSerializer.GetWriter<TValue>();
writer.WriteInt32(value.Count);
var keyWriter = keySerializer.GetWriter<TKey>();
var valueWriter = valueSerializer.GetWriter<TValue>();
foreach (var kvp in value)
{
keyw(ctx, writer, kvp.Key);
valuew(ctx, writer, kvp.Value);
keyWriter(context, writer, kvp.Key);
valueWriter(context, writer, kvp.Value);
}
};

return new SerializerPair(read, write);
#endif
}


private static CtxReadDelegate<Dictionary<TKey, TValue>?> CreateReadDictionary<TKey, TValue>(SerializerPair keySerializer, SerializerPair valueSerializer)
private static CtxReadDelegate<Dictionary<TKey, TValue>?> CreateReadDictionary<TKey, TValue>(
SerializerPair keySerializer, SerializerPair valueSerializer)
{
CtxReadDelegate<Dictionary<TKey, TValue>?> read = (ctx, reader) =>
CtxReadDelegate<Dictionary<TKey, TValue>?> read = (context, reader) =>
{
int count = reader.ReadInt();
if (count == -1)
return null;
var result = new Dictionary<TKey, TValue>(count);
var keyr = keySerializer.GetReader<TKey>();
var valuer = valueSerializer.GetReader<TValue>();
for (int i = 0; i < count; i++)
var keyReader = keySerializer.GetReader<TKey>();
var valueReader = valueSerializer.GetReader<TValue>();
for (var index = 0; index < count; index++)
{
var key = keyr(ctx, reader);
var value = valuer(ctx, reader);
var key = keyReader(context, reader);
var value = valueReader(context, reader);
result.Add(key, value);
}
return result;
};

return read;
}
}
Expand Down
2 changes: 1 addition & 1 deletion rd-net/RdFramework.Reflection/ReflectionSerializers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ private void RegisterModelSerializer<T>()
{
if (allowNullable)
{
unsafeWriter.Write(value != null);
unsafeWriter.WriteBoolean(value != null);
if (value == null)
return;
}
Expand Down
9 changes: 4 additions & 5 deletions rd-net/RdFramework.Reflection/ScalarSerializer.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
Expand Down Expand Up @@ -154,7 +152,7 @@ private SerializerPair CreateCustomScalar<T>(ISerializersSource serializers)
if (allowNullable)
{
unsafeWriter.Write(value != null);
unsafeWriter.WriteBoolean(value != null);
if (value == null)
return;
}
Expand Down Expand Up @@ -207,9 +205,10 @@ private SerializerPair CreateEnumSerializer<T>()
var writerCaster = Expression.Lambda<Func<T, int>>(writerConvert, writerParameter).Compile();

if (Mode.IsAssertion) Assertion.Require(typeof(T).IsSubclassOf(typeof(Enum)), "{0}", typeof(T));

var result = new SerializerPair(
(CtxReadDelegate<T>) ((ctx, reader) => readerCaster(reader.ReadInt())),
(CtxWriteDelegate<T>) ((ctx, w, o) => w.Write(writerCaster(o))));
(CtxReadDelegate<T>) ((_, reader) => readerCaster(reader.ReadInt())),
(CtxWriteDelegate<T>) ((_, writer, o) => writer.WriteInt32(writerCaster(o))));

return result;
}
Expand Down
Loading

0 comments on commit e6c1dcb

Please sign in to comment.