Skip to content

Commit

Permalink
Add Memory-based binary converters (AllocZero#242)
Browse files Browse the repository at this point in the history
* Add Memory-based binary converters
* Update converters section in docs.
  • Loading branch information
firenero authored May 11, 2024
1 parent a52c374 commit dd8ec28
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 3 deletions.
3 changes: 2 additions & 1 deletion src/EfficientDynamoDb/Converters/DdbWriter.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Runtime.CompilerServices;
using System.Text.Json;
using System.Threading.Tasks;
Expand Down Expand Up @@ -47,7 +48,7 @@ public void WriteDdbBool(bool value)
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteDdbBinary(byte[] value)
public void WriteDdbBinary(ReadOnlySpan<byte> value)
{
JsonWriter.WriteStartObject();
JsonWriter.WriteBase64String(DdbTypeNames.Binary, value);
Expand Down
4 changes: 3 additions & 1 deletion src/EfficientDynamoDb/DynamoDbContextMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using EfficientDynamoDb.Internal.Converters.Collections;
using EfficientDynamoDb.Internal.Converters.Documents;
using EfficientDynamoDb.Internal.Converters.Primitives;
using EfficientDynamoDb.Internal.Converters.Primitives.Binary;
using EfficientDynamoDb.Internal.Metadata;

namespace EfficientDynamoDb
Expand All @@ -22,7 +23,8 @@ public class DynamoDbContextMetadata
new DictionaryDdbConverterFactory(), new IDictionaryDdbConverterFactory(), new IReadOnlyDictionaryDdbConverterFactory(),
new NumberSetDdbConverterFactory(), new NumberISetDdbConverterFactory(), new StringSetDdbConverterFactory(), new StringISetDdbConverterFactory(),
new IReadOnlyCollectionDdbConverterFactory(), new IReadOnlyListDdbConverterFactory(), new IListDdbConverterFactory(),
new DocumentDdbConverterFactory(), new AttributeValueDdbConverterFactory(), new BinaryDdbConverterFactory(), new ArrayDdbConverterFactory()
new DocumentDdbConverterFactory(), new AttributeValueDdbConverterFactory(), new BinaryDdbConverterFactory(), new ArrayDdbConverterFactory(),
new BinaryToMemoryDdbConverterFactory(), new BinaryToReadOnlyMemoryDdbConverterFactory(),
};

private readonly IReadOnlyCollection<DdbConverter> _converters;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using EfficientDynamoDb.Converters;
using EfficientDynamoDb.DocumentModel;

namespace EfficientDynamoDb.Internal.Converters.Primitives
namespace EfficientDynamoDb.Internal.Converters.Primitives.Binary
{
internal sealed class BinaryDdbConverter : DdbConverter<byte[]?>
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using EfficientDynamoDb.Converters;
using EfficientDynamoDb.DocumentModel;

namespace EfficientDynamoDb.Internal.Converters.Primitives.Binary
{
internal sealed class BinaryToMemoryDdbConverter : DdbConverter<Memory<byte>>
{
public override Memory<byte> Read(in AttributeValue attributeValue) =>
attributeValue.AsBinaryAttribute().Value;

public override AttributeValue Write(ref Memory<byte> value)
{
var array = MemoryMarshal.TryGetArray((ReadOnlyMemory<byte>)value, out var segment)
? segment.Array
: value.ToArray();
Debug.Assert(array != null);

return new AttributeValue(new BinaryAttributeValue(array));
}

public override Memory<byte> Read(ref DdbReader reader) =>
reader.JsonReaderValue.GetBytesFromBase64();

public override void Write(in DdbWriter writer, ref Memory<byte> value) =>
writer.WriteDdbBinary(value.Span);
}

internal sealed class BinaryToMemoryDdbConverterFactory : DdbConverterFactory
{
public override bool CanConvert(Type typeToConvert) =>
typeToConvert == typeof(Memory<byte>) || typeToConvert == typeof(Memory<byte>?);

public override DdbConverter CreateConverter(Type typeToConvert, DynamoDbContextMetadata metadata) =>
new BinaryToMemoryDdbConverter();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using EfficientDynamoDb.Converters;
using EfficientDynamoDb.DocumentModel;

namespace EfficientDynamoDb.Internal.Converters.Primitives.Binary
{
internal sealed class BinaryToReadOnlyMemoryDdbConverter : DdbConverter<ReadOnlyMemory<byte>>
{
public override ReadOnlyMemory<byte> Read(in AttributeValue attributeValue) =>
attributeValue.AsBinaryAttribute().Value;

public override AttributeValue Write(ref ReadOnlyMemory<byte> value)
{
var array = MemoryMarshal.TryGetArray(value, out var segment)
? segment.Array
: value.ToArray();
Debug.Assert(array != null);

return new AttributeValue(new BinaryAttributeValue(array));
}

public override ReadOnlyMemory<byte> Read(ref DdbReader reader) =>
reader.JsonReaderValue.GetBytesFromBase64();

public override void Write(in DdbWriter writer, ref ReadOnlyMemory<byte> value) =>
writer.WriteDdbBinary(value.Span);
}

internal sealed class BinaryToReadOnlyMemoryDdbConverterFactory : DdbConverterFactory
{
public override bool CanConvert(Type typeToConvert) =>
typeToConvert == typeof(ReadOnlyMemory<byte>) || typeToConvert == typeof(ReadOnlyMemory<byte>?);

public override DdbConverter CreateConverter(Type typeToConvert, DynamoDbContextMetadata metadata) =>
new BinaryToReadOnlyMemoryDdbConverter();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using EfficientDynamoDb.Exceptions;
using EfficientDynamoDb.Internal.Converters.Collections.BinarySet;
using EfficientDynamoDb.Internal.Converters.Primitives;
using EfficientDynamoDb.Internal.Converters.Primitives.Binary;
using EfficientDynamoDb.Internal.Converters.Primitives.Enums;
using EfficientDynamoDb.Internal.Converters.Primitives.Numbers;

Expand Down
1 change: 1 addition & 0 deletions website/docs/dev_guide/high_level/converters.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ EfficientDynamoDb does not require specifying a converter explicitly for the fol
* Guids
* Booleans
* Collections: arrays, lists, dictionaries, sets (including their read-only and mutable interfaces)
* Binary data: `byte[]`, `Memory<byte>`, `ReadOnlyMemory<byte>`
* `AttributeValue` structs (low-level API representation of the DynamoDB attribute)

In addition, you can use one of the following converters to change the default behavior:
Expand Down

0 comments on commit dd8ec28

Please sign in to comment.