diff --git a/src/EfficientDynamoDb/Converters/DdbWriter.cs b/src/EfficientDynamoDb/Converters/DdbWriter.cs index ed5427df..97ddedf5 100644 --- a/src/EfficientDynamoDb/Converters/DdbWriter.cs +++ b/src/EfficientDynamoDb/Converters/DdbWriter.cs @@ -1,3 +1,4 @@ +using System; using System.Runtime.CompilerServices; using System.Text.Json; using System.Threading.Tasks; @@ -47,7 +48,7 @@ public void WriteDdbBool(bool value) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void WriteDdbBinary(byte[] value) + public void WriteDdbBinary(ReadOnlySpan value) { JsonWriter.WriteStartObject(); JsonWriter.WriteBase64String(DdbTypeNames.Binary, value); diff --git a/src/EfficientDynamoDb/DynamoDbContextMetadata.cs b/src/EfficientDynamoDb/DynamoDbContextMetadata.cs index ee1d846f..8c1b924a 100644 --- a/src/EfficientDynamoDb/DynamoDbContextMetadata.cs +++ b/src/EfficientDynamoDb/DynamoDbContextMetadata.cs @@ -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 @@ -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 _converters; diff --git a/src/EfficientDynamoDb/Internal/Converters/Primitives/BinaryDdbConverter.cs b/src/EfficientDynamoDb/Internal/Converters/Primitives/Binary/BinaryDdbConverter.cs similarity index 95% rename from src/EfficientDynamoDb/Internal/Converters/Primitives/BinaryDdbConverter.cs rename to src/EfficientDynamoDb/Internal/Converters/Primitives/Binary/BinaryDdbConverter.cs index 3613aec1..d11ae003 100644 --- a/src/EfficientDynamoDb/Internal/Converters/Primitives/BinaryDdbConverter.cs +++ b/src/EfficientDynamoDb/Internal/Converters/Primitives/Binary/BinaryDdbConverter.cs @@ -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 { diff --git a/src/EfficientDynamoDb/Internal/Converters/Primitives/Binary/BinaryToMemoryDdbConverter.cs b/src/EfficientDynamoDb/Internal/Converters/Primitives/Binary/BinaryToMemoryDdbConverter.cs new file mode 100644 index 00000000..40e807a3 --- /dev/null +++ b/src/EfficientDynamoDb/Internal/Converters/Primitives/Binary/BinaryToMemoryDdbConverter.cs @@ -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> + { + public override Memory Read(in AttributeValue attributeValue) => + attributeValue.AsBinaryAttribute().Value; + + public override AttributeValue Write(ref Memory value) + { + var array = MemoryMarshal.TryGetArray((ReadOnlyMemory)value, out var segment) + ? segment.Array + : value.ToArray(); + Debug.Assert(array != null); + + return new AttributeValue(new BinaryAttributeValue(array)); + } + + public override Memory Read(ref DdbReader reader) => + reader.JsonReaderValue.GetBytesFromBase64(); + + public override void Write(in DdbWriter writer, ref Memory value) => + writer.WriteDdbBinary(value.Span); + } + + internal sealed class BinaryToMemoryDdbConverterFactory : DdbConverterFactory + { + public override bool CanConvert(Type typeToConvert) => + typeToConvert == typeof(Memory) || typeToConvert == typeof(Memory?); + + public override DdbConverter CreateConverter(Type typeToConvert, DynamoDbContextMetadata metadata) => + new BinaryToMemoryDdbConverter(); + } +} \ No newline at end of file diff --git a/src/EfficientDynamoDb/Internal/Converters/Primitives/Binary/BinaryToReadOnlyMemoryDdbConverter.cs b/src/EfficientDynamoDb/Internal/Converters/Primitives/Binary/BinaryToReadOnlyMemoryDdbConverter.cs new file mode 100644 index 00000000..6b62edf6 --- /dev/null +++ b/src/EfficientDynamoDb/Internal/Converters/Primitives/Binary/BinaryToReadOnlyMemoryDdbConverter.cs @@ -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> + { + public override ReadOnlyMemory Read(in AttributeValue attributeValue) => + attributeValue.AsBinaryAttribute().Value; + + public override AttributeValue Write(ref ReadOnlyMemory 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 Read(ref DdbReader reader) => + reader.JsonReaderValue.GetBytesFromBase64(); + + public override void Write(in DdbWriter writer, ref ReadOnlyMemory value) => + writer.WriteDdbBinary(value.Span); + } + + internal sealed class BinaryToReadOnlyMemoryDdbConverterFactory : DdbConverterFactory + { + public override bool CanConvert(Type typeToConvert) => + typeToConvert == typeof(ReadOnlyMemory) || typeToConvert == typeof(ReadOnlyMemory?); + + public override DdbConverter CreateConverter(Type typeToConvert, DynamoDbContextMetadata metadata) => + new BinaryToReadOnlyMemoryDdbConverter(); + } +} \ No newline at end of file diff --git a/src/EfficientDynamoDb/Internal/Metadata/DefaultDdbConverterFactory.cs b/src/EfficientDynamoDb/Internal/Metadata/DefaultDdbConverterFactory.cs index 031c194d..f28e6779 100644 --- a/src/EfficientDynamoDb/Internal/Metadata/DefaultDdbConverterFactory.cs +++ b/src/EfficientDynamoDb/Internal/Metadata/DefaultDdbConverterFactory.cs @@ -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; diff --git a/website/docs/dev_guide/high_level/converters.md b/website/docs/dev_guide/high_level/converters.md index a82f448b..a607a7a9 100644 --- a/website/docs/dev_guide/high_level/converters.md +++ b/website/docs/dev_guide/high_level/converters.md @@ -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`, `ReadOnlyMemory` * `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: