diff --git a/Directory.Packages.props b/Directory.Packages.props
index a84cc1e8590..192a57a583e 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -33,6 +33,7 @@
+
diff --git a/Orleans.slnx b/Orleans.slnx
index 3a3e39ca595..3c4b5275e7d 100644
--- a/Orleans.slnx
+++ b/Orleans.slnx
@@ -42,6 +42,7 @@
+
diff --git a/src/Orleans.Serialization.MemoryPack/MemoryPackCodec.cs b/src/Orleans.Serialization.MemoryPack/MemoryPackCodec.cs
new file mode 100644
index 00000000000..53c870be287
--- /dev/null
+++ b/src/Orleans.Serialization.MemoryPack/MemoryPackCodec.cs
@@ -0,0 +1,241 @@
+using System;
+using System.Collections.Concurrent;
+using System.Reflection;
+using MemoryPack;
+using Microsoft.Extensions.Options;
+using Orleans.Serialization.Buffers;
+using Orleans.Serialization.Buffers.Adaptors;
+using Orleans.Serialization.Cloning;
+using Orleans.Serialization.Codecs;
+using Orleans.Serialization.Serializers;
+using Orleans.Serialization.WireProtocol;
+
+namespace Orleans.Serialization;
+
+///
+/// A serialization codec which uses .
+///
+///
+/// MemoryPack codec performs slightly worse than default Orleans serializer, if performance is critical for your application, consider using default serialization.
+///
+[Alias(WellKnownAlias)]
+public class MemoryPackCodec : IGeneralizedCodec, IGeneralizedCopier, ITypeFilter
+{
+ private static readonly ConcurrentDictionary SupportedTypes = new();
+ private static readonly Type SelfType = typeof(MemoryPackCodec);
+
+ private readonly ICodecSelector[] _serializableTypeSelectors;
+ private readonly ICopierSelector[] _copyableTypeSelectors;
+ private readonly MemoryPackCodecOptions _options;
+
+ ///
+ /// The well-known type alias for this codec.
+ ///
+ public const string WellKnownAlias = "memorypack";
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// /// Filters used to indicate which types should be serialized by this codec.
+ /// Filters used to indicate which types should be copied by this codec.
+ /// The MemoryPack codec options.
+ public MemoryPackCodec(
+ IEnumerable serializableTypeSelectors,
+ IEnumerable copyableTypeSelectors,
+ IOptions options)
+ {
+ _serializableTypeSelectors = serializableTypeSelectors.Where(t => string.Equals(t.CodecName, WellKnownAlias, StringComparison.Ordinal)).ToArray();
+ _copyableTypeSelectors = copyableTypeSelectors.Where(t => string.Equals(t.CopierName, WellKnownAlias, StringComparison.Ordinal)).ToArray();
+ _options = options.Value;
+ }
+
+ ///
+ void IFieldCodec.WriteField(ref Writer writer, uint fieldIdDelta, Type expectedType, object value)
+ {
+ if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))
+ {
+ return;
+ }
+
+ // The schema type when serializing the field is the type of the codec.
+ writer.WriteFieldHeader(fieldIdDelta, expectedType, SelfType, WireType.TagDelimited);
+
+ // Write the type name
+ ReferenceCodec.MarkValueField(writer.Session);
+ writer.WriteFieldHeaderExpected(0, WireType.LengthPrefixed);
+ writer.Session.TypeCodec.WriteLengthPrefixed(ref writer, value.GetType());
+
+ var bufferWriter = new BufferWriterBox(new());
+ try
+ {
+ MemoryPackSerializer.Serialize(value.GetType(), bufferWriter, value, _options.SerializerOptions);
+
+ ReferenceCodec.MarkValueField(writer.Session);
+ writer.WriteFieldHeaderExpected(1, WireType.LengthPrefixed);
+ writer.WriteVarUInt32((uint)bufferWriter.Value.Length);
+ bufferWriter.Value.CopyTo(ref writer);
+ }
+ finally
+ {
+ bufferWriter.Value.Dispose();
+ }
+
+ writer.WriteEndObject();
+ }
+
+ ///
+ object IFieldCodec.ReadValue(ref Reader reader, Field field)
+ {
+ if (field.IsReference)
+ {
+ return ReferenceCodec.ReadReference(ref reader, field.FieldType);
+ }
+
+ field.EnsureWireTypeTagDelimited();
+
+ var placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);
+ object result = null;
+ Type type = null;
+ uint fieldId = 0;
+ while (true)
+ {
+ var header = reader.ReadFieldHeader();
+ if (header.IsEndBaseOrEndObject)
+ {
+ break;
+ }
+
+ fieldId += header.FieldIdDelta;
+ switch (fieldId)
+ {
+ case 0:
+ ReferenceCodec.MarkValueField(reader.Session);
+ type = reader.Session.TypeCodec.ReadLengthPrefixed(ref reader);
+ break;
+ case 1:
+ if (type is null)
+ {
+ ThrowTypeFieldMissing();
+ }
+
+ ReferenceCodec.MarkValueField(reader.Session);
+ var length = reader.ReadVarUInt32();
+
+ var bufferWriter = new BufferWriterBox(new());
+ try
+ {
+ reader.ReadBytes(ref bufferWriter, (int)length);
+ result = MemoryPackSerializer.Deserialize(type, bufferWriter.Value.AsReadOnlySequence(), _options.SerializerOptions);
+ }
+ finally
+ {
+ bufferWriter.Value.Dispose();
+ }
+
+ break;
+ default:
+ reader.ConsumeUnknownField(header);
+ break;
+ }
+ }
+
+ ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);
+ return result;
+ }
+
+ ///
+ bool IGeneralizedCodec.IsSupportedType(Type type)
+ {
+ if (type == SelfType)
+ {
+ return true;
+ }
+
+ if (CommonCodecTypeFilter.IsAbstractOrFrameworkType(type))
+ {
+ return false;
+ }
+
+ foreach (var selector in _serializableTypeSelectors)
+ {
+ if (selector.IsSupportedType(type))
+ {
+ return true;
+ }
+ }
+
+ if (_options.IsSerializableType?.Invoke(type) is bool value)
+ {
+ return value;
+ }
+
+ return IsMemoryPackContract(type);
+ }
+
+ ///
+ object IDeepCopier.DeepCopy(object input, CopyContext context)
+ {
+ if (context.TryGetCopy(input, out object result))
+ {
+ return result;
+ }
+
+ var bufferWriter = new BufferWriterBox(new());
+ try
+ {
+ MemoryPackSerializer.Serialize(input.GetType(), bufferWriter, input, _options.SerializerOptions);
+
+ var sequence = bufferWriter.Value.AsReadOnlySequence();
+ result = MemoryPackSerializer.Deserialize(input.GetType(), sequence, _options.SerializerOptions);
+ }
+ finally
+ {
+ bufferWriter.Value.Dispose();
+ }
+
+ context.RecordCopy(input, result);
+ return result;
+ }
+
+ ///
+ bool IGeneralizedCopier.IsSupportedType(Type type)
+ {
+ if (CommonCodecTypeFilter.IsAbstractOrFrameworkType(type))
+ {
+ return false;
+ }
+
+ foreach (var selector in _copyableTypeSelectors)
+ {
+ if (selector.IsSupportedType(type))
+ {
+ return true;
+ }
+ }
+
+ if (_options.IsCopyableType?.Invoke(type) is bool value)
+ {
+ return value;
+ }
+
+ return IsMemoryPackContract(type);
+ }
+
+ ///
+ bool? ITypeFilter.IsTypeAllowed(Type type) => (((IGeneralizedCopier)this).IsSupportedType(type) || ((IGeneralizedCodec)this).IsSupportedType(type)) ? true : null;
+
+ private static bool IsMemoryPackContract(Type type)
+ {
+ if (SupportedTypes.TryGetValue(type, out bool isMemoryPackContract))
+ {
+ return isMemoryPackContract;
+ }
+
+ isMemoryPackContract = type.GetCustomAttribute() is not null;
+
+ SupportedTypes.TryAdd(type, isMemoryPackContract);
+ return isMemoryPackContract;
+ }
+
+ private static void ThrowTypeFieldMissing() => throw new RequiredFieldMissingException("Serialized value is missing its type field.");
+}
diff --git a/src/Orleans.Serialization.MemoryPack/MemoryPackCodecOptions.cs b/src/Orleans.Serialization.MemoryPack/MemoryPackCodecOptions.cs
new file mode 100644
index 00000000000..1415b1155fa
--- /dev/null
+++ b/src/Orleans.Serialization.MemoryPack/MemoryPackCodecOptions.cs
@@ -0,0 +1,25 @@
+using System;
+using MemoryPack;
+
+namespace Orleans.Serialization;
+
+///
+/// Options for .
+///
+public class MemoryPackCodecOptions
+{
+ ///
+ /// Gets or sets the .
+ ///
+ public MemoryPackSerializerOptions SerializerOptions { get; set; } = MemoryPackSerializerOptions.Default;
+
+ ///
+ /// Gets or sets a delegate used to determine if a type is supported by the MemoryPack serializer for serialization and deserialization.
+ ///
+ public Func IsSerializableType { get; set; }
+
+ ///
+ /// Gets or sets a delegate used to determine if a type is supported by the MemoryPack serializer for copying.
+ ///
+ public Func IsCopyableType { get; set; }
+}
diff --git a/src/Orleans.Serialization.MemoryPack/Orleans.Serialization.MemoryPack.csproj b/src/Orleans.Serialization.MemoryPack/Orleans.Serialization.MemoryPack.csproj
new file mode 100644
index 00000000000..295e67fd411
--- /dev/null
+++ b/src/Orleans.Serialization.MemoryPack/Orleans.Serialization.MemoryPack.csproj
@@ -0,0 +1,23 @@
+
+
+
+ README.md
+ Microsoft.Orleans.Serialization.MemoryPack
+ $(DefaultTargetFrameworks);netstandard2.1
+ MemoryPack integration for Orleans.Serialization
+ true
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Orleans.Serialization.MemoryPack/README.md b/src/Orleans.Serialization.MemoryPack/README.md
new file mode 100644
index 00000000000..24fd5500089
--- /dev/null
+++ b/src/Orleans.Serialization.MemoryPack/README.md
@@ -0,0 +1,87 @@
+# Microsoft Orleans Serialization for MemoryPack
+
+## Introduction
+Microsoft Orleans Serialization for MemoryPack provides MemoryPack serialization support for Microsoft Orleans using the MemoryPack format. This high-performance binary serialization format is ideal for scenarios requiring efficient serialization and deserialization.
+
+## Getting Started
+To use this package, install it via NuGet:
+
+```shell
+dotnet add package Microsoft.Orleans.Serialization.MemoryPack
+```
+
+## Example - Configuring MemoryPack Serialization
+```csharp
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using Orleans.Hosting;
+using Orleans.Serialization;
+
+var builder = Host.CreateApplicationBuilder(args)
+ .UseOrleans(siloBuilder =>
+ {
+ siloBuilder
+ .UseLocalhostClustering()
+ // Configure MemoryPack as a serializer
+ .AddSerializer(serializerBuilder => serializerBuilder.AddMemoryPackSerializer());
+ });
+
+// Run the host
+await builder.RunAsync();
+```
+
+## Example - Using MemoryPack with a Custom Type
+```csharp
+using Orleans;
+using Orleans.Serialization.Cloning;
+using Orleans.Serialization.Codecs;
+using Orleans.Serialization.Configuration;
+using Orleans.Serialization.Serializers;
+using MemoryPack;
+namespace ExampleGrains;
+
+// Define a class with MemoryPack attributes
+[MemoryPackable]
+public partial class MyMemoryPackClass
+{
+ public string Name { get; set; }
+ public int Age { get; set; }
+ public List Tags { get; set; }
+}
+
+// You can use it directly in your grain interfaces and implementation
+public interface IMyGrain : IGrainWithStringKey
+{
+ Task GetData();
+ Task SetData(MyMemoryPackClass data);
+}
+
+public class MyGrain : Grain, IMyGrain
+{
+ private MyMemoryPackClass _data;
+
+ public Task GetData()
+ {
+ return Task.FromResult(_data);
+ }
+
+ public Task SetData(MyMemoryPackClass data)
+ {
+ _data = data;
+ return Task.CompletedTask;
+ }
+}
+```
+
+## Documentation
+For more comprehensive documentation, please refer to:
+- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)
+- [Orleans Serialization](https://learn.microsoft.com/en-us/dotnet/orleans/host/configuration-guide/serialization)
+- [MemoryPack for C#](https://github.com/Cysharp/MemoryPack)
+
+## Feedback & Contributing
+- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)
+- Join our community on [Discord](https://aka.ms/orleans-discord)
+- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements
+- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)
+- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)
diff --git a/src/Orleans.Serialization.MemoryPack/SerializationHostingExtensions.cs b/src/Orleans.Serialization.MemoryPack/SerializationHostingExtensions.cs
new file mode 100644
index 00000000000..50f5ffccee3
--- /dev/null
+++ b/src/Orleans.Serialization.MemoryPack/SerializationHostingExtensions.cs
@@ -0,0 +1,92 @@
+using System;
+using MemoryPack;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
+using Orleans.Serialization.Cloning;
+using Orleans.Serialization.Serializers;
+using Orleans.Serialization.Utilities.Internal;
+
+namespace Orleans.Serialization;
+
+///
+/// Extension method for .
+///
+public static class SerializationHostingExtensions
+{
+ private static readonly ServiceDescriptor ServiceDescriptor = new(typeof(MemoryPackCodec), typeof(MemoryPackCodec));
+
+ ///
+ /// Adds support for serializing and deserializing values using .
+ ///
+ /// The serializer builder.
+ /// A delegate used to indicate which types should be serialized by this codec.
+ /// A delegate used to indicate which types should be copied by this codec.
+ /// The MemoryPack serializer options.
+ public static ISerializerBuilder AddMemoryPackSerializer(
+ this ISerializerBuilder serializerBuilder,
+ Func isSerializable = null,
+ Func isCopyable = null,
+ MemoryPackSerializerOptions memoryPackSerializerOptions = null)
+ {
+ return serializerBuilder.AddMemoryPackSerializer(
+ isSerializable,
+ isCopyable,
+ optionsBuilder => optionsBuilder.Configure(options =>
+ {
+ if (memoryPackSerializerOptions is not null)
+ {
+ options.SerializerOptions = memoryPackSerializerOptions;
+ }
+ })
+ );
+ }
+
+ ///
+ /// Adds support for serializing and deserializing values using .
+ ///
+ /// The serializer builder.
+ /// A delegate used to indicate which types should be serialized by this codec.
+ /// A delegate used to indicate which types should be copied by this codec.
+ /// A delegate used to configure the options for the MemoryPack codec.
+ public static ISerializerBuilder AddMemoryPackSerializer(
+ this ISerializerBuilder serializerBuilder,
+ Func isSerializable,
+ Func isCopyable,
+ Action> configureOptions = null)
+ {
+ var services = serializerBuilder.Services;
+ if (configureOptions != null)
+ {
+ configureOptions(services.AddOptions());
+ }
+
+ if (isSerializable != null)
+ {
+ services.AddSingleton(new DelegateCodecSelector
+ {
+ CodecName = MemoryPackCodec.WellKnownAlias,
+ IsSupportedTypeDelegate = isSerializable
+ });
+ }
+
+ if (isCopyable != null)
+ {
+ services.AddSingleton(new DelegateCopierSelector
+ {
+ CopierName = MemoryPackCodec.WellKnownAlias,
+ IsSupportedTypeDelegate = isCopyable
+ });
+ }
+
+ if (!services.Contains(ServiceDescriptor))
+ {
+ services.AddSingleton();
+ services.AddFromExisting();
+ services.AddFromExisting();
+ services.AddFromExisting();
+ serializerBuilder.Configure(options => options.WellKnownTypeAliases[MemoryPackCodec.WellKnownAlias] = typeof(MemoryPackCodec));
+ }
+
+ return serializerBuilder;
+ }
+}
diff --git a/src/api/Orleans.Serialization.MemoryPack/Orleans.Serialization.MemoryPack.cs b/src/api/Orleans.Serialization.MemoryPack/Orleans.Serialization.MemoryPack.cs
new file mode 100644
index 00000000000..55327288ab3
--- /dev/null
+++ b/src/api/Orleans.Serialization.MemoryPack/Orleans.Serialization.MemoryPack.cs
@@ -0,0 +1,45 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+namespace Orleans.Serialization
+{
+ [Alias("memorypack")]
+ public partial class MemoryPackCodec : Serializers.IGeneralizedCodec, Codecs.IFieldCodec, Cloning.IGeneralizedCopier, Cloning.IDeepCopier, ITypeFilter
+ {
+ public const string WellKnownAlias = "memorypack";
+ public MemoryPackCodec(System.Collections.Generic.IEnumerable serializableTypeSelectors, System.Collections.Generic.IEnumerable copyableTypeSelectors, Microsoft.Extensions.Options.IOptions options) { }
+
+ object Cloning.IDeepCopier.DeepCopy(object input, Cloning.CopyContext context) { throw null; }
+
+ bool Cloning.IGeneralizedCopier.IsSupportedType(System.Type type) { throw null; }
+
+ object Codecs.IFieldCodec.ReadValue(ref Buffers.Reader reader, WireProtocol.Field field) { throw null; }
+
+ void Codecs.IFieldCodec.WriteField(ref Buffers.Writer writer, uint fieldIdDelta, System.Type expectedType, object value) { }
+
+ bool? ITypeFilter.IsTypeAllowed(System.Type type) { throw null; }
+
+ bool Serializers.IGeneralizedCodec.IsSupportedType(System.Type type) { throw null; }
+ }
+
+ public partial class MemoryPackCodecOptions
+ {
+ public System.Func IsCopyableType { get { throw null; } set { } }
+
+ public System.Func IsSerializableType { get { throw null; } set { } }
+
+ public MemoryPack.MemoryPackSerializerOptions SerializerOptions { get { throw null; } set { } }
+ }
+
+ public static partial class SerializationHostingExtensions
+ {
+ public static ISerializerBuilder AddMemoryPackSerializer(this ISerializerBuilder serializerBuilder, System.Func isSerializable = null, System.Func isCopyable = null, MemoryPack.MemoryPackSerializerOptions memoryPackSerializerOptions = null) { throw null; }
+
+ public static ISerializerBuilder AddMemoryPackSerializer(this ISerializerBuilder serializerBuilder, System.Func isSerializable, System.Func isCopyable, System.Action> configureOptions = null) { throw null; }
+ }
+}
diff --git a/test/Orleans.Serialization.UnitTests/MemoryPackSerializerTests.cs b/test/Orleans.Serialization.UnitTests/MemoryPackSerializerTests.cs
new file mode 100644
index 00000000000..22b8c0585df
--- /dev/null
+++ b/test/Orleans.Serialization.UnitTests/MemoryPackSerializerTests.cs
@@ -0,0 +1,148 @@
+#nullable enable
+using System;
+using Microsoft.Extensions.DependencyInjection;
+using Orleans.Serialization.Cloning;
+using Orleans.Serialization.Codecs;
+using Orleans.Serialization.Serializers;
+using Orleans.Serialization.TestKit;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace Orleans.Serialization.UnitTests;
+
+///
+/// Tests for Orleans' MemoryPack serialization support.
+///
+/// MemoryPack is a binary serialization format that provides:
+/// - More compact representation than JSON
+/// - Faster serialization/deserialization than text formats
+/// - Cross-platform and cross-language support
+///
+/// Orleans' MemoryPack integration:
+/// - Leverages the MemoryPack-CSharp library
+/// - Supports union types (discriminated unions)
+/// - Provides both serialization and deep copy functionality
+/// - Can be used for specific types while using Orleans' native format for others
+///
+/// This is useful when:
+/// - Interoperating with systems that use MemoryPack
+/// - Requiring a compact binary format with broad language support
+/// - Needing better performance than JSON but more portability than Orleans' native format
+///
+[Trait("Category", "BVT")]
+public class MemoryPackCodecTests : FieldCodecTester>
+{
+ public MemoryPackCodecTests(ITestOutputHelper output) : base(output)
+ {
+ }
+
+ protected override void Configure(ISerializerBuilder builder)
+ {
+ builder.AddMemoryPackSerializer();
+ }
+
+ protected override MyMemoryPackClass? CreateValue() => new() { IntProperty = 30, StringProperty = "hello", SubClass = new() { Id = Guid.NewGuid() } };
+
+ protected override MyMemoryPackClass?[] TestValues => new MyMemoryPackClass?[]
+ {
+ null,
+ new() { SubClass = new() { Id = Guid.NewGuid() } },
+ new() { IntProperty = 150, StringProperty = new string('c', 20), SubClass = new() { Id = Guid.NewGuid() } },
+ new() { IntProperty = 150_000, StringProperty = new string('c', 6_000), SubClass = new() { Id = Guid.NewGuid() } },
+ new() { Union = new MyMemoryPackUnionVariant1 { IntProperty = 1 } },
+ new() { Union = new MyMemoryPackUnionVariant2 { StringProperty = "String" } },
+ };
+
+ [Fact]
+ public void MemoryPackSerializerDeepCopyTyped()
+ {
+ var original = new MyMemoryPackClass { IntProperty = 30, StringProperty = "hi", SubClass = new() { Id = Guid.NewGuid() } };
+ var copier = ServiceProvider.GetRequiredService>();
+ var result = copier.Copy(original);
+
+ Assert.Equal(original.IntProperty, result.IntProperty);
+ Assert.Equal(original.StringProperty, result.StringProperty);
+ Assert.Equal(original.SubClass.Id, result.SubClass.Id);
+ }
+
+ [Fact]
+ public void MemoryPackSerializerDeepCopyUntyped()
+ {
+ var original = new MyMemoryPackClass { IntProperty = 30, StringProperty = "hi", SubClass = new() { Id = Guid.NewGuid() } };
+ var copier = ServiceProvider.GetRequiredService();
+ var result = (MyMemoryPackClass)copier.Copy((object)original);
+
+ Assert.Equal(original.IntProperty, result.IntProperty);
+ Assert.Equal(original.StringProperty, result.StringProperty);
+ Assert.Equal(original.SubClass.Id, result.SubClass.Id);
+ }
+
+ [Fact]
+ public void MemoryPackSerializerRoundTripThroughCodec()
+ {
+ var original = new MyMemoryPackClass { IntProperty = 30, StringProperty = "hi", SubClass = new() { Id = Guid.NewGuid() } };
+ var result = RoundTripThroughCodec(original);
+
+ Assert.Equal(original.IntProperty, result.IntProperty);
+ Assert.Equal(original.StringProperty, result.StringProperty);
+ }
+
+ [Fact]
+ public void MemoryPackSerializerRoundTripThroughUntypedSerializer()
+ {
+ var original = new MyMemoryPackClass { IntProperty = 30, StringProperty = "hi", SubClass = new() { Id = Guid.NewGuid() } };
+ var untypedResult = RoundTripThroughUntypedSerializer(original, out _);
+
+ var result = Assert.IsType(untypedResult);
+ Assert.Equal(original.IntProperty, result.IntProperty);
+ Assert.Equal(original.StringProperty, result.StringProperty);
+ }
+}
+
+
+[Trait("Category", "BVT")]
+public class MemoryPackUnionCodecTests : FieldCodecTester>
+{
+ public MemoryPackUnionCodecTests(ITestOutputHelper output) : base(output)
+ {
+ }
+
+ protected override void Configure(ISerializerBuilder builder)
+ {
+ builder.AddMemoryPackSerializer();
+ }
+
+ protected override IMyMemoryPackUnion? CreateValue() => new MyMemoryPackUnionVariant1() { IntProperty = 30 };
+
+ protected override IMyMemoryPackUnion?[] TestValues => new IMyMemoryPackUnion?[]
+ {
+ null,
+ new MyMemoryPackUnionVariant1 { IntProperty = 1 },
+ new MyMemoryPackUnionVariant2 { StringProperty = "String" },
+ };
+}
+
+
+[Trait("Category", "BVT")]
+public class MemoryPackCodecCopierTests : CopierTester>
+{
+ public MemoryPackCodecCopierTests(ITestOutputHelper output) : base(output)
+ {
+ }
+
+ protected override void Configure(ISerializerBuilder builder)
+ {
+ builder.AddMemoryPackSerializer();
+ }
+ protected override IDeepCopier CreateCopier() => ServiceProvider.GetRequiredService().GetDeepCopier();
+
+ protected override MyMemoryPackClass? CreateValue() => new() { IntProperty = 30, StringProperty = "hello", SubClass = new() { Id = Guid.NewGuid() } };
+
+ protected override MyMemoryPackClass?[] TestValues => new MyMemoryPackClass?[]
+ {
+ null,
+ new() { SubClass = new() { Id = Guid.NewGuid() } },
+ new() { IntProperty = 150, StringProperty = new string('c', 20), SubClass = new() { Id = Guid.NewGuid() } },
+ new() { IntProperty = 150_000, StringProperty = new string('c', 6_000), SubClass = new() { Id = Guid.NewGuid() } },
+ };
+}
diff --git a/test/Orleans.Serialization.UnitTests/Models.cs b/test/Orleans.Serialization.UnitTests/Models.cs
index 723acc6badc..dbd1526d9ae 100644
--- a/test/Orleans.Serialization.UnitTests/Models.cs
+++ b/test/Orleans.Serialization.UnitTests/Models.cs
@@ -6,6 +6,7 @@
using System.Runtime.Serialization;
using System.Text.Json;
using System.Text.Json.Nodes;
+using MemoryPack;
using MessagePack;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
@@ -963,4 +964,41 @@ public sealed record MyMessagePackUnionVariant2 : IMyMessagePackUnion
[Key(0)]
public string StringProperty { get; init; }
}
+
+ [MemoryPackable]
+ public partial record MyMemoryPackClass
+ {
+ public int IntProperty { get; init; }
+
+ public string StringProperty { get; init; }
+
+ public MyMemoryPackSubClass SubClass { get; init; }
+
+ public IMyMemoryPackUnion Union { get; init; }
+ }
+
+ [MemoryPackable]
+ public partial record MyMemoryPackSubClass
+ {
+ public Guid Id { get; init; }
+ }
+
+ [MemoryPackable]
+ [MemoryPackUnion(0, typeof(MyMemoryPackUnionVariant1))]
+ [MemoryPackUnion(1, typeof(MyMemoryPackUnionVariant2))]
+ public partial interface IMyMemoryPackUnion
+ {
+ }
+
+ [MemoryPackable]
+ public partial record MyMemoryPackUnionVariant1 : IMyMemoryPackUnion
+ {
+ public int IntProperty { get; init; }
+ }
+
+ [MemoryPackable]
+ public partial record MyMemoryPackUnionVariant2 : IMyMemoryPackUnion
+ {
+ public string StringProperty { get; init; }
+ }
}
diff --git a/test/Orleans.Serialization.UnitTests/Orleans.Serialization.UnitTests.csproj b/test/Orleans.Serialization.UnitTests/Orleans.Serialization.UnitTests.csproj
index 4b4e67305af..5d04473c0a1 100644
--- a/test/Orleans.Serialization.UnitTests/Orleans.Serialization.UnitTests.csproj
+++ b/test/Orleans.Serialization.UnitTests/Orleans.Serialization.UnitTests.csproj
@@ -39,6 +39,7 @@
+