From 40b489c160fc8ef65626ac17201e7bf7fd985184 Mon Sep 17 00:00:00 2001 From: Sammo Gabay Date: Tue, 3 Jun 2025 03:16:12 -0400 Subject: [PATCH] [.NET] Prefer spans of handles over plain ints where possible Uses the P/Invoke source generation in conjunction with the custom CanteraHandler marshaller, to marshal arrays, not just scalars, of the typed handle classes. --- .../dotnet/Cantera/src/Interop/CanteraHandle.cs | 6 ++---- .../sourcegen/src/sourcegen/csharp/config.yaml | 6 ++++++ .../sourcegen/src/sourcegen/csharp/generator.py | 13 ++++++++++++- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/interfaces/dotnet/Cantera/src/Interop/CanteraHandle.cs b/interfaces/dotnet/Cantera/src/Interop/CanteraHandle.cs index 25cb202bf..d9d3df978 100644 --- a/interfaces/dotnet/Cantera/src/Interop/CanteraHandle.cs +++ b/interfaces/dotnet/Cantera/src/Interop/CanteraHandle.cs @@ -46,10 +46,8 @@ abstract class CanteraHandle : IDisposable public sealed override string ToString() => $"{GetType().Name} {{{_value}}}"; - [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder), MarshalMode.ManagedToUnmanagedIn, - typeof(Marshaller<>))] - [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder), MarshalMode.ManagedToUnmanagedOut, - typeof(Marshaller<>))] + [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder), + MarshalMode.Default, typeof(Marshaller<>))] public static class Marshaller where T : CanteraHandle, new() { public static int ConvertToUnmanaged(T handle) diff --git a/interfaces/sourcegen/src/sourcegen/csharp/config.yaml b/interfaces/sourcegen/src/sourcegen/csharp/config.yaml index 3d6804e5e..629563705 100644 --- a/interfaces/sourcegen/src/sourcegen/csharp/config.yaml +++ b/interfaces/sourcegen/src/sourcegen/csharp/config.yaml @@ -68,6 +68,12 @@ class_accessors: kin_parent: SolutionHandle trans_parent: SolutionHandle +# Functions that are typed to take an array of ints, but are really +# supposed to take an array of handles +handle_array_takers: + sol_newInterface: SolutionHandle + reactornet_new: ReactorHandle + # Handles for which there is no special delete function, # so we need to generate them manually because we can't # discover the type name from the delete. diff --git a/interfaces/sourcegen/src/sourcegen/csharp/generator.py b/interfaces/sourcegen/src/sourcegen/csharp/generator.py index 5cdb5406d..de2b917cf 100644 --- a/interfaces/sourcegen/src/sourcegen/csharp/generator.py +++ b/interfaces/sourcegen/src/sourcegen/csharp/generator.py @@ -33,6 +33,8 @@ class Config: class_accessors: dict[str, str] + handle_array_takers: dict[str, str] + derived_handles: dict[str, str] wrapper_classes: dict[str, dict[str, str]] @@ -172,8 +174,17 @@ class CSharpSourceGenerator(SourceGenerator): ret_type = crosswalk(ret_type) + handle_array_type = self._config.handle_array_takers.get(name) + for i, param in enumerate(params): param_type = crosswalk(param.p_type) + if handle_array_type and param_type.endswith("Span"): + # There is a slight inconsistency in CLib in that sometimes + # the collection of handles will be marked as const and sometimes not. + # However, is it never modified, so we can always use a ReadOnlySpan. + # When this inconsistency is removed, the above can become + # param_type == "ReadOnlySpan" + param_type = f"ReadOnlySpan<{handle_array_type}>" params[i] = Param(param_type, param.name, param.description, param.direction, param.default, param.base) @@ -225,7 +236,7 @@ class CSharpSourceGenerator(SourceGenerator): span_param_name=func.arglist[-1].name) for func in cs_funcs if func.gets_string()) - # Add wrappers for functions that get or set arrays of doubles. + # Add wrappers for functions that get or set arrays. def transform_to_span_func(func: CsFunc) -> CsFunc: arglist = ArgList([*func.arglist[:-2], func.arglist[-1]]) return CsFunc('void', func.name, arglist, False, None)