Skip to content

[API Proposal] Create ReadOnlySpanMarshaller<T, TUnmanaged>.ManagedToUnmanagedOut marshaller #101136

@jtschuster

Description

@jtschuster

Background and motivation

To address #96525, we can provide a marshaller for ReadOnlySpan<T> for ManagedToUnmanagedOut direction. We have marshallers for UnmanagedToManagedOut and ManagedToUnmanagedIn. This API wasn't created previously due to the assumption that the managed ReadOnlySpan<T> would need to be written to in generated marshaling code, but that isn't strictly necessary for stateful marshallers. This API would allow LibraryImport methods to return ReadOnlySpan<T> without creating a new marshaller or specifying the marshaller type in the method definition.

API Proposal

  [System.Runtime.InteropServices.Marshalling.ContiguousCollectionMarshallerAttribute]
  [System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute(typeof(System.ReadOnlySpan<>), System.Runtime.InteropServices.Marshalling.MarshalMode.ManagedToUnmanagedIn, typeof(System.Runtime.InteropServices.Marshalling.ReadOnlySpanMarshaller<,>.ManagedToUnmanagedIn))]
+ [System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute(typeof(System.ReadOnlySpan<>), System.Runtime.InteropServices.Marshalling.MarshalMode.ManagedToUnmanagedOut, typeof(System.Runtime.InteropServices.Marshalling.ReadOnlySpanMarshaller<,>.ManagedToUnmanagedOut))]
  [System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute(typeof(System.ReadOnlySpan<>), System.Runtime.InteropServices.Marshalling.MarshalMode.UnmanagedToManagedOut, typeof(System.Runtime.InteropServices.Marshalling.ReadOnlySpanMarshaller<,>.UnmanagedToManagedOut))]
  public static unsafe class ReadOnlySpanMarshaller<T, TUnmanagedElement> where TUnmanagedElement : unmanaged
  {
+     public struct ManagedToUnmanagedOut
+     {
+         public void FromUnmanaged(TUnmanagedElement* unmanaged) { }
+         public ReadOnlySpan<T> ToManaged() { }
+         public ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(int numElements) { }
+         public Span<T> GetManagedValuesDestination(int numElements) { }
+         public void Free() { }
+     }
}

API Usage

The API would primarily be used in code generated by the LibraryImport generator to unmarshal a native array into a managed ReadOnlySpan<T> when a method returns a ReadOnlySpan<T> or has an out parameter of type ReadOnlySpan<T>.

[LibraryImport("DllName")]
[return: MarshalUsing(CountElementName = nameof(length))]
public static partial ReadOnlySpan<int> GetRange(int start, int end, out int length);

Alternative Designs

A workaround is to create a LibraryImport that returns another built-in collection type and create a wrapper that converts the returned collection into a ReadOnlySpan<T>, or use hand-written marshalling for the method.

Risk

Minimal. We already provide marshallers for ReadOnlySpan<T> to pass a parameter in, and we have marshallers for other collections to return a value from a native method, so this is not introducing a new concept.

Metadata

Metadata

Assignees

Labels

api-approvedAPI was approved in API review, it can be implementedarea-System.Runtime.InteropServicesblockingMarks issues that we want to fast track in order to unblock other important work

Type

No type

Projects

Status

No status

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions