Skip to content

Commit

Permalink
Merge pull request #1066 from AArnott/multiIfaceProxies
Browse files Browse the repository at this point in the history
Enable generation of proxies that implement multiple interfaces
  • Loading branch information
AArnott authored Jul 26, 2024
2 parents dc105fd + ca1b916 commit 53dd557
Show file tree
Hide file tree
Showing 9 changed files with 273 additions and 119 deletions.
37 changes: 26 additions & 11 deletions src/StreamJsonRpc/JsonRpc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -655,7 +655,9 @@ public IActivityTracingStrategy? ActivityTracingStrategy
/// <param name="stream">A bidirectional stream to send and receive RPC messages on.</param>
/// <param name="target">An optional target object to invoke when incoming RPC requests arrive.</param>
/// <returns>The initialized and listening <see cref="JsonRpc"/> object.</returns>
#pragma warning disable RS0027 // API with optional parameter(s) should have the most parameters amongst its public overloads
public static JsonRpc Attach(Stream stream, object? target = null)
#pragma warning restore RS0027 // API with optional parameter(s) should have the most parameters amongst its public overloads
{
Requires.NotNull(stream, nameof(stream));

Expand Down Expand Up @@ -726,7 +728,7 @@ public static T Attach<T>(Stream? sendingStream, Stream? receivingStream)
where T : class
{
var rpc = new JsonRpc(sendingStream, receivingStream);
T proxy = rpc.CreateProxy<T>(null, JsonRpcProxyOptions.Default, null);
T proxy = rpc.CreateProxy<T>(default, null, JsonRpcProxyOptions.Default, null);
rpc.StartListening();
return proxy;
}
Expand Down Expand Up @@ -762,7 +764,7 @@ public static T Attach<T>(IJsonRpcMessageHandler handler, JsonRpcProxyOptions? o
where T : class
{
var rpc = new JsonRpc(handler);
T proxy = rpc.CreateProxy<T>(null, options, null)!;
T proxy = rpc.CreateProxy<T>(default, null, options, null)!;
rpc.StartListening();
return proxy;
}
Expand All @@ -787,7 +789,7 @@ public T Attach<T>()
public T Attach<T>(JsonRpcProxyOptions? options)
where T : class
{
return this.CreateProxy<T>(null, options, null);
return this.CreateProxy<T>(default, null, options, null);
}

/// <summary>
Expand All @@ -806,7 +808,19 @@ public T Attach<T>(JsonRpcProxyOptions? options)
public object Attach(Type interfaceType, JsonRpcProxyOptions? options)
{
Requires.NotNull(interfaceType, nameof(interfaceType));
return this.CreateProxy(interfaceType.GetTypeInfo(), null, options ?? JsonRpcProxyOptions.Default, null)!;
return this.CreateProxy(interfaceType.GetTypeInfo(), default, null, options ?? JsonRpcProxyOptions.Default, null)!;
}

/// <summary>
/// Creates a JSON-RPC client proxy that conforms to the specified server interfaces.
/// </summary>
/// <param name="interfaceTypes">The interfaces that describes the functions available on the remote end.</param>
/// <param name="options">A set of customizations for how the client proxy is wired up. If <see langword="null"/>, default options will be used.</param>
/// <returns>An instance of the generated proxy.</returns>
public object Attach(ReadOnlySpan<Type> interfaceTypes, JsonRpcProxyOptions? options)
{
Requires.Argument(interfaceTypes.Length > 0, nameof(interfaceTypes), Resources.RequiredArgumentMissing);
return this.CreateProxy(interfaceTypes[0], interfaceTypes.Slice(1), null, options ?? JsonRpcProxyOptions.Default, null)!;
}

/// <inheritdoc cref="AddLocalRpcTarget(object, JsonRpcTargetOptions?)"/>
Expand Down Expand Up @@ -1201,10 +1215,10 @@ internal static T MarshalLimitedArgument<T>(T marshaledObject)
throw new NotImplementedException();
}

/// <inheritdoc cref="CreateProxy(TypeInfo, ValueTuple{TypeInfo, int}[], JsonRpcProxyOptions?, long?)"/>
internal object Attach(Type contractInterface, (TypeInfo Type, int Code)[]? implementedOptionalInterfaces, JsonRpcProxyOptions? options, long? marshaledObjectHandle)
/// <inheritdoc cref="CreateProxy(Type, ReadOnlySpan{Type}, ReadOnlySpan{ValueTuple{Type, int}}, JsonRpcProxyOptions?, long?)"/>
internal object Attach(Type contractInterface, (Type Type, int Code)[]? implementedOptionalInterfaces, JsonRpcProxyOptions? options, long? marshaledObjectHandle)
{
return this.CreateProxy(contractInterface.GetTypeInfo(), implementedOptionalInterfaces, options, marshaledObjectHandle);
return this.CreateProxy(contractInterface.GetTypeInfo(), default, implementedOptionalInterfaces, options, marshaledObjectHandle);
}

/// <inheritdoc cref="RpcTargetInfo.AddLocalRpcMethod(MethodInfo, object?, JsonRpcMethodAttribute?, SynchronizationContext?)"/>
Expand Down Expand Up @@ -2680,23 +2694,24 @@ private void ThrowIfConfigurationLocked()
}
}

private T CreateProxy<T>((TypeInfo Type, int Code)[]? implementedOptionalInterfaces, JsonRpcProxyOptions? options, long? marshaledObjectHandle)
private T CreateProxy<T>(ReadOnlySpan<Type> additionalContractInterfaces, ReadOnlySpan<(Type Type, int Code)> implementedOptionalInterfaces, JsonRpcProxyOptions? options, long? marshaledObjectHandle)
where T : class
{
return (T)this.CreateProxy(typeof(T).GetTypeInfo(), implementedOptionalInterfaces, options, marshaledObjectHandle);
return (T)this.CreateProxy(typeof(T).GetTypeInfo(), additionalContractInterfaces, implementedOptionalInterfaces, options, marshaledObjectHandle);
}

/// <summary>
/// Creates a JSON-RPC client proxy that implements a given set of interfaces.
/// </summary>
/// <param name="contractInterface">The interface that describes the functions available on the remote end.</param>
/// <param name="additionalContractInterfaces"><inheritdoc cref="ProxyGeneration.Get" path="/param[@name='additionalContractInterfaces']"/></param>
/// <param name="implementedOptionalInterfaces">Additional marshalable interfaces that the client proxy should implement.</param>
/// <param name="options">A set of customizations for how the client proxy is wired up. If <see langword="null" />, default options will be used.</param>
/// <param name="marshaledObjectHandle">The handle to the remote object that is being marshaled via this proxy.</param>
/// <returns>An instance of the generated proxy.</returns>
private IJsonRpcClientProxyInternal CreateProxy(TypeInfo contractInterface, (TypeInfo Type, int Code)[]? implementedOptionalInterfaces, JsonRpcProxyOptions? options, long? marshaledObjectHandle)
private IJsonRpcClientProxyInternal CreateProxy(Type contractInterface, ReadOnlySpan<Type> additionalContractInterfaces, ReadOnlySpan<(Type Type, int Code)> implementedOptionalInterfaces, JsonRpcProxyOptions? options, long? marshaledObjectHandle)
{
TypeInfo proxyType = ProxyGeneration.Get(contractInterface, implementedOptionalInterfaces);
TypeInfo proxyType = ProxyGeneration.Get(contractInterface, additionalContractInterfaces, implementedOptionalInterfaces);
return (IJsonRpcClientProxyInternal)Activator.CreateInstance(
proxyType.AsType(),
this,
Expand Down
Loading

0 comments on commit 53dd557

Please sign in to comment.