refactored IResolvingCapability to hide ConsumedCapability

This commit is contained in:
Christian Köllner 2020-04-03 22:10:40 +02:00
parent 4bf0e970c2
commit d7f937a9c0
8 changed files with 90 additions and 37 deletions

View File

@ -8,8 +8,15 @@ namespace Capnp.Rpc
public interface IResolvingCapability public interface IResolvingCapability
{ {
/// <summary> /// <summary>
/// Will eventually give the resolved capability. /// Completes when the capability gets resolved.
/// </summary> /// </summary>
Task<ConsumedCapability?> WhenResolved { get; } Task WhenResolved { get; }
/// <summary>
/// Returns the resolved capability
/// </summary>
/// <typeparam name="T">Capability interface or <see cref="BareProxy"/></typeparam>
/// <returns>the resolved capability, or null if it did not resolve yet</returns>
T? GetResolvedCapability<T>() where T: class;
} }
} }

View File

@ -17,10 +17,11 @@ namespace Capnp.Rpc
} }
readonly Task<Proxy>? _proxyTask; readonly Task<Proxy>? _proxyTask;
readonly Task<ConsumedCapability?> _capTask;
public LazyCapability(Task<ConsumedCapability?> capabilityTask) public LazyCapability(Task<ConsumedCapability?> capabilityTask)
{ {
WhenResolved = capabilityTask; _capTask = capabilityTask;
} }
public LazyCapability(Task<Proxy> proxyTask) public LazyCapability(Task<Proxy> proxyTask)
@ -29,7 +30,7 @@ namespace Capnp.Rpc
async Task<ConsumedCapability?> AwaitCap() => (await _proxyTask!).ConsumedCap; async Task<ConsumedCapability?> AwaitCap() => (await _proxyTask!).ConsumedCap;
WhenResolved = AwaitCap(); _capTask = AwaitCap();
} }
internal override void Freeze(out IRpcEndpoint? boundEndpoint) internal override void Freeze(out IRpcEndpoint? boundEndpoint)
@ -40,7 +41,7 @@ namespace Capnp.Rpc
try try
{ {
WhenResolved.Result?.Freeze(out boundEndpoint); _capTask.Result?.Freeze(out boundEndpoint);
} }
catch (AggregateException exception) catch (AggregateException exception)
{ {
@ -61,7 +62,7 @@ namespace Capnp.Rpc
{ {
if (WhenResolved.ReplacementTaskIsCompletedSuccessfully()) if (WhenResolved.ReplacementTaskIsCompletedSuccessfully())
{ {
using var proxy = new Proxy(WhenResolved.Result); using var proxy = GetResolvedCapability<BareProxy>()!;
return proxy.Export(endpoint, writer); return proxy.Export(endpoint, writer);
} }
else else
@ -84,14 +85,33 @@ namespace Capnp.Rpc
} }
} }
public Task<ConsumedCapability?> WhenResolved { get; } public Task WhenResolved => _capTask;
public T? GetResolvedCapability<T>() where T: class
{
if (_capTask.IsCompleted)
{
try
{
return CapabilityReflection.CreateProxy<T>(_capTask.Result) as T;
}
catch (AggregateException exception)
{
throw exception.InnerException!;
}
}
else
{
return null;
}
}
async Task<DeserializerState> CallImpl(ulong interfaceId, ushort methodId, DynamicSerializerState args, CancellationToken cancellationToken) async Task<DeserializerState> CallImpl(ulong interfaceId, ushort methodId, DynamicSerializerState args, CancellationToken cancellationToken)
{ {
ConsumedCapability? cap; ConsumedCapability? cap;
try try
{ {
cap = await WhenResolved; cap = await _capTask;
} }
catch catch
{ {

View File

@ -21,9 +21,6 @@ namespace Capnp.Rpc
public LocalAnswerCapability(Task<Proxy> proxyTask) public LocalAnswerCapability(Task<Proxy> proxyTask)
{ {
_whenResolvedProxy = proxyTask; _whenResolvedProxy = proxyTask;
async Task<ConsumedCapability?> AwaitResolved() => (await _whenResolvedProxy).ConsumedCap;
WhenResolved = AwaitResolved();
} }
public LocalAnswerCapability(Task<DeserializerState> answer, MemberAccessPath access): public LocalAnswerCapability(Task<DeserializerState> answer, MemberAccessPath access):
@ -42,7 +39,9 @@ namespace Capnp.Rpc
} }
public Task<ConsumedCapability?> WhenResolved { get; private set; } public Task WhenResolved => _whenResolvedProxy;
public T? GetResolvedCapability<T>() where T : class => _whenResolvedProxy.GetResolvedCapability<T>();
internal override Action? Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer) internal override Action? Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer)
{ {

View File

@ -16,11 +16,12 @@ namespace Capnp.Rpc
{ {
_remoteId = remoteId; _remoteId = remoteId;
async Task<Proxy> AwaitProxy() => new Proxy(await WhenResolved); async Task<Proxy> AwaitProxy() => new Proxy(await _resolvedCap.Task);
_whenResolvedProxy = AwaitProxy(); _whenResolvedProxy = AwaitProxy();
} }
public override Task<ConsumedCapability?> WhenResolved => _resolvedCap.Task; public override Task WhenResolved => _resolvedCap.Task;
public override T? GetResolvedCapability<T>() where T: class => _whenResolvedProxy.GetResolvedCapability<T>();
internal override void Freeze(out IRpcEndpoint? boundEndpoint) internal override void Freeze(out IRpcEndpoint? boundEndpoint)
{ {

View File

@ -17,7 +17,7 @@ namespace Capnp.Rpc
/// <typeparam name="T">Capability interface</typeparam> /// <typeparam name="T">Capability interface</typeparam>
/// <param name="obj">instance to share</param> /// <param name="obj">instance to share</param>
/// <returns></returns> /// <returns></returns>
public static T Share<T>(T obj) where T: class public static T Share<T>(T obj) where T : class
{ {
if (obj is Proxy proxy) if (obj is Proxy proxy)
return proxy.Cast<T>(false); return proxy.Cast<T>(false);
@ -32,18 +32,30 @@ namespace Capnp.Rpc
bool _disposedValue = false; bool _disposedValue = false;
/// <summary> /// <summary>
/// Will eventually give the resolved capability, if this is a promised capability. /// Completes when the capability gets resolved.
/// </summary> /// </summary>
public Task<ConsumedCapability?> WhenResolved public Task WhenResolved
{ {
get get
{ {
return ConsumedCap is IResolvingCapability resolving ? return ConsumedCap is IResolvingCapability resolving ?
resolving.WhenResolved : resolving.WhenResolved : Task.CompletedTask;
Task.FromResult(ConsumedCap);
} }
} }
/// <summary>
/// Returns the resolved capability
/// </summary>
/// <typeparam name="T">Capability interface or <see cref="BareProxy"/></typeparam>
/// <returns>the resolved capability, or null if it did not resolve yet</returns>
public T? GetResolvedCapability<T>() where T : class
{
if (ConsumedCap is IResolvingCapability resolving)
return resolving.GetResolvedCapability<T>();
else
return CapabilityReflection.CreateProxy<T>(ConsumedCap) as T;
}
/// <summary> /// <summary>
/// Underlying low-level capability /// Underlying low-level capability
/// </summary> /// </summary>

View File

@ -23,18 +23,6 @@ namespace Capnp.Rpc
_question = question ?? throw new ArgumentNullException(nameof(question)); _question = question ?? throw new ArgumentNullException(nameof(question));
_access = access ?? throw new ArgumentNullException(nameof(access)); _access = access ?? throw new ArgumentNullException(nameof(access));
_whenResolvedProxy = proxyTask ?? throw new ArgumentNullException(nameof(proxyTask)); _whenResolvedProxy = proxyTask ?? throw new ArgumentNullException(nameof(proxyTask));
async Task<ConsumedCapability?> AwaitWhenResolved()
{
var proxy = await _whenResolvedProxy;
if (_question.IsTailCall)
throw new InvalidOperationException("Question is a tail call, so won't resolve back.");
return proxy.ConsumedCap;
}
WhenResolved = AwaitWhenResolved();
} }
static async Task<Proxy> TransferOwnershipToDummyProxy(PendingQuestion question, MemberAccessPath access) static async Task<Proxy> TransferOwnershipToDummyProxy(PendingQuestion question, MemberAccessPath access)
@ -81,7 +69,7 @@ namespace Capnp.Rpc
{ {
try try
{ {
return WhenResolved.Result; return _whenResolvedProxy.Result.ConsumedCap;
} }
catch (AggregateException exception) catch (AggregateException exception)
{ {
@ -96,7 +84,9 @@ namespace Capnp.Rpc
} }
} }
public override Task<ConsumedCapability?> WhenResolved { get; } public override Task WhenResolved => _whenResolvedProxy;
public override T? GetResolvedCapability<T>() where T: class => _whenResolvedProxy.GetResolvedCapability<T>();
protected override void GetMessageTarget(MessageTarget.WRITER wr) protected override void GetMessageTarget(MessageTarget.WRITER wr)
{ {

View File

@ -16,7 +16,8 @@ namespace Capnp.Rpc
ILogger Logger { get; } = Logging.CreateLogger<RemoteResolvingCapability>(); ILogger Logger { get; } = Logging.CreateLogger<RemoteResolvingCapability>();
#endif #endif
public abstract Task<ConsumedCapability?> WhenResolved { get; } public abstract Task WhenResolved { get; }
public abstract T? GetResolvedCapability<T>() where T : class;
protected RemoteResolvingCapability(IRpcEndpoint ep) : base(ep) protected RemoteResolvingCapability(IRpcEndpoint ep) : base(ep)
{ {

View File

@ -9,7 +9,9 @@ namespace Capnp.Rpc
{ {
while (cap is IResolvingCapability resolving) while (cap is IResolvingCapability resolving)
{ {
cap = await resolving.WhenResolved; await resolving.WhenResolved;
using var proxy = resolving.GetResolvedCapability<BareProxy>()!;
cap = proxy.ConsumedCap;
} }
return cap; return cap;
@ -30,7 +32,9 @@ namespace Capnp.Rpc
try try
{ {
var resolvedCap = await Unwrap(await cap.WhenResolved); await cap.WhenResolved;
using var proxy = cap.GetResolvedCapability<BareProxy>()!;
var resolvedCap = await Unwrap(proxy.ConsumedCap);
endpoint.Resolve(preliminaryId, vine, () => resolvedCap!); endpoint.Resolve(preliminaryId, vine, () => resolvedCap!);
} }
catch (System.Exception exception) catch (System.Exception exception)
@ -68,5 +72,24 @@ namespace Capnp.Rpc
default: return BareProxy.FromImpl(obj); default: return BareProxy.FromImpl(obj);
} }
} }
public static T? GetResolvedCapability<T>(this Task<Proxy> proxyTask) where T: class
{
if (proxyTask.IsCompleted)
{
try
{
return proxyTask.Result.Cast<T>(false);
}
catch (AggregateException exception)
{
throw exception.InnerException!;
}
}
else
{
return null;
}
}
} }
} }