Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Proper way to get a mutable struct for Memory<byte> / Span<byte>?

For a network protocol implementation I want to make use of the new Memory and Span classes to achieve zero-copy of the buffer while accessing the data through a struct.

I have the following contrived example:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct Data
{
    public int IntValue;
    public short ShortValue;
    public byte ByteValue;
}

static void Prepare()
{
    var buffer = new byte[1024];
    var dSpan = MemoryMarshal.Cast<byte, Data>(buffer);
    ref var d = ref dSpan[0];

    d.ByteValue = 1;
    d.ShortValue = (2 << 8) + 3;
    d.IntValue = (4 << 24) + (5 << 16) + (6 << 8) + 7;
}

The result is that buffer is filled with 7, 6, 5, 4, 3, 2, 1, which is as desired, but I can hardly imagine that MemoryMarshal.Cast is the only way (bar anything requiring the unsafe keyword) to do this. I tried some other methods, but I can't figure out how to use them with either a ref struct (which can't be used as generic type argument) or how to get a struct that's in the actual buffer and not a copy (on which any mutations made are not reflected in the buffer).

Is there a some easier way to get this mutable struct from the buffer?

like image 847
mycroes Avatar asked May 26 '18 20:05

mycroes


1 Answers

Oof. It looks like MemoryMarshal.Cast is what used to be the NonPortableCast extension method (from: this commit), in which case - yes, that's the appropriate way to thunk between layouts of spans, most commonly (but not exclusively) like in this case - between byte and some struct.

like image 83
Marc Gravell Avatar answered Sep 28 '22 17:09

Marc Gravell