-
-
Save thenameless314159/a2a6487ce19c0da24d08a1cf328ddc8e to your computer and use it in GitHub Desktop.
DotNext API proposal
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// <summary> | |
/// Represents an object that can be both restored from and converted to a span-based binary representation. | |
/// </summary> | |
/// <remarks> | |
/// This interface is intended to be used for objects that exposes settable members. | |
/// </remarks> | |
public interface IBufferFormattable : IBufferWritable, IBinaryReadable | |
{ | |
} | |
/// <summary> | |
/// Represents an object that can be both restored from and converted to a binary representation. | |
/// </summary> | |
/// <typeparam name="TSelf">The implementing type.</typeparam> | |
public interface IBufferFormattable<TSelf> : IBufferWritable, IBinaryReadable<TSelf> | |
where TSelf : IBufferFormattable<TSelf> | |
{ | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// <summary> | |
/// Represents an object that can be restored from a span-based binary representation. | |
/// </summary> | |
/// <remarks> | |
/// This interface is intended to be used for objects that exposes settable members. | |
/// </remarks> | |
public interface IBinaryReadable : ISpanReadable<byte> | |
{ | |
/// <summary> | |
/// Restores the instance values from its binary representation. | |
/// </summary> | |
/// <param name="source">The source buffer.</param> | |
/// <param name="bytesRead">The number of bytes that was read from the source buffer.</param> | |
/// <returns>The restored object the parsing done successfully; otherwise <see langword="null"/>.</returns> | |
public static T? Read<T>(in ReadOnlySequence<byte> source, out int bytesRead) | |
where T : IBinaryReadable<T> | |
=> IBinaryReadable<T>.Read(in source, out bytesRead); | |
/// <summary> | |
/// Restores the instance values from its binary representation. | |
/// </summary> | |
/// <param name="source">The source buffer.</param> | |
/// <param name="bytesRead">The number of bytes that was read from the source buffer.</param> | |
/// <returns>The restored object the parsing done successfully; otherwise <see langword="null"/>.</returns> | |
public static T? Read<T>(ReadOnlySpan<byte> source, out int bytesRead) | |
where T : IBinaryReadable<T> | |
=> IBinaryReadable<T>.Read(source, out bytesRead); | |
/// <summary> | |
/// Attempts to restore the object from its binary representation. | |
/// </summary> | |
/// <param name="source">The source buffer.</param> | |
/// <param name="result">The restored object.</param> | |
/// <param name="bytesRead">The number of bytes that was read from the source buffer.</param> | |
/// <param name="rethrowOnFailure">Whether read exceptions should be thrown or discarded.</param> | |
/// <returns><see langword="true"/> if the parsing done successfully; otherwise, <see langword="false"/>.</returns> | |
public static bool TryRead<T>(in ReadOnlySequence<byte> source, [NotNullWhen(true)] out T? result, out int bytesRead, bool rethrowOnFailure = true) | |
where T : IBinaryReadable<T> | |
=> IBinaryReadable<T>.TryRead(in source, out result, out bytesRead, rethrowOnFailure); | |
/// <summary> | |
/// Attempts to restore the object from its binary representation. | |
/// </summary> | |
/// <param name="source">The source buffer.</param> | |
/// <param name="result">The restored object.</param> | |
/// <param name="bytesRead">The number of bytes that was read from the source buffer.</param> | |
/// <param name="rethrowOnFailure">Whether read exceptions should be thrown or discarded.</param> | |
/// <returns><see langword="true"/> if the parsing done successfully; otherwise, <see langword="false"/>.</returns> | |
public static bool TryRead<T>(ReadOnlySpan<byte> source, [NotNullWhen(true)] out T? result, out int bytesRead, bool rethrowOnFailure = true) | |
where T : IBinaryReadable<T> | |
=> IBinaryReadable<T>.TryRead(source, out result, out bytesRead, rethrowOnFailure); | |
} | |
/// <summary> | |
/// Represents an object that can be restored from a binary representation. | |
/// </summary> | |
/// <typeparam name="TSelf">The implementing type.</typeparam> | |
public interface IBinaryReadable<out TSelf> : ISpanReadable<TSelf, byte> | |
where TSelf : IBinaryReadable<TSelf> | |
{ | |
/// <summary> | |
/// Restores the instance values from its binary representation. | |
/// </summary> | |
/// <param name="source">The source buffer.</param> | |
/// <param name="bytesRead">The number of bytes that was read from the source buffer.</param> | |
/// <returns>The restored object the parsing done successfully; otherwise <see langword="null"/>.</returns> | |
public static TSelf? Read(in ReadOnlySequence<byte> source, out int bytesRead) | |
{ | |
if (source.IsSingleSegment) | |
return Read(source.FirstSpan, out bytesRead); | |
if (source.Length > int.MaxValue) | |
throw new ArgumentOutOfRangeException(nameof(source), default(string)); | |
int size = (int)source.Length; | |
using BufferRental<byte> buffer = size <= (uint)BufferRental<byte>.StackallocThreshold | |
? new(stackalloc byte[size]) | |
: new(size); | |
source.CopyTo(buffer.Span); | |
return Read(buffer.Span[..size], out bytesRead); | |
} | |
/// <summary> | |
/// Attempts to restore the object from its binary representation. | |
/// </summary> | |
/// <param name="source">The source buffer.</param> | |
/// <param name="result">The restored object.</param> | |
/// <param name="bytesRead">The number of bytes that was read from the source buffer.</param> | |
/// <param name="rethrowOnFailure">Whether read exceptions should be thrown or discarded.</param> | |
/// <returns><see langword="true"/> if the parsing done successfully; otherwise, <see langword="false"/>.</returns> | |
public static bool TryRead(in ReadOnlySequence<byte> source, [NotNullWhen(true)] out TSelf? result, out int bytesRead, bool rethrowOnFailure = true) | |
{ | |
if (source.IsSingleSegment) | |
return TryRead(source.FirstSpan, out result, out bytesRead, rethrowOnFailure); | |
if (source.Length > int.MaxValue) | |
throw new ArgumentOutOfRangeException(nameof(source), default(string)); | |
int size = (int)source.Length; | |
using BufferRental<byte> buffer = size <= (uint)BufferRental<byte>.StackallocThreshold | |
? new(stackalloc byte[size]) | |
: new(size); | |
source.CopyTo(buffer.Span); | |
return TryRead(buffer.Span[..size], out result, out bytesRead, rethrowOnFailure); | |
} | |
} | |
/// <summary> | |
/// Provides extension methods for the <see cref="IBinaryReadable"/> interface. | |
/// </summary> | |
public static class BufferReadableExtensions | |
{ | |
/// <summary> | |
/// Restores the instance values from its binary representation. | |
/// </summary> | |
/// <param name="value">The readable value.</param> | |
/// <param name="source">The source buffer.</param> | |
/// <returns>The number of bytes that was read from the source buffer.</returns> | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static int Read(this IBinaryReadable value, in ReadOnlySequence<byte> source) | |
{ | |
if (source.IsSingleSegment) | |
return value.Deserialize(source.FirstSpan); | |
if (source.Length > int.MaxValue) | |
throw new ArgumentOutOfRangeException(nameof(source), default(string)); | |
int size = (int)source.Length; | |
using BufferRental<byte> buffer = size <= (uint)BufferRental<byte>.StackallocThreshold | |
? new(stackalloc byte[size]) | |
: new(size); | |
source.CopyTo(buffer.Span); | |
return value.Deserialize(buffer.Span[..size]); | |
} | |
/// <summary> | |
/// Attempts to restore the object from its binary representation. | |
/// </summary> | |
/// <param name="value">The readable value.</param> | |
/// <param name="source">The source buffer.</param> | |
/// <param name="bytesRead">The number of bytes that was read from the source buffer.</param> | |
/// <param name="rethrowOnFailure">Whether read exceptions should be thrown or discarded.</param> | |
/// <returns><see langword="true"/> if the parsing done successfully; otherwise, <see langword="false"/>.</returns> | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static bool TryRead(this IBinaryReadable value, in ReadOnlySequence<byte> source, out int bytesRead, bool rethrowOnFailure = true) | |
{ | |
if (source.IsSingleSegment) | |
return value.TryDeserialize(source.FirstSpan, out bytesRead, rethrowOnFailure); | |
if (source.Length > int.MaxValue) | |
throw new ArgumentOutOfRangeException(nameof(source), default(string)); | |
int size = (int)source.Length; | |
using BufferRental<byte> buffer = size <= (uint)BufferRental<byte>.StackallocThreshold | |
? new(stackalloc byte[size]) | |
: new(size); | |
source.CopyTo(buffer.Span); | |
return value.TryDeserialize(buffer.Span[..size], out bytesRead, rethrowOnFailure); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// <summary> | |
/// Represents an object that can be restored from a sequence-based binary representation. | |
/// </summary> | |
/// <remarks> | |
/// This interface is intended to be used for objects that exposes settable members. | |
/// </remarks> | |
public interface IBufferReadable | |
{ | |
/// <summary> | |
/// Restores the instance values from its binary representation. | |
/// </summary> | |
/// <param name="input">The input sequence reader.</param> | |
void Deserialize(ref SequenceReader<byte> input); | |
/// <summary> | |
/// Restores the instance values from its binary representation. | |
/// </summary> | |
/// <param name="source">The source buffer.</param> | |
/// <param name="bytesRead">The number of bytes that was read from the source buffer.</param> | |
/// <returns>The restored object the parsing done successfully; otherwise <see langword="null"/>.</returns> | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static T? Read<T>(in ReadOnlySequence<byte> source, out long bytesRead) | |
where T : IBufferReadable<T> | |
=> IBufferReadable<T>.Read(in source, out bytesRead); | |
/// <summary> | |
/// Restores the instance values from its binary representation. | |
/// </summary> | |
/// <param name="source">The source buffer.</param> | |
/// <param name="bytesRead">The number of bytes that was read from the source buffer.</param> | |
/// <returns>The restored object the parsing done successfully; otherwise <see langword="null"/>.</returns> | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static T? Read<T>(in ReadOnlyMemory<byte> source, out long bytesRead) | |
where T : IBufferReadable<T> | |
=> IBufferReadable<T>.Read(in source, out bytesRead); | |
/// <summary> | |
/// Attempts to restore the object from its binary representation. | |
/// </summary> | |
/// <param name="source">The source buffer.</param> | |
/// <param name="result">The restored object.</param> | |
/// <param name="bytesRead">The number of bytes that was read from the source buffer.</param> | |
/// <param name="rethrowOnFailure">Whether read exceptions should be thrown or discarded.</param> | |
/// <returns><see langword="true"/> if the parsing done successfully; otherwise, <see langword="false"/>.</returns> | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static bool TryRead<T>(in ReadOnlySequence<byte> source, [NotNullWhen(true)] out T? result, out long bytesRead, bool rethrowOnFailure = true) | |
where T : IBufferReadable<T> | |
=> IBufferReadable<T>.TryRead(in source, out result, out bytesRead, rethrowOnFailure); | |
/// <summary> | |
/// Attempts to restore the object from its binary representation. | |
/// </summary> | |
/// <param name="source">The source buffer.</param> | |
/// <param name="result">The restored object.</param> | |
/// <param name="bytesRead">The number of bytes that was read from the source buffer.</param> | |
/// <param name="rethrowOnFailure">Whether read exceptions should be thrown or discarded.</param> | |
/// <returns><see langword="true"/> if the parsing done successfully; otherwise, <see langword="false"/>.</returns> | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static bool TryRead<T>(in ReadOnlyMemory<byte> source, [NotNullWhen(true)] out T? result, out long bytesRead, bool rethrowOnFailure = true) | |
where T : IBufferReadable<T> | |
=> IBufferReadable<T>.TryRead(in source, out result, out bytesRead, rethrowOnFailure); | |
} | |
/// <summary> | |
/// Represents an object that can be restored from a binary representation. | |
/// </summary> | |
/// <typeparam name="TSelf">The implementing type.</typeparam> | |
/// <remarks> | |
/// This interface is intended to be used for decoding objects in networking scenarios from sequences obtained from a System.IO.PipeReader for example. | |
/// </remarks> | |
public interface IBufferReadable<out TSelf> | |
where TSelf : IBufferReadable<TSelf> | |
{ | |
/// <summary> | |
/// Restores the object from its binary representation. | |
/// </summary> | |
/// <param name="input">The input sequence reader.</param> | |
/// <returns>The restored object the parsing done successfully; otherwise <see langword="null"/>.</returns> | |
public static abstract TSelf? Read(ref SequenceReader<byte> input); | |
/// <summary> | |
/// Restores the object from its span representation. | |
/// </summary> | |
/// <param name="input">The input span reader.</param> | |
/// <param name="bytesRead">The number of bytes that was read from the source buffer.</param> | |
/// <returns>The restored object the parsing done successfully; otherwise <see langword="null"/>.</returns> | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static TSelf? Read(in ReadOnlySequence<byte> input, out long bytesRead) | |
{ | |
SequenceReader<byte> reader = new(input); | |
var result = TSelf.Read(ref reader); | |
bytesRead = reader.Consumed; | |
return result; | |
} | |
/// <summary> | |
/// Restores the instance values from its binary representation. | |
/// </summary> | |
/// <param name="source">The source buffer.</param> | |
/// <param name="bytesRead">The number of bytes that was read from the source buffer.</param> | |
/// <returns>The restored object the parsing done successfully; otherwise <see langword="null"/>.</returns> | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static TSelf? Read(in ReadOnlyMemory<byte> source, out long bytesRead) | |
{ | |
ReadOnlySequence<byte> sequence = new(source); | |
return Read(in sequence, out bytesRead); | |
} | |
/// <summary> | |
/// Attempts to restore the object from its span representation. | |
/// </summary> | |
/// <param name="source">The source span.</param> | |
/// <param name="result">The restored object.</param> | |
/// <param name="bytesRead">The number of bytes that was read from the source buffer.</param> | |
/// <param name="rethrowOnFailure">Whether read exceptions should be thrown or discarded.</param> | |
/// <returns><see langword="true"/> if the parsing done successfully; otherwise, <see langword="false"/>.</returns> | |
public static bool TryRead(in ReadOnlySequence<byte> source, [NotNullWhen(true)] out TSelf? result, out long bytesRead, bool rethrowOnFailure = true) | |
{ | |
SequenceReader<byte> reader = new(source); | |
try { result = TSelf.Read(ref reader); } | |
catch (Exception) when (rethrowOnFailure) | |
{ | |
throw; | |
} | |
catch | |
{ | |
result = default; | |
return false; | |
} | |
// The bytesRead must be assigned regardless of the operation success. | |
finally | |
{ | |
bytesRead = reader.Consumed; | |
} | |
return result != null; | |
} | |
/// <summary> | |
/// Attempts to restore the object from its span representation. | |
/// </summary> | |
/// <param name="source">The source span.</param> | |
/// <param name="result">The restored object.</param> | |
/// <param name="bytesRead">The number of bytes that was read from the source buffer.</param> | |
/// <param name="rethrowOnFailure">Whether read exceptions should be thrown or discarded.</param> | |
/// <returns><see langword="true"/> if the parsing done successfully; otherwise, <see langword="false"/>.</returns> | |
public static bool TryRead(in ReadOnlyMemory<byte> source, [NotNullWhen(true)] out TSelf? result, out long bytesRead, bool rethrowOnFailure = true) | |
{ | |
ReadOnlySequence<byte> sequence = new(source); | |
return TryRead(in sequence, out result, out bytesRead, rethrowOnFailure); | |
} | |
} | |
/// <summary> | |
/// Provides extension methods for the <see cref="IBufferReadable"/> interface. | |
/// </summary> | |
public static class BinaryReadableExtensions | |
{ | |
/// <summary> | |
/// Restores the instance values from its binary representation. | |
/// </summary> | |
/// <param name="value">The readable value.</param> | |
/// <param name="source">The source buffer.</param> | |
/// <returns>The number of bytes that was read from the source.</returns> | |
public static long Deserialize(this IBufferReadable value, in ReadOnlySequence<byte> source) | |
{ | |
SequenceReader<byte> reader = new(source); | |
value.Deserialize(ref reader); | |
return reader.Consumed; | |
} | |
/// <summary> | |
/// Restores the instance values from its binary representation. | |
/// </summary> | |
/// <param name="value">The readable value.</param> | |
/// <param name="source">The source buffer.</param> | |
/// <returns>The number of bytes that was read from the source.</returns> | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static long Deserialize(this IBufferReadable value, in ReadOnlyMemory<byte> source) | |
{ | |
ReadOnlySequence<byte> sequence = new(source); | |
return value.Deserialize(in sequence); | |
} | |
/// <summary> | |
/// Attempts to restore the object from its binary representation. | |
/// </summary> | |
/// <param name="value">The readable value.</param> | |
/// <param name="source">The source buffer.</param> | |
/// <param name="bytesRead">The number of bytes that was read from the source buffer.</param> | |
/// <param name="rethrowOnFailure">Whether read exceptions should be thrown or discarded.</param> | |
/// <returns><see langword="true"/> if the parsing done successfully; otherwise, <see langword="false"/>.</returns> | |
public static bool TryDeserialize(this IBufferReadable value, in ReadOnlySequence<byte> source, out long bytesRead, bool rethrowOnFailure = true) | |
{ | |
SequenceReader<byte> reader = new(source); | |
try { value.Deserialize(ref reader); } | |
catch (Exception) when (rethrowOnFailure) | |
{ | |
throw; | |
} | |
catch | |
{ | |
return false; | |
} | |
// The readCount must be assigned regardless of the operation success. | |
finally | |
{ | |
bytesRead = reader.Consumed; | |
} | |
return true; | |
} | |
/// <summary> | |
/// Attempts to restore the object from its binary representation. | |
/// </summary> | |
/// <param name="value">The readable value.</param> | |
/// <param name="source">The source buffer.</param> | |
/// <param name="bytesRead">The number of bytes that was read from the source buffer.</param> | |
/// <param name="rethrowOnFailure">Whether read exceptions should be thrown or discarded.</param> | |
/// <returns><see langword="true"/> if the parsing done successfully; otherwise, <see langword="false"/>.</returns> | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static bool TryDeserialize(this IBufferReadable value, in ReadOnlyMemory<byte> source, out long bytesRead, bool rethrowOnFailure = true) | |
{ | |
ReadOnlySequence<byte> sequence = new(source); | |
return value.TryDeserialize(in sequence, out bytesRead, rethrowOnFailure); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// <summary> | |
/// Represents an object that can be both restored from a sequence-based and converted to a span-based binary representation. | |
/// </summary> | |
/// <remarks> | |
/// This interface is intended to be used for objects that exposes settable members. | |
/// </remarks> | |
public interface IBufferSerializable : IBufferReadable, IBufferWritable | |
{ | |
} | |
/// <summary> | |
/// Represents an object that can be both restored from and converted to a binary representation. | |
/// </summary> | |
/// <remarks> | |
/// This interface is intended to be used for decoding objects in networking scenarios from sequences obtained from a System.IO.PipeReader for example. | |
/// </remarks> | |
public interface IBufferSerializable<out TSelf> : IBufferReadable<TSelf>, IBufferWritable | |
where TSelf : IBufferSerializable<TSelf> | |
{ | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// <summary> | |
/// Represents an object that can be converted to a binary representation. | |
/// </summary> | |
public interface IBufferWritable : ISpanWritable<byte>, ISizeComputable | |
{ | |
} | |
/// <summary> | |
/// Provides extension methods for the <see cref="IBufferWritable"/> interface. | |
/// </summary> | |
public static class BufferWritableExtensions | |
{ | |
/// <summary> | |
/// Encodes the object to the output buffer. | |
/// </summary> | |
/// <param name="value">The writable value.</param> | |
/// <param name="output">The output buffer writer.</param> | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static void WriteTo(this IBufferWritable value, IBufferWriter<byte> output) | |
{ | |
int size = value.GetSizeOf(); | |
Span<byte> span = output.GetSpan(size); | |
int bytesWritten = value.Serialize(span); | |
Debug.Assert(bytesWritten == size); | |
output.Advance(bytesWritten); | |
} | |
/// <summary> | |
/// Gets the object as a binary representation. | |
/// </summary> | |
/// <param name="value">The writable value.</param> | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static byte[] GetBytes(this IBufferWritable value) | |
{ | |
byte[] buffer = new byte[value.GetSizeOf()]; | |
int bytesWritten = value.Serialize(buffer); | |
Debug.Assert(bytesWritten == buffer.Length); | |
return buffer; | |
} | |
/// <summary> | |
/// Gets the object as an owned binary representation. | |
/// </summary> | |
/// <param name="value">The writable value.</param> | |
/// <param name="bytesWritten">The number of bytes that was written to the</param> | |
/// <param name="allocator">The memory allocator.</param> | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static IMemoryOwner<byte> GetOwnedBytes(this IBufferWritable value, out int bytesWritten, Func<int, IMemoryOwner<byte>>? allocator = null) | |
{ | |
int size = value.GetSizeOf(); | |
IMemoryOwner<byte> owner = | |
allocator?.Invoke(size) | |
?? MemoryPool<byte>.Shared.Rent(size); | |
bytesWritten = value.Serialize(owner.Memory.Span[..size]); | |
Debug.Assert(bytesWritten == size); | |
return owner; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// <summary> | |
/// Represents an object that can be deserialized from a span of <typeparamref name="T" /> elements. | |
/// </summary> | |
/// <remarks> | |
/// This interface is intended to be used for objects that exposes settable members. | |
/// </remarks> | |
/// <typeparam name="T">The span element type.</typeparam> | |
public interface ISpanReadable<T> | |
{ | |
/// <summary> | |
/// Restores the instance values from its span representation. | |
/// </summary> | |
/// <param name="input">The input span reader.</param> | |
void Deserialize(ref SpanReader<T> input); | |
} | |
/// <summary> | |
/// Represents an object that can be restored from a span of <typeparamref name="T" /> elements. | |
/// </summary> | |
/// <typeparam name="TSelf">The implementing type.</typeparam> | |
/// <typeparam name="T">The span element type.</typeparam> | |
public interface ISpanReadable<out TSelf, T> | |
where TSelf : ISpanReadable<TSelf, T> | |
{ | |
/// <summary> | |
/// Restores the object from its span representation. | |
/// </summary> | |
/// <param name="input">The input span reader.</param> | |
/// <returns>The restored object the parsing done successfully; otherwise <see langword="null"/>.</returns> | |
public static abstract TSelf? Read(ref SpanReader<T> input); | |
/// <summary> | |
/// Restores the object from its span representation. | |
/// </summary> | |
/// <param name="source">The source span.</param> | |
/// <param name="readCount">The number of elements that was read from the source span.</param> | |
/// <returns>The restored object the parsing done successfully; otherwise <see langword="null"/>.</returns> | |
public static TSelf? Read(ReadOnlySpan<T> source, out int readCount) | |
{ | |
SpanReader<T> reader = new(source); | |
var result = TSelf.Read(ref reader); | |
readCount = reader.ConsumedCount; | |
return result; | |
} | |
/// <summary> | |
/// Attempts to restore the object from its span representation. | |
/// </summary> | |
/// <param name="source">The source span.</param> | |
/// <param name="result">The restored object.</param> | |
/// <param name="readCount">The number of elements that was read from the source span.</param> | |
/// <param name="rethrowOnFailure">Whether read exceptions should be thrown or discarded.</param> | |
/// <returns><see langword="true"/> if the parsing done successfully; otherwise, <see langword="false"/>.</returns> | |
public static bool TryRead(ReadOnlySpan<T> source, [NotNullWhen(true)] out TSelf? result, out int readCount, bool rethrowOnFailure = true) | |
{ | |
SpanReader<T> reader = new(source); | |
try { result = TSelf.Read(ref reader); } | |
catch (Exception) when (rethrowOnFailure) | |
{ | |
throw; | |
} | |
catch | |
{ | |
result = default; | |
return false; | |
} | |
// The readCount must be assigned regardless of the operation success. | |
finally | |
{ | |
readCount = reader.ConsumedCount; | |
} | |
return result != null; | |
} | |
} | |
/// <summary> | |
/// Provides extension methods for the <see cref="ISpanReadable{T}"/> interface. | |
/// </summary> | |
public static class SpanReadableExtensions | |
{ | |
/// <summary> | |
/// Restores the instance values from its binary representation. | |
/// </summary> | |
/// <param name="value">The readable value.</param> | |
/// <param name="source">The source span.</param> | |
/// <returns>The number of bytes that was read from the source buffer.</returns> | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static int Deserialize<T>(this ISpanReadable<T> value, ReadOnlySpan<T> source) | |
{ | |
SpanReader<T> reader = new(source); | |
value.Deserialize(ref reader); | |
return reader.ConsumedCount; | |
} | |
/// <summary> | |
/// Attempts to restore the object from its binary representation. | |
/// </summary> | |
/// <param name="value">The readable value.</param> | |
/// <param name="source">The source span.</param> | |
/// <param name="readCount">The number of elements that was read from the source span.</param> | |
/// <param name="rethrowOnFailure">Whether read exceptions should be thrown or discarded.</param> | |
/// <returns><see langword="true"/> if the parsing done successfully; otherwise, <see langword="false"/>.</returns> | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static bool TryDeserialize<T>(this ISpanReadable<T> value, ReadOnlySpan<T> source, out int readCount, bool rethrowOnFailure = true) | |
{ | |
SpanReader<T> reader = new(source); | |
try { value.Deserialize(ref reader); } | |
catch (Exception) when (rethrowOnFailure) | |
{ | |
throw; | |
} | |
catch | |
{ | |
return false; | |
} | |
// The writtenCount must be assigned regardless of the operation success. | |
finally | |
{ | |
readCount = reader.ConsumedCount; | |
} | |
return true; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// <summary> | |
/// Represents helper methods to work with <see cref="SequenceReader{T}"/> buffer representations. | |
/// </summary> | |
public static class SequenceReaderExtensions | |
{ | |
/// <summary> | |
/// Reads the value of blittable type from the raw bytes | |
/// represented by the memory block. | |
/// </summary> | |
/// <param name="reader">The memory reader.</param> | |
/// <param name="result">The value deserialized from bytes.</param> | |
/// <typeparam name="T">The blittable type.</typeparam> | |
/// <returns> | |
/// <see langword="true"/> if memory block contains enough amount of unread bytes to decode the value; | |
/// otherwise, <see langword="false"/>. | |
/// </returns> | |
public static unsafe bool TryRead<T>(this scoped ref SequenceReader<byte> reader, out T result) | |
where T : unmanaged | |
{ | |
ReadOnlySpan<byte> unreadSpan = reader.UnreadSpan; | |
if (unreadSpan.Length < sizeof(T)) | |
return TryReadMultiSegment(ref reader, out result); | |
result = ReadUnaligned<T>(ref MemoryMarshal.GetReference(unreadSpan)); | |
reader.Advance(sizeof(T)); | |
return true; | |
} | |
private static unsafe bool TryReadMultiSegment<T>(scoped ref SequenceReader<byte> reader, out T result) | |
where T : unmanaged | |
{ | |
Span<byte> span = stackalloc byte[sizeof(T)]; | |
if (!reader.TryCopyTo(span)) | |
{ | |
result = default; | |
return false; | |
} | |
result = ReadUnaligned<T>(ref MemoryMarshal.GetReference(span)); | |
reader.Advance(sizeof(T)); | |
return true; | |
} | |
/// <summary> | |
/// Reads the value of blittable type from the raw bytes | |
/// represented by the memory block. | |
/// </summary> | |
/// <param name="reader">The memory reader.</param> | |
/// <typeparam name="T">The blittable type.</typeparam> | |
/// <returns>The value deserialized from bytes.</returns> | |
/// <exception cref="InternalBufferOverflowException">The end of memory block is reached.</exception> | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static unsafe T Read<T>(this ref SequenceReader<byte> reader) where T : unmanaged | |
{ | |
if (!reader.TryReadExact(sizeof(T), out ReadOnlySequence<byte> sequence)) | |
ThrowInternalBufferOverflowException(); | |
ReadOnlySpan<byte> span = sequence.FirstSpan; | |
if (span.Length < sizeof(T)) | |
return ReadMultiSegment<T>(in sequence); | |
return ReadUnaligned<T>(ref MemoryMarshal.GetReference(span)); | |
} | |
private static unsafe T ReadMultiSegment<T>(in ReadOnlySequence<byte> input) | |
where T : unmanaged | |
{ | |
Span<byte> span = stackalloc byte[sizeof(T)]; | |
input.CopyTo(span); | |
return ReadUnaligned<T>(ref MemoryMarshal.GetReference(span)); | |
} | |
/// <summary> | |
/// Decodes 16-bit signed integer. | |
/// </summary> | |
/// <param name="reader">The memory reader.</param> | |
/// <param name="isLittleEndian"><see langword="true"/> to use little-endian encoding; <see langword="false"/> to use big-endian encoding.</param> | |
/// <returns>The decoded value.</returns> | |
/// <exception cref="InternalBufferOverflowException">The end of memory block is reached.</exception> | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static short ReadInt16(this ref SequenceReader<byte> reader, bool isLittleEndian = true) | |
=> isLittleEndian != BitConverter.IsLittleEndian | |
? ReverseEndianness(reader.Read<short>()) | |
: reader.Read<short>(); | |
// etc... | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment