public IEnumerable <string> GetParameterDeclarations() { yield return("&self"); foreach (var p in Method.Parameters) { Assert(!p.IsReturnValue); int?lengthIs = null; var lengthIsAttribute = p.CustomAttributes.SingleOrDefault(a => a.AttributeType.Name == "LengthIsAttribute"); if (lengthIsAttribute != null) { lengthIs = (int)lengthIsAttribute.ConstructorArguments[0].Value; } if (p.ParameterType.IsArray) { // need additional input size parameter (even if parameter is marked as [Out]) yield return(NameHelpers.FirstToLower(p.Name) + "Size: u32"); } else if (p.ParameterType.IsByReference && (p.ParameterType as ByReferenceType).ElementType.IsArray) { Assert(!lengthIs.HasValue); // need additional output size parameter yield return(NameHelpers.FirstToLower(p.Name) + "Size: *mut u32"); } yield return(NameHelpers.PreventKeywords(NameHelpers.FirstToLower(p.Name)) + ": " + TypeHelpers.GetTypeName(DeclaringType.Generator, this, p.ParameterType, TypeUsage.Raw)); } if (Method.ReturnType.FullName != "System.Void") { if (Method.ReturnType.IsArray) { yield return("outSize: *mut u32"); } yield return("out: *mut " + TypeHelpers.GetTypeName(DeclaringType.Generator, this, Method.ReturnType, TypeUsage.Raw)); } }
public string MakeWrapperBody(MethodDefinition def, bool isFactoryMethod) { var rawName = RawName; bool isGetMany = GetManyParameterName != null; var getManyPname = GetManyParameterName; var output = Output; var rawParams = new List <string> { "self.get_abi() as *const _ as *mut _" }; foreach (var p in def.Parameters) { var pname = NameHelpers.PreventKeywords(NameHelpers.FirstToLower(p.Name)); if (p.ParameterType.IsByReference) { if (((ByReferenceType)p.ParameterType).ElementType.IsArray) { rawParams.Add("&mut " + pname + "Size"); } // output parameter rawParams.Add("&mut " + pname); } else { // input parameter if (p.ParameterType.IsArray) { if (p.IsOut) { if (isGetMany) { rawParams.Add(pname + ".capacity() as u32"); rawParams.Add(pname + ".as_mut_ptr() as *mut T::Abi"); } else { rawParams.Add(pname + ".len() as u32"); rawParams.Add(pname + ".as_mut_ptr() as *mut _"); } } else { rawParams.Add(pname + ".len() as u32"); rawParams.Add(pname + ".as_ptr() as *mut _"); } } else { rawParams.Add(TypeHelpers.UnwrapInputParameter(pname, p.ParameterType)); } } } if (def.ReturnType.FullName != "System.Void") { if (def.ReturnType.IsArray) { rawParams.Add("&mut outSize"); } rawParams.Add("&mut out"); } var outInit = String.Join(" ", output.SelectMany(o => TypeHelpers.CreateUninitializedOutputs(o.Item1, o.Item2))); if (outInit != "") { outInit = "\r\n " + outInit; } var outWrap = String.Join(", ", output.Zip(GeneratedOutTypes, (a, b) => Tuple.Create(a.Item1, a.Item2, a.Item3, b)).Select(o => TypeHelpers.WrapOutputParameter(o.Item1, o.Item2, isFactoryMethod || o.Item3, o.Item4))); if (output.Count != 1) { outWrap = "(" + outWrap + ")"; // also works for count == 0 (empty tuple) } outWrap = "Ok(" + outWrap + ")"; if (isGetMany) { outInit = $"\r\n debug_assert!({ getManyPname }.capacity() > 0, \"capacity of `{ getManyPname }` must not be 0 (use Vec::with_capacity)\"); { getManyPname }.clear();{ outInit }"; outWrap = $"{ getManyPname }.set_len(out as usize); Ok(())"; } return(outInit + $@" let hr = (self.get_vtbl().{ rawName })({ String.Join(", ", rawParams) }); if hr == S_OK {{ { outWrap } }} else {{ err(hr) }}"); }
private MethodDetailsCache InitializeDetailsCache() { string rawName = GetRawName(); string name = GetWrapperName(rawName); bool isGetMany = (rawName == "GetMany" && DeclaringType.Namespace == "Windows.Foundation.Collections" && (DeclaringType.Name == "IVectorView`1" || DeclaringType.Name == "IIterator`1" || DeclaringType.Name == "IVector`1")); string getManyPname = null; // These `GetMany` methods have special semantics, since it takes an array and returns the number of elements that were filled // It uses the __RPC__out_ecount_part(capacity, *actual) annotation in the C headers. For the wrapper we use a &mut Vec<> buffer. var input = new List <Tuple <string, TypeReference, InputKind> >(); var output = new List <Tuple <string, TypeReference, bool> >(); foreach (var p in Method.Parameters) { string pname = NameHelpers.PreventKeywords(NameHelpers.FirstToLower(p.Name)); if (p.ParameterType.IsByReference) { Assert(p.IsOut); var realType = ((ByReferenceType)p.ParameterType).ElementType; output.Add(Tuple.Create(pname, realType, false)); } else { if (p.ParameterType.IsArray) { if (p.IsOut) { if (isGetMany) { Assert(getManyPname == null); // there should only be one out-array parameter for GetMany getManyPname = pname; input.Add(Tuple.Create(pname, ((ArrayType)p.ParameterType).ElementType, InputKind.VecBuffer)); } else { input.Add(Tuple.Create(pname, ((ArrayType)p.ParameterType).ElementType, InputKind.MutSlice)); } } else { input.Add(Tuple.Create(pname, ((ArrayType)p.ParameterType).ElementType, InputKind.Slice)); } } else { input.Add(Tuple.Create(pname, p.ParameterType, InputKind.Default)); } } } if (Method.ReturnType.FullName != "System.Void") { // this makes the actual return value the last in the tuple (if multiple) output.Add(Tuple.Create("out", Method.ReturnType, TypeHelpers.IsReturnTypeNonNull(Method.ReturnType, DeclaringType.Generator))); } // TODO: second tuple element should be true for some method's return value var outTypes = output.Select(o => Tuple.Create(o.Item2, o.Item3)).ToArray(); if (isGetMany) { outTypes = new Tuple <TypeReference, bool>[] { }; // GetMany has no return value } return(new MethodDetailsCache { WrappedName = name, RawName = rawName, InputParameterNames = input.Select(i => i.Item1).ToArray(), InputParameterTypes = input.Select(i => Tuple.Create(i.Item2, i.Item3)).ToArray(), OutTypes = outTypes.ToArray(), GetManyParameterName = isGetMany ? getManyPname : null, Output = output }); }