private (string signature, string code, bool isCompoundValue) buildFromConstructor(string name, Type type, string indent) { var constructorParameters = type.GetTypeInfo() .GetConstructors() .Select(x => x.GetParameters()) .OrderByDescending(x => x.Length) .First() ; var builder = new StringBuilder(); builder.AppendLine(decoder + ".AdvanceToCompoundValue();"); var signature = "("; foreach (var p in constructorParameters) { var decoderGenerator = new DecoderGenerator(decoder, message); decoderGenerator.add(name + "_" + p.Name, p.ParameterType, indent); signature += decoderGenerator.Signature; builder.Append(decoderGenerator.Result); } signature += ")"; builder.Append(indent); builder.Append("var " + name + " = new " + Generator.BuildTypeString(type) + "("); builder.Append(string.Join(", ", constructorParameters.Select(x => name + "_" + x.Name))); builder.Append(");"); return(signature, builder.ToString(), true); }
private (string signature, string code, bool isCompoundValue) createMethod(Type type, string name, string indent) { if (SignatureString.For.ContainsKey(type)) { return( SignatureString.For[type], decoder + ".Get" + type.Name, false ); } else { var decoderGenerator = new DecoderGenerator(decoder, message); decoderGenerator.add(name + "_inner", type, indent + " "); return( decoderGenerator.Signature, @"() => " + indent + @"{ " + decoderGenerator.Result + @" " + indent + "return " + name + @"_inner; " + indent + "}", decoderGenerator.IsCompoundValue ); } }
private static string generateMethodImplementation(MethodInfo methodInfo, string interfaceName) { if (!methodInfo.Name.EndsWith("Async")) { throw new InvalidOperationException($"The method '{methodInfo.Name}' does not end with 'Async'"); } var callName = methodInfo.Name.Substring(0, methodInfo.Name.Length - "Async".Length); var returnType = methodInfo.ReturnType; var returnTypeString = BuildTypeString(returnType); if (returnTypeString != "global::System.Threading.Tasks.Task" && !returnTypeString.StartsWith("global::System.Threading.Tasks.Task<")) { throw new InvalidOperationException($"The method '{methodInfo.Name}' does not return a Task type"); } var isProperty = propertyName.IsMatch(callName); isProperty &= methodInfo.GetCustomAttribute <DbusMethodAttribute>() == null; var parameters = methodInfo.GetParameters(); if (isProperty) { if (callName.StartsWith("Get")) { if (parameters.Length == 0) { isProperty &= true; } else if (parameters[0].ParameterType == typeof(CancellationToken)) { isProperty &= true; } else { isProperty = false; } } else if (callName.StartsWith("Set")) { if (parameters.Length == 1 && parameters[0].ParameterType != typeof(CancellationToken)) { isProperty &= true; } else if (parameters.Length == 2 && parameters[1].ParameterType == typeof(CancellationToken)) { isProperty &= true; } else { isProperty = false; } } } var encoder = new EncoderGenerator("sendBody"); var cancellationTokenName = "default(global::System.Threading.CancellationToken)"; if (parameters.Length > 0 || isProperty) { if (isProperty) { encoder.Add($@"""{interfaceName}""", typeof(string)); encoder.Add($@"""{callName.Substring(3 /* "Get" or "Set" */)}""", typeof(string)); interfaceName = "org.freedesktop.DBus.Properties"; callName = callName.Substring(0, 3); // "Get" or "Set" foreach (var parameter in parameters) { if (parameter.ParameterType == typeof(CancellationToken)) { cancellationTokenName = parameter.Name !; } else { encoder.AddVariant(parameter.Name !, parameter.ParameterType); } } } else { foreach (var parameter in parameters) { if (parameter.ParameterType == typeof(CancellationToken)) { cancellationTokenName = parameter.Name !; } else { encoder.Add(parameter.Name !, parameter.ParameterType); } } } } string returnStatement; var decoder = new DecoderGenerator("decoder", "receivedMessage"); if (returnType == typeof(Task)) { returnStatement = "return;"; } else if (isProperty) { // must be "Get" decoder.Add("result", typeof(object), Indent + " "); returnStatement = "return (" + BuildTypeString(returnType.GenericTypeArguments[0]) + ")result;"; } else // Task<T> { decoder.Add("result", returnType.GenericTypeArguments[0], Indent + " "); returnStatement = "return result;"; } var createFunction = ""; if (returnType != typeof(Task)) { createFunction = @" " + BuildTypeString(methodInfo.ReturnType.GenericTypeArguments[0]) + @" decode(global::Dbus.Decoder decoder) { " + decoder.Result + @" " + returnStatement + @" } "; } return(@" public async " + returnTypeString + @" " + methodInfo.Name + @"(" + string.Join(", ", methodInfo.GetParameters().Select(x => BuildTypeString(x.ParameterType) + " " + x.Name)) + @") { var sendBody = new global::Dbus.Encoder(); " + encoder.Result + @" var receivedMessage = await connection.SendMethodCall( this.path, """ + interfaceName + @""", """ + callName + @""", this.destination, sendBody, """ + encoder.Signature + @""", " + cancellationTokenName + @" ).ConfigureAwait(false); " + (returnType == typeof(Task) ? "" : createFunction) + @" using (receivedMessage) { receivedMessage.AssertSignature(""" + decoder.Signature + @"""); " + (returnType == typeof(Task) ? "return;" : "return decode(receivedMessage.Decoder);") + @" } } "); }
public static (string name, string implementation) GenerateMethodProxy(MethodInfo method) { if (!method.Name.EndsWith("Async")) { throw new InvalidOperationException("Only method names ending in 'Async' are supported"); } if (method.ReturnType != typeof(Task) && method.ReturnType.GetGenericTypeDefinition() != typeof(Task <>)) { throw new InvalidOperationException("Only methods returning a Task type are supported"); } var methodName = method.Name.Substring(0, method.Name.Length - "Async".Length); var methodImplementation = new StringBuilder(); methodImplementation.Append(@" private async global::System.Threading.Tasks.Task handle" + method.Name + @"(global::Dbus.MethodCallOptions methodCallOptions, global::Dbus.ReceivedMessage receivedMessage, global::System.Threading.CancellationToken cancellationToken) { "); var decoder = new DecoderGenerator("receivedMessage.Decoder", "receivedMessage"); var methodParameters = new List <string>(); foreach (var parameter in method.GetParameters()) { if (parameter.ParameterType == typeof(CancellationToken)) { methodParameters.Add("cancellationToken"); } else { decoder.Add(parameter.Name !, parameter.ParameterType); methodParameters.Add(parameter.Name !); } } var encoder = new EncoderGenerator("sendBody"); if (method.ReturnType != typeof(Task)) // Task<T> { var returnType = method.ReturnType.GenericTypeArguments[0]; encoder.Add("methodResult", returnType, Indent); } methodImplementation.Append(Indent); methodImplementation.AppendLine(@"receivedMessage.AssertSignature(""" + decoder.Signature + @""");"); methodImplementation.Append(decoder.Result); methodImplementation.Append(Indent); if (encoder.Signature != "") { methodImplementation.Append("var methodResult = "); } methodImplementation.Append("await target." + method.Name + "("); methodImplementation.Append(string.Join(", ", methodParameters)); methodImplementation.AppendLine(");"); methodImplementation.Append(Indent); methodImplementation.AppendLine("if (!methodCallOptions.ShouldSendReply)"); methodImplementation.Append(Indent); methodImplementation.AppendLine(" return;"); methodImplementation.Append(Indent); methodImplementation.AppendLine("var sendBody = new global::Dbus.Encoder();"); if (encoder.Signature != "") { methodImplementation.Append(encoder.Result); } methodImplementation.Append(Indent); methodImplementation.AppendLine(@"await connection.SendMethodReturnAsync(methodCallOptions, sendBody, """ + encoder.Signature + @""", cancellationToken).ConfigureAwait(false);"); methodImplementation.Append(@" }"); return(methodName, methodImplementation.ToString()); }
public static (string subscription, string implementation) GenerateEventImplementation(EventInfo eventInfo, string interfaceName) { if (eventInfo.EventHandlerType == null) { throw new InvalidOperationException("EventInfo has no handler type"); } var subscription = new StringBuilder(); subscription.Append(Indent); subscription.AppendLine("eventSubscriptions.Add(connection.RegisterSignalHandler("); subscription.Append(Indent); subscription.Append(" "); subscription.AppendLine("this.path,"); subscription.Append(Indent); subscription.Append(" "); subscription.AppendLine(@"""" + interfaceName + @""","); subscription.Append(Indent); subscription.Append(" "); subscription.AppendLine(@"""" + eventInfo.Name + @""","); subscription.Append(Indent); subscription.Append(" "); subscription.AppendLine("this.handle" + eventInfo.Name); subscription.Append(Indent); subscription.AppendLine("));"); var invocationParameters = new List <string>(); var decoder = new DecoderGenerator("receivedMessage.Decoder", "receivedMessage"); if (eventInfo.EventHandlerType.IsConstructedGenericType) { var arguments = eventInfo.EventHandlerType.GenericTypeArguments; for (var i = 0; i < arguments.Length; ++i) { var invocationParameter = "decoded" + i; decoder.Add(invocationParameter, arguments[i]); invocationParameters.Add(invocationParameter); } } var implementation = new StringBuilder(); implementation.Append(" "); implementation.Append("public event "); implementation.Append(BuildTypeString(eventInfo.EventHandlerType)); implementation.Append(" "); implementation.Append(eventInfo.Name); implementation.AppendLine(";"); implementation.Append(" "); implementation.Append("private void handle"); implementation.Append(eventInfo.Name); implementation.AppendLine("(global::Dbus.ReceivedMessage receivedMessage)"); implementation.Append(" "); implementation.AppendLine("{"); implementation.Append(Indent); implementation.AppendLine(@"receivedMessage.AssertSignature(""" + decoder.Signature + @""");"); implementation.Append(decoder.Result); implementation.Append(Indent); implementation.AppendLine(eventInfo.Name + "?.Invoke(" + string.Join(", ", invocationParameters) + ");"); implementation.Append(" "); implementation.AppendLine("}"); return(subscription.ToString(), implementation.ToString()); }