Rai
Rai
CC#
Created by Rai on 9/17/2024 in #help
MemoryMarshal.Cast on a struct with array of known fixed size
I'm wondering if there is some way to marshal a byte array into a struct that is known to be of fixed size, or has known length values via other fields:
using System.Runtime.InteropServices;
using System.Text.Json;

Span<byte> buffer = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
Console.WriteLine(buffer.Length == Marshal.SizeOf<TestStruct>());
var tstruct = MemoryMarshal.Cast<byte, TestStruct>(buffer)[0];
Console.WriteLine(JsonSerializer.Serialize(tstruct));
Console.WriteLine(tstruct.b);

[StructLayout(LayoutKind.Explicit, Size = 20)]
public struct TestStruct
{
[FieldOffset(0)] [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I4, SizeConst = 4)]
public int[] arr;

[FieldOffset(16)] [MarshalAs(UnmanagedType.I4)]
public int b;
}
using System.Runtime.InteropServices;
using System.Text.Json;

Span<byte> buffer = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
Console.WriteLine(buffer.Length == Marshal.SizeOf<TestStruct>());
var tstruct = MemoryMarshal.Cast<byte, TestStruct>(buffer)[0];
Console.WriteLine(JsonSerializer.Serialize(tstruct));
Console.WriteLine(tstruct.b);

[StructLayout(LayoutKind.Explicit, Size = 20)]
public struct TestStruct
{
[FieldOffset(0)] [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I4, SizeConst = 4)]
public int[] arr;

[FieldOffset(16)] [MarshalAs(UnmanagedType.I4)]
public int b;
}
Althought due to MarshalAs it should be known that it's up to 4 elements this wouldn't work due to the array being recognized as a pointer/reference type. Is there a way to do this without having to enable unsafe and abuse the fixed keyword?
5 replies
CC#
Created by Rai on 8/7/2024 in #help
SourceGenerator multiple steps (passing data from one to another)
Is there some way, possibly even documented way, to get let's say an attribute name in one SyntaxProvider Collection and do something with that in another one. As of now I haven't found a way to make this work, as manually calling Collect and Select outside of RegisterSourceOutput results in the local variables being used as temp storage to transport these values between steps to have these values but only as long as they are inside the lambda scope of the Select method, the moment it's outside any change to local variables is lost. Even attempts such as using static fields will not provide a working solution, nor playing around with passing the IncrementalValueProvider around to each and every step doesn't seem to be a possible solution. Furthermore there doesn't seem to any documented examples of this when looking at the dotnet provided examples at: https://github.com/dotnet/roslyn-sdk/tree/main/samples/CSharp/SourceGenerators/SourceGeneratorSamples e.g code along the lines of.:
var attrProvider = attributeProvider.Collect();
attrProvider .Select((array, token) =>
{
attribute = array.First();
return array;
}
);
var classProvider = context.SyntaxProvider.CreateSyntaxProvider(
predicate: (node, _) => node is ClassDeclarationSyntax,
transform: (ctx, _) => GetTypesHavingAttribute(ctx, attribute)
)
.Where(m => m is not null);
var attrProvider = attributeProvider.Collect();
attrProvider .Select((array, token) =>
{
attribute = array.First();
return array;
}
);
var classProvider = context.SyntaxProvider.CreateSyntaxProvider(
predicate: (node, _) => node is ClassDeclarationSyntax,
transform: (ctx, _) => GetTypesHavingAttribute(ctx, attribute)
)
.Where(m => m is not null);
If reasoning may be required: I require to retrieve all attributes that inherit from a generic attribute in order to properly seperate if necessary the later on fetched classes in to their respective groups. Furthermore these provided attributes contain necessary metadata, which are required for the generation of the necessary code.
13 replies