AArnott / Nerdbank.MessagePack

A .NET MessagePack serialization library with great performance and simplicity.
https://aarnott.github.io/Nerdbank.MessagePack/
MIT License
39 stars 1 forks source link

Sample/doc using System.IO.Stream #100

Closed joelverhagen closed 1 week ago

joelverhagen commented 1 week ago

I'm excited to see a new MessagePack library for .NET! I currently use the MessagePack package for NuGet/Insights for intermediate data serialization. I hope to switch over to your new project when I see feature parity.

I didn't see any sample on how to adapt serialization or deserialization for System.IO.Stream. I think that sample would be helpful since Stream is such a commonly used IO API in .NET.

AArnott commented 1 week ago

I'm delighted to hear of your interest. It's possible to work with streams today, either asynchronously or synchronously. Here is a sample:

[Fact]
public async Task SerializeWithStreamAsync()
{
    Person person = new("Andrew", "Arnott");

    using MemoryStream stream = new();
    PipeWriter pipeWriter = PipeWriter.Create(stream, new StreamPipeWriterOptions(leaveOpen: true));
    await this.Serializer.SerializeAsync(pipeWriter, person);
    await pipeWriter.CompleteAsync();

    stream.Position = 0;
    PipeReader pipeReader = PipeReader.Create(stream, new StreamPipeReaderOptions(leaveOpen: true));
    Person? deserialized = await this.Serializer.DeserializeAsync<Person>(pipeReader);

    Assert.Equal(person, deserialized);
}

[Fact]
public void SerializeWithStream()
{
    Person person = new("Andrew", "Arnott");

    using MemoryStream stream = new();
    stream.Write(this.Serializer.Serialize(person));

    stream.Position = 0;
    Person? deserialized = this.Serializer.Deserialize<Person>(stream.ToArray());
}

[GenerateShape]
public partial record Person(string FirstName, string LastName);

We can do better than this going forward in a couple ways:

  1. The async variety today suffers from much slower deserialization performance. That's something I hope to improve in the near future.
  2. The synchronous variety (in its simplest form as given above) allocates a contiguous buffer for the msgpack for interop with the Stream class. With another facade or two (possibly hidden in the library) we can make this more efficient so as to avoid any extra memory allocations.