@@ -13,29 +13,121 @@ public class MethodDetailsCache
1313 public string RawName ;
1414 public string [ ] InputParameterNames ;
1515 public Tuple < TypeReference , InputKind > [ ] InputParameterTypes ;
16- public TypeReference [ ] OutTypes ;
17- public string WrapperBody ;
16+ public Tuple < TypeReference , bool > [ ] OutTypes ;
17+ public string GetManyParameterName ;
18+ public List < Tuple < string , TypeReference , bool > > Output ;
1819
1920 public string [ ] MakeInputParameters ( Generator generator , ITypeRequestSource source )
2021 {
2122 return InputParameterNames . Zip ( InputParameterTypes , ( name , t ) => name + ": " + TypeHelpers . GetInputTypeName ( generator , source , t . Item1 , t . Item2 ) ) . ToArray ( ) ;
2223 }
2324
24- public string MakeOutType ( Generator generator , ITypeRequestSource source )
25+ public string MakeOutType ( Generator generator , ITypeRequestSource source , bool isFactoryMethod )
2526 {
26- string outType = String . Join ( ", " , OutTypes . Select ( o => TypeHelpers . GetTypeName ( generator , source , o , TypeUsage . Out ) ) ) ;
27+ string outType = String . Join ( ", " , OutTypes . Select ( o => TypeHelpers . GetTypeName ( generator , source , o . Item1 , ( o . Item2 || isFactoryMethod ) ? TypeUsage . OutNonNull : TypeUsage . Out ) ) ) ;
2728 if ( OutTypes . Count ( ) != 1 )
2829 {
2930 outType = "(" + outType + ")" ; // also works for count == 0 (empty tuple)
3031 }
3132 return outType ;
3233 }
34+
35+ public string MakeWrapperBody ( MethodDefinition def , bool isFactoryMethod )
36+ {
37+ var rawName = RawName ;
38+ bool isGetMany = GetManyParameterName != null ;
39+ var getManyPname = GetManyParameterName ;
40+ var output = Output ;
41+
42+ var rawParams = new List < string > { "self as *const _ as *mut _" } ;
43+ foreach ( var p in def . Parameters )
44+ {
45+ var pname = NameHelpers . PreventKeywords ( NameHelpers . FirstToLower ( p . Name ) ) ;
46+ if ( p . ParameterType . IsByReference )
47+ {
48+ if ( ( ( ByReferenceType ) p . ParameterType ) . ElementType . IsArray )
49+ {
50+ rawParams . Add ( "&mut " + pname + "Size" ) ;
51+ }
52+
53+ // output parameter
54+ rawParams . Add ( "&mut " + pname ) ;
55+ }
56+ else
57+ {
58+ // input parameter
59+ if ( p . ParameterType . IsArray )
60+ {
61+ if ( p . IsOut )
62+ {
63+ if ( isGetMany )
64+ {
65+ rawParams . Add ( pname + ".capacity() as u32" ) ;
66+ rawParams . Add ( pname + ".as_mut_ptr() as *mut T::Abi" ) ;
67+ }
68+ else
69+ {
70+ rawParams . Add ( pname + ".len() as u32" ) ;
71+ rawParams . Add ( pname + ".as_mut_ptr() as *mut _" ) ;
72+ }
73+ }
74+ else
75+ {
76+ rawParams . Add ( pname + ".len() as u32" ) ;
77+ rawParams . Add ( pname + ".as_ptr() as *mut _" ) ;
78+ }
79+ }
80+ else
81+ {
82+ rawParams . Add ( TypeHelpers . UnwrapInputParameter ( pname , p . ParameterType ) ) ;
83+ }
84+ }
85+ }
86+
87+ if ( def . ReturnType . FullName != "System.Void" )
88+ {
89+ if ( def . ReturnType . IsArray )
90+ {
91+ rawParams . Add ( "&mut outSize" ) ;
92+ }
93+ rawParams . Add ( "&mut out" ) ;
94+ }
95+
96+ var outInit = String . Join ( " " , output . SelectMany ( o => TypeHelpers . CreateUninitializedOutputs ( o . Item1 , o . Item2 ) ) ) ;
97+ if ( outInit != "" ) outInit = "\r \n " + outInit ;
98+
99+ var outWrap = String . Join ( ", " , output . Select ( o => TypeHelpers . WrapOutputParameter ( o . Item1 , o . Item2 , isFactoryMethod || o . Item3 ) ) ) ;
100+ if ( output . Count != 1 )
101+ {
102+ outWrap = "(" + outWrap + ")" ; // also works for count == 0 (empty tuple)
103+ }
104+ outWrap = "Ok(" + outWrap + ")" ;
105+
106+ if ( isGetMany )
107+ {
108+ outInit = $ "\r \n debug_assert!({ getManyPname } .capacity() > 0, \" capacity of `{ getManyPname } ` must not be 0 (use Vec::with_capacity)\" ); { getManyPname } .clear();{ outInit } ";
109+ outWrap = $ "{ getManyPname } .set_len(out as usize); Ok(())";
110+ }
111+
112+ return outInit + $@ "
113+ let hr = ((*self.lpVtbl).{ rawName } )({ String . Join ( ", " , rawParams ) } );
114+ if hr == S_OK {{ { outWrap } }} else {{ err(hr) }}" ;
115+ }
33116 }
34117
35118 public class MethodDef : ITypeRequestSource
36119 {
37120 public TypeDef DeclaringType { get ; private set ; }
38121 public MethodDefinition Method { get ; private set ; }
122+ public bool IsFactoryMethod
123+ {
124+ get
125+ {
126+ var kind = ( ( InterfaceDef ) DeclaringType ) . InterfaceKind ;
127+ if ( kind == InterfaceKind . Unidentified ) { throw new InvalidOperationException ( ) ; }
128+ return kind == InterfaceKind . Factory ;
129+ }
130+ }
39131
40132 public Module Module
41133 {
@@ -120,10 +212,10 @@ public string GetWrapperName(string rawName)
120212 public string GetWrapperDefinition ( )
121213 {
122214 var inputParameters = Details . MakeInputParameters ( DeclaringType . Generator , this ) ;
123- var outType = Details . MakeOutType ( DeclaringType . Generator , this ) ;
215+ var outType = Details . MakeOutType ( DeclaringType . Generator , this , IsFactoryMethod ) ;
124216
125- return $@ "#[inline] pub unsafe fn { Details . WrappedName } ({ String . Join ( ", " , new string [ ] { "&self" } . Concat ( inputParameters ) ) } ) -> Result<{ outType } > {{{ Details.WrapperBody }
126- }}" ;
217+ return $@ "#[inline] pub fn { Details . WrappedName } ({ String . Join ( ", " , new string [ ] { "&self" } . Concat ( inputParameters ) ) } ) -> Result<{ outType } > {{ unsafe {{ { Details . MakeWrapperBody ( Method , IsFactoryMethod ) }
218+ }}}} " ;
127219 }
128220
129221 private MethodDetailsCache InitializeDetailsCache ( )
@@ -139,7 +231,7 @@ private MethodDetailsCache InitializeDetailsCache()
139231 // It uses the __RPC__out_ecount_part(capacity, *actual) annotation in the C headers. For the wrapper we use a &mut Vec<> buffer.
140232
141233 var input = new List < Tuple < string , TypeReference , InputKind > > ( ) ;
142- var output = new List < Tuple < string , TypeReference > > ( ) ;
234+ var output = new List < Tuple < string , TypeReference , bool > > ( ) ;
143235
144236 foreach ( var p in Method . Parameters )
145237 {
@@ -148,7 +240,7 @@ private MethodDetailsCache InitializeDetailsCache()
148240 {
149241 Assert ( p . IsOut ) ;
150242 var realType = ( ( ByReferenceType ) p . ParameterType ) . ElementType ;
151- output . Add ( Tuple . Create ( pname , realType ) ) ;
243+ output . Add ( Tuple . Create ( pname , realType , false ) ) ;
152244 }
153245 else
154246 {
@@ -182,17 +274,18 @@ private MethodDetailsCache InitializeDetailsCache()
182274 if ( Method . ReturnType . FullName != "System.Void" )
183275 {
184276 // this makes the actual return value the last in the tuple (if multiple)
185- output . Add ( Tuple . Create ( "out" , Method . ReturnType ) ) ;
277+ output . Add ( Tuple . Create ( "out" , Method . ReturnType , TypeHelpers . IsReturnTypeNonNull ( Method . ReturnType , DeclaringType . Generator ) ) ) ;
186278 }
187279
188- var outTypes = output . Select ( o => o . Item2 ) . ToArray ( ) ;
280+ // TODO: second tuple element should be true for some method's return value
281+ var outTypes = output . Select ( o => Tuple . Create ( o . Item2 , o . Item3 ) ) . ToArray ( ) ;
189282
190283 if ( isGetMany )
191284 {
192- outTypes = new TypeReference [ ] { } ; // GetMany has no return value
285+ outTypes = new Tuple < TypeReference , bool > [ ] { } ; // GetMany has no return value
193286 }
194287
195-
288+
196289
197290 return new MethodDetailsCache
198291 {
@@ -201,87 +294,11 @@ private MethodDetailsCache InitializeDetailsCache()
201294 InputParameterNames = input . Select ( i => i . Item1 ) . ToArray ( ) ,
202295 InputParameterTypes = input . Select ( i => Tuple . Create ( i . Item2 , i . Item3 ) ) . ToArray ( ) ,
203296 OutTypes = outTypes . ToArray ( ) ,
204- WrapperBody = GetWrapperBody ( rawName , isGetMany , getManyPname , output )
297+ GetManyParameterName = isGetMany ? getManyPname : null ,
298+ Output = output
205299 } ;
206300 }
207301
208- private string GetWrapperBody ( string rawName , bool isGetMany , string getManyPname , List < Tuple < string , TypeReference > > output )
209- {
210- var rawParams = new List < string > { "self as *const _ as *mut _" } ;
211- foreach ( var p in Method . Parameters )
212- {
213- var pname = NameHelpers . PreventKeywords ( NameHelpers . FirstToLower ( p . Name ) ) ;
214- if ( p . ParameterType . IsByReference )
215- {
216- if ( ( ( ByReferenceType ) p . ParameterType ) . ElementType . IsArray )
217- {
218- rawParams . Add ( "&mut " + pname + "Size" ) ;
219- }
220-
221- // output parameter
222- rawParams . Add ( "&mut " + pname ) ;
223- }
224- else
225- {
226- // input parameter
227- if ( p . ParameterType . IsArray )
228- {
229- if ( p . IsOut )
230- {
231- if ( isGetMany )
232- {
233- rawParams . Add ( pname + ".capacity() as u32" ) ;
234- rawParams . Add ( pname + ".as_mut_ptr() as *mut T::Abi" ) ;
235- }
236- else
237- {
238- rawParams . Add ( pname + ".len() as u32" ) ;
239- rawParams . Add ( pname + ".as_mut_ptr() as *mut _" ) ;
240- }
241- }
242- else
243- {
244- rawParams . Add ( pname + ".len() as u32" ) ;
245- rawParams . Add ( pname + ".as_ptr() as *mut _" ) ;
246- }
247- }
248- else
249- {
250- rawParams . Add ( TypeHelpers . UnwrapInputParameter ( pname , p . ParameterType ) ) ;
251- }
252- }
253- }
254-
255- if ( Method . ReturnType . FullName != "System.Void" )
256- {
257- if ( Method . ReturnType . IsArray )
258- {
259- rawParams . Add ( "&mut outSize" ) ;
260- }
261- rawParams . Add ( "&mut out" ) ;
262- }
263-
264- var outInit = String . Join ( " " , output . SelectMany ( o => TypeHelpers . CreateUninitializedOutputs ( o . Item1 , o . Item2 ) ) ) ;
265- if ( outInit != "" ) outInit = "\r \n " + outInit ;
266-
267- var outWrap = String . Join ( ", " , output . Select ( o => TypeHelpers . WrapOutputParameter ( o . Item1 , o . Item2 ) ) ) ;
268- if ( output . Count != 1 )
269- {
270- outWrap = "(" + outWrap + ")" ; // also works for count == 0 (empty tuple)
271- }
272- outWrap = "Ok(" + outWrap + ")" ;
273-
274- if ( isGetMany )
275- {
276- outInit = $ "\r \n debug_assert!({ getManyPname } .capacity() > 0, \" capacity of `{ getManyPname } ` must not be 0 (use Vec::with_capacity)\" ); { getManyPname } .clear();{ outInit } ";
277- outWrap = $ "{ getManyPname } .set_len(out as usize); Ok(())";
278- }
279-
280- return outInit + $@ "
281- let hr = ((*self.lpVtbl).{ rawName } )({ String . Join ( ", " , rawParams ) } );
282- if hr == S_OK {{ { outWrap } }} else {{ err(hr) }}" ;
283- }
284-
285302 public string GetRawDeclaration ( )
286303 {
287304 var name = GetRawName ( ) ;
0 commit comments