Skip to content

Commit b45d12f

Browse files
authored
Merge pull request #54 from Boddlnagg/optional-comptr
Make ComPtr results optional
2 parents 832141a + 9735cad commit b45d12f

31 files changed

+80350
-80250
lines changed

Generator/Types/ClassDef.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,11 @@ public override void CollectDependencies()
5656

5757
foreach (var m in factoryMethods)
5858
{
59-
methodWrappers.Add(new ClassMethodDef(m, this));
59+
methodWrappers.Add(new ClassMethodDef(m, this, true));
6060
}
6161
foreach (var m in staticMethods)
6262
{
63-
methodWrappers.Add(new ClassMethodDef(m, this));
63+
methodWrappers.Add(new ClassMethodDef(m, this, false));
6464
}
6565

6666
// fix name clashes in method wrappers (caused by overloads from different interfaces)

Generator/Types/ClassMethodDef.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,15 @@ public IEnumerable<TypeDef> ForeignAssemblyDependencies
5454
}
5555
}
5656

57-
public ClassMethodDef(MethodDef method, ClassDef containingClass)
57+
public ClassMethodDef(MethodDef method, ClassDef containingClass, bool isFactory)
5858
{
5959
WrappedMethod = method;
6060
ContainingClass = containingClass;
6161
Name = WrappedMethod.Details.WrappedName;
6262

6363
AddDependency(method.DeclaringType);
6464
inputParameters = WrappedMethod.Details.MakeInputParameters(Generator, this);
65-
outType = WrappedMethod.Details.MakeOutType(Generator, this);
65+
outType = WrappedMethod.Details.MakeOutType(Generator, this, isFactory);
6666
}
6767

6868
public void FixupName(string suffix)
@@ -76,9 +76,9 @@ public string Emit()
7676
var dependsOnAssemblies = new List<string>(ForeignAssemblyDependencies.GroupBy(t => t.Module.Assembly.Name.Name).Select(g => g.Key));
7777
var features = new FeatureConditions(dependsOnAssemblies);
7878

79-
return $@"{ features.GetAttribute() }#[inline] pub fn { Name }({ String.Join(", ", inputParameters) }) -> Result<{ outType }> {{ unsafe {{
79+
return $@"{ features.GetAttribute() }#[inline] pub fn { Name }({ String.Join(", ", inputParameters) }) -> Result<{ outType }> {{
8080
<Self as RtActivatable<{ m.DeclaringType.Name }>>::get_activation_factory().{ m.Details.WrappedName }({ String.Join(", ", m.Details.InputParameterNames) })
81-
}}}}";
81+
}}";
8282
}
8383

8484
public void AddDependency(TypeDef other)

Generator/Types/InterfaceDef.cs

+18-5
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@
77

88
namespace Generator.Types
99
{
10+
public enum InterfaceKind
11+
{
12+
Unidentified,
13+
Factory,
14+
Statics,
15+
Instance
16+
}
17+
1018
public class InterfaceDef : TypeDef
1119
{
1220
public override TypeKind Kind
@@ -18,8 +26,8 @@ public override TypeKind Kind
1826
}
1927

2028
public bool IsDelegate { get; private set; }
29+
public InterfaceKind InterfaceKind { get; private set; }
2130

22-
private bool isFactoryOrStatic;
2331
private List<MethodDef> methods;
2432
public override IEnumerable<MethodDef> Methods
2533
{
@@ -49,7 +57,7 @@ public override void CollectDependencies()
4957
exclusiveToType = exclusiveTo.ConstructorArguments[0].Value as TypeDefinition;
5058
}
5159

52-
isFactoryOrStatic = IsFactoryOrStatic(Generator, this, exclusiveToType);
60+
InterfaceKind = GetInterfaceKind(Generator, this, exclusiveToType);
5361

5462
rawMethodDeclarations = methods.Select(m => m.GetRawDeclaration()).ToList();
5563
wrapperMethodDeclarations = methods.Select(m => m.GetWrapperDefinition()).ToList();
@@ -76,7 +84,7 @@ public override void Emit()
7684
genericWithBounds = "<" + String.Join(", ", t.GenericParameters.Select(p => p.Name + ": RtType")) + ">";
7785
}
7886

79-
string prependStatic = isFactoryOrStatic ? "static " : "";
87+
string prependStatic = (InterfaceKind == InterfaceKind.Factory || InterfaceKind == InterfaceKind.Statics) ? "static " : "";
8088

8189
var rawMethodDeclarationsWithFeatures = new List<string>();
8290
var lastFeatureAttr = definitionFeatureConditions.LastOrDefault()?.GetAttribute();
@@ -122,7 +130,7 @@ public override void Emit()
122130
}
123131
}
124132

125-
private bool IsFactoryOrStatic(Generator gen, TypeDef t, TypeDefinition exclusiveToType)
133+
private InterfaceKind GetInterfaceKind(Generator gen, TypeDef t, TypeDefinition exclusiveToType)
126134
{
127135
var trimmedName = t.Name.TrimEnd('1', '2', '3', '4', '5', '6', '7', '8', '9');
128136
var guessedFromName = trimmedName.EndsWith("Factory") || trimmedName.EndsWith("Statics");
@@ -149,7 +157,12 @@ private bool IsFactoryOrStatic(Generator gen, TypeDef t, TypeDefinition exclusiv
149157
}
150158
}
151159

152-
return candidates.Any(c => c.GetFactoryTypes().Contains(t.Type) || c.GetStaticTypes().Contains(t.Type));
160+
if (candidates.Any(c => c.GetFactoryTypes().Contains(t.Type)))
161+
return InterfaceKind.Factory;
162+
else if (candidates.Any(c => c.GetStaticTypes().Contains(t.Type)))
163+
return InterfaceKind.Statics;
164+
else
165+
return InterfaceKind.Instance;
153166
}
154167
}
155168
}

Generator/Types/MethodDef.cs

+108-91
Original file line numberDiff line numberDiff line change
@@ -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();

Generator/Types/TypeDef.cs

+11-1
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,17 @@ public string GetPath(Module requestingModule)
205205
}
206206
else
207207
{
208-
name = $"::rt::gen::{ Module.Path }::{ Name }";
208+
if (Module.Path.StartsWith("windows::foundation"))
209+
{
210+
var shortened = Module.Path.Substring("windows::foundation".Length);
211+
if (shortened.Length > 0)
212+
shortened = shortened.Substring(2) + "::";
213+
name = $"foundation::{ shortened }{ Name }";
214+
}
215+
else
216+
{
217+
name = $"::rt::gen::{ Module.Path }::{ Name }";
218+
}
209219
var relative = $"{ Module.GetRelativePath(requestingModule) }::{ Name }";
210220
if (relative.Length < name.Length)
211221
name = relative;

0 commit comments

Comments
 (0)