Skip to content

Commit 6f13196

Browse files
authored
Update UserTypeMarshallingV2.md to match approved design (#72230)
1 parent e5a47d6 commit 6f13196

File tree

1 file changed

+42
-44
lines changed

1 file changed

+42
-44
lines changed

docs/design/libraries/LibraryImportGenerator/UserTypeMarshallingV2.md

Lines changed: 42 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -165,13 +165,13 @@ namespace System.Runtime.InteropServices.Marshalling;
165165
+ MarshalMode = marshalMode;
166166
+ MarshallerType = marshallerType;
167167
+ }
168-
+
168+
+
169169
+ public Type ManagedType { get; }
170-
+
170+
+
171171
+ public MarshalMode MarshalMode { get; }
172-
+
172+
+
173173
+ public Type MarshallerType { get; }
174-
+
174+
+
175175
+ /// <summary>
176176
+ /// Placeholder type for generic parameter
177177
+ /// </summary>
@@ -193,7 +193,7 @@ namespace System.Runtime.InteropServices.Marshalling;
193193

194194
First of all, this new design continues to use the existing policy for defining "blittable" types as described in the V1 design. The rest of this document will describe the custom user-defined marshalling rules.
195195

196-
In the new design, the user will first define an "entry-point type" that represents a marshalling concept. For example, if we are marshalling a `string` to a native UTF-8 encoded string, we might call the marshaller `Utf8StringMarshaller`. This new type will be a `static class`. The developer will then use the `ManagedToUnmanagedMarshallersAttribute`, `UnmanagedToManagedMarshallersAttribute`, and `ElementMarshallerAttribute` to specify which "marshaller implementation type" will be used to actually provide the marshalling. If an attribute is missing or a property on the attribute is set to `null` or left unset, this marshaller will not support marshalling in that scenario. A single type can be specified multiple times if it provides the marshalling support for multiple scenarios.
196+
In the new design, the user will first define an "entry-point type" that represents a marshalling concept. For example, if we are marshalling a `string` to a native UTF-8 encoded string, we might call the marshaller `Utf8StringMarshaller`. This entry-point type must be a `static class` or a `struct`. The developer will then use the `CustomMarshallerAttribute` to specify which "marshaller implementation type" will be used to actually provide the marshalling for a `MarshalMode`. If an attribute is missing or a property on the attribute is set to `null` or left unset, this marshaller will not support marshalling in that scenario. If the marshaller implementation type is considered stateless if it is a `static class` and stateful if it is a `struct`. A single type can be specified multiple times if it provides the marshalling support for multiple scenarios.
197197

198198
To avoid confusion around when each marshaller applies, we define when the marshallers apply based on the C# syntax used. This helps reduce the concept load as developers don't need to remember the mapping between the previous design's `CustomTypeMarshallerDirection` enum member and the C# keyword used for a parameter, which do not match in a Reverse P/Invoke-like scenario.
199199

@@ -220,8 +220,8 @@ The type `TNative` can be any `unmanaged` type. It represents whatever unmanaged
220220
### Stateless Managed->Unmanaged
221221

222222
```csharp
223-
[ManagedToUnmanagedMarshallers(typeof(TManaged<,,,...>), InMarshaller = typeof(ManagedToNative))]
224-
[UnmanagedToManagedMarshallers(typeof(TManaged<,,,...>), OutMarshaller = typeof(ManagedToNative))]
223+
[CustomMarshaller(typeof(TManaged<,,,...>), MarshalMode.ManagedToUnmanagedIn, typeof(ManagedToNative))]
224+
[CustomMarshaller(typeof(TManaged<,,,...>), MarshalMode.UnmanagedToManagedOut, typeof(ManagedToNative))]
225225
static class TMarshaller<T, U, V...>
226226
{
227227
public static class ManagedToNative
@@ -240,8 +240,8 @@ static class TMarshaller<T, U, V...>
240240
The element type of the `Span` for the caller-allocated buffer can be any type that guarantees any alignment requirements.
241241

242242
```csharp
243-
[ManagedToUnmanagedMarshallers(typeof(TManaged<,,,...>), InMarshaller = typeof(ManagedToNative))]
244-
[UnmanagedToManagedMarshallers(typeof(TManaged<,,,...>), OutMarshaller = typeof(ManagedToNative))]
243+
[CustomMarshaller(typeof(TManaged<,,,...>), MarshalMode.ManagedToUnmanagedIn, typeof(ManagedToNative))]
244+
[CustomMarshaller(typeof(TManaged<,,,...>), MarshalMode.UnmanagedToManagedOut, typeof(ManagedToNative))]
245245
static class TMarshaller<T, U, V...>
246246
{
247247
public static class ManagedToNative
@@ -258,8 +258,8 @@ static class TMarshaller<T, U, V...>
258258
### Stateless Unmanaged->Managed
259259

260260
```csharp
261-
[ManagedToUnmanagedMarshallers(typeof(TManaged<,,,...>), OutMarshaller = typeof(NativeToManaged))]
262-
[UnmanagedToManagedMarshallers(typeof(TManaged<,,,...>), InMarshaller = typeof(NativeToManaged))]
261+
[CustomMarshaller(typeof(TManaged<,,,...>), MarshalMode.ManagedToUnmanagedOut, typeof(NativeToManaged))]
262+
[CustomMarshaller(typeof(TManaged<,,,...>), MarshalMode.UnmanagedToManagedIn, typeof(NativeToManaged))]
263263
static class TMarshaller<T, U, V...>
264264
{
265265
public static class NativeToManaged
@@ -277,8 +277,8 @@ static class TMarshaller<T, U, V...>
277277
This shape directs the generator to emit the `ConvertToManagedFinally` call in the "GuaranteedUnmarshal" phase of marshalling.
278278

279279
```csharp
280-
[ManagedToUnmanagedMarshallers(typeof(TManaged<,,,...>), OutMarshaller = typeof(NativeToManaged))]
281-
[UnmanagedToManagedMarshallers(typeof(TManaged<,,,...>), InMarshaller = typeof(NativeToManaged))]
280+
[CustomMarshaller(typeof(TManaged<,,,...>), MarshalMode.ManagedToUnmanagedOut, typeof(NativeToManaged))]
281+
[CustomMarshaller(typeof(TManaged<,,,...>), MarshalMode.UnmanagedToManagedIn, typeof(NativeToManaged))]
282282
static class TMarshaller<T, U, V...>
283283
{
284284
public static class NativeToManaged
@@ -293,9 +293,9 @@ static class TMarshaller<T, U, V...>
293293

294294
### Stateless Bidirectional
295295
```csharp
296-
[ManagedToUnmanagedMarshallers(typeof(TManaged<,,,...>), RefMarshaller = typeof(Bidirectional))]
297-
[ManagedToUnmanagedMarshallers(typeof(TManaged<,,,...>), RefMarshaller = typeof(Bidirectional))]
298-
[ElementMarshaller(typeof(TManaged<,,,...>), typeof(Bidirectional))]
296+
[CustomMarshaller(typeof(TManaged<,,,...>), MarshalMode.ManagedToUnmanagedRef, typeof(Bidirectional))]
297+
[CustomMarshaller(typeof(TManaged<,,,...>), MarshalMode.UnmanagedToManagedRef, typeof(Bidirectional))]
298+
[CustomMarshaller(typeof(TManaged<,,,...>), MarshalMode.ElementRef, typeof(Bidirectional))]
299299
static class TMarshaller<T, U, V...>
300300
{
301301
public static class Bidirectional
@@ -311,8 +311,8 @@ static class TMarshaller<T, U, V...>
311311
### Stateful Managed->Unmanaged
312312

313313
```csharp
314-
[ManagedToUnmanagedMarshallers(typeof(TManaged<,,,...>), InMarshaller = typeof(ManagedToNative))]
315-
[UnmanagedToManagedMarshallers(typeof(TManaged<,,,...>), OutMarshaller = typeof(ManagedToNative))]
314+
[CustomMarshaller(typeof(TManaged<,,,...>), MarshalMode.ManagedToUnmanagedIn, typeof(ManagedToNative))]
315+
[CustomMarshaller(typeof(TManaged<,,,...>), MarshalMode.UnmanagedToManagedOut, typeof(ManagedToNative))]
316316
static class TMarshaller<T, U, V...>
317317
{
318318
public struct ManagedToNative // Can be ref struct
@@ -339,8 +339,8 @@ static class TMarshaller<T, U, V...>
339339
The element type of the `Span` for the caller-allocated buffer can be any type that guarantees any alignment requirements.
340340

341341
```csharp
342-
[ManagedToUnmanagedMarshallers(typeof(TManaged<,,,...>), InMarshaller = typeof(ManagedToNative))]
343-
[UnmanagedToManagedMarshallers(typeof(TManaged<,,,...>), OutMarshaller = typeof(ManagedToNative))]
342+
[CustomMarshaller(typeof(TManaged<,,,...>), MarshalMode.ManagedToUnmanagedIn, typeof(ManagedToNative))]
343+
[CustomMarshaller(typeof(TManaged<,,,...>), MarshalMode.UnmanagedToManagedOut, typeof(ManagedToNative))]
344344
static class TMarshaller<T, U, V...>
345345
{
346346
public struct ManagedToNative // Can be ref struct
@@ -367,15 +367,15 @@ static class TMarshaller<T, U, V...>
367367
### Stateful Unmanaged->Managed
368368

369369
```csharp
370-
[ManagedToUnmanagedMarshallers(typeof(TManaged<,,,...>), OutMarshaller = typeof(NativeToManaged))]
371-
[UnmanagedToManagedMarshallers(typeof(TManaged<,,,...>), InMarshaller = typeof(NativeToManaged))]
370+
[CustomMarshaller(typeof(TManaged<,,,...>), MarshalMode.ManagedToUnmanagedOut, typeof(NativeToManaged))]
371+
[CustomMarshaller(typeof(TManaged<,,,...>), MarshalMode.UnmanagedToManagedIn, typeof(NativeToManaged))]
372372
static class TMarshaller<T, U, V...>
373373
{
374374
public struct NativeToManaged // Can be ref struct
375375
{
376376
public NativeToManaged(); // Optional, can throw exceptions.
377377
378-
public void FromUnmanaged(TNative native); // Should not throw exceptions.
378+
public void FromUnmanaged(TNative unmanaged); // Should not throw exceptions.
379379
380380
public TManaged ToManaged(); // Can throw exceptions.
381381
@@ -388,15 +388,15 @@ static class TMarshaller<T, U, V...>
388388
### Stateful Unmanaged->Managed with Guaranteed Unmarshalling
389389

390390
```csharp
391-
[ManagedToUnmanagedMarshallers(typeof(TManaged<,,,...>), OutMarshaller = typeof(NativeToManaged))]
392-
[UnmanagedToManagedMarshallers(typeof(TManaged<,,,...>), InMarshaller = typeof(NativeToManaged))]
391+
[CustomMarshaller(typeof(TManaged<,,,...>), MarshalMode.ManagedToUnmanagedOut, typeof(NativeToManaged))]
392+
[CustomMarshaller(typeof(TManaged<,,,...>), MarshalMode.UnmanagedToManagedIn, typeof(NativeToManaged))]
393393
static class TMarshaller<T, U, V...>
394394
{
395395
public struct NativeToManaged // Can be ref struct
396396
{
397397
public NativeToManaged(); // Optional, can throw exceptions.
398398
399-
public void FromUnmanaged(TNative native); // Should not throw exceptions.
399+
public void FromUnmanaged(TNative unmanaged); // Should not throw exceptions.
400400
401401
public TManaged ToManagedFinally(); // Should not throw exceptions.
402402
@@ -408,8 +408,8 @@ static class TMarshaller<T, U, V...>
408408

409409
### Stateful Bidirectional
410410
```csharp
411-
[ManagedToUnmanagedMarshallers(typeof(TManaged<,,,...>), RefMarshaller = typeof(Bidirectional))]
412-
[ManagedToUnmanagedMarshallers(typeof(TManaged<,,,...>), RefMarshaller = typeof(Bidirectional))]
411+
[CustomMarshaller(typeof(TManaged<,,,...>), MarshalMode.ManagedToUnmanagedRef, typeof(Bidirectional))]
412+
[CustomMarshaller(typeof(TManaged<,,,...>), MarshalMode.UnmanagedToManagedRef, typeof(Bidirectional))]
413413
static class TMarshaller<T, U, V...>
414414
{
415415
public struct Bidirectional // Can be ref struct
@@ -423,7 +423,7 @@ static class TMarshaller<T, U, V...>
423423

424424
## Linear (Array-like) Collection Marshaller Shapes
425425

426-
We'll continue with the collection marshaller shapes. These marshaller shapes support marshalling the structure of a collection of values, where the values themselves are marshalled with marshallers of their own (using the marshaller provided in the `ElementMarshallerAttribute`). This construction allows us to compose our marshallers and to easily support arrays of custom types without needing to implement a separate marshaller for each element type.
426+
We'll continue with the collection marshaller shapes. These marshaller shapes support marshalling the structure of a collection of values, where the values themselves are marshalled with marshallers of their own (using the marshaller provided for `MarshalMode.Element*`). This construction allows us to compose our marshallers and to easily support arrays of custom types without needing to implement a separate marshaller for each element type.
427427

428428
Each of these shapes will support marshalling the following type:
429429

@@ -502,13 +502,13 @@ static class TMarshaller<T, U, V..., TUnmanagedElement> where TUnmanagedElement
502502
{
503503
public static class NativeToManaged
504504
{
505-
public static TCollection AllocateContainerForManagedElements(TNative unmanaged, int length); // Can throw exceptions
505+
public static TCollection AllocateContainerForManagedElements(TNative unmanaged, int numElements); // Can throw exceptions
506506
507-
public static Span<TManagedElement> GetManagedValuesDestination(T[] managed) => managed; // Can throw exceptions
507+
public static Span<TManagedElement> GetManagedValuesDestination(TCollection managed) => managed; // Can throw exceptions
508508
509509
public static ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(TNative unmanaged, int numElements); // Can throw exceptions
510510
511-
public static void Free(TNative native); // Optional. Should not throw exceptions.
511+
public static void Free(TNative unmanaged); // Optional. Should not throw exceptions.
512512
}
513513
}
514514

@@ -525,13 +525,13 @@ static class TMarshaller<T, U, V..., TUnmanagedElement> where TUnmanagedElement
525525
{
526526
public static class NativeToManaged
527527
{
528-
public static TCollection AllocateContainerForManagedElementsFinally(TNative unmanaged, int length); // Should not throw exceptions other than OutOfMemoryException.
528+
public static TCollection AllocateContainerForManagedElementsFinally(TNative unmanaged, int numElements); // Should not throw exceptions other than OutOfMemoryException.
529529
530-
public static Span<TManagedElement> GetManagedValuesDestination(T[] managed) => managed; // Can throw exceptions
530+
public static Span<TManagedElement> GetManagedValuesDestination(TCollection managed) => managed; // Can throw exceptions
531531
532532
public static ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(TNative unmanaged, int numElements); // Can throw exceptions
533533
534-
public static void Free(TNative native); // Optional. Should not throw exceptions.
534+
public static void Free(TNative unmanaged); // Optional. Should not throw exceptions.
535535
}
536536
}
537537

@@ -571,7 +571,7 @@ static class TMarshaller<T, U, V..., TUnmanagedElement> where TUnmanagedElement
571571
572572
public ReadOnlySpan<TManagedElement> GetManagedValuesSource(); // Can throw exceptions.
573573
574-
public Span<byte> GetUnmanagedValuesDestination(); // Can throw exceptions.
574+
public Span<TUnmanagedElement> GetUnmanagedValuesDestination(); // Can throw exceptions.
575575
576576
public ref TIgnored GetPinnableReference(); // Optional. Can throw exceptions.
577577
@@ -603,7 +603,7 @@ static class TMarshaller<T, U, V..., TUnmanagedElement> where TUnmanagedElement
603603
604604
public ReadOnlySpan<TManagedElement> GetManagedValuesSource(); // Can throw exceptions.
605605
606-
public Span<byte> GetUnmanagedValuesDestination(); // Can throw exceptions.
606+
public Span<TUnmanagedElement> GetUnmanagedValuesDestination(); // Can throw exceptions.
607607
608608
public ref TIgnored GetPinnableReference(); // Optional. Can throw exceptions.
609609
@@ -631,9 +631,9 @@ static class TMarshaller<T, U, V..., TUnmanagedElement> where TUnmanagedElement
631631
632632
public void FromUnmanaged(TNative value); // Should not throw exceptions.
633633
634-
public ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(int length); // Can throw exceptions.
634+
public ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(int numElements); // Can throw exceptions.
635635
636-
public Span<TManagedElement> GetManagedValuesDestination(int length); // Can throw exceptions.
636+
public Span<TManagedElement> GetManagedValuesDestination(int numElements); // Can throw exceptions.
637637
638638
public TCollection ToManaged(); // Can throw exceptions
639639
@@ -656,9 +656,9 @@ static class TMarshaller<T, U, V..., TUnmanagedElement> where TUnmanagedElement
656656
657657
public void FromUnmanaged(TNative value); // Should not throw exceptions.
658658
659-
public ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(int length); // Can throw exceptions.
659+
public ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(int numElements); // Can throw exceptions.
660660
661-
public Span<TManagedElement> GetManagedValuesDestination(int length); // Can throw exceptions.
661+
public Span<TManagedElement> GetManagedValuesDestination(int numElements); // Can throw exceptions.
662662
663663
public TCollection ToManagedFinally(); // Can throw exceptions
664664
@@ -738,9 +738,7 @@ struct HResult
738738
private int hr;
739739
}
740740

741-
[ManagedToUnmanagedMarshallers(typeof(HResult), InMarshaller = typeof(HResultMarshaller), RefMarshaller = typeof(HResultMarshaller), OutMarshaller = typeof(HResultMarshaller))]
742-
[UnmanagedToManagedMarshallers(typeof(HResult), InMarshaller = typeof(HResultMarshaller), RefMarshaller = typeof(HResultMarshaller), OutMarshaller = typeof(HResultMarshaller))]
743-
[ElementMarshaller(typeof(HResult), typeof(HResultMarshaller))]
741+
[CustomMarshaller(typeof(HResult), MarshalMode.Default, typeof(HResultMarshaller))]
744742
public static class HResultMarshaller
745743
{
746744
public static int ConvertToUnmanaged(HResult hr);

0 commit comments

Comments
 (0)