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
{
/// <summary>
/// Will eventually give the resolved capability.
/// Completes when the capability gets resolved.
/// </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<ConsumedCapability?> _capTask;
public LazyCapability(Task<ConsumedCapability?> capabilityTask)
{
WhenResolved = capabilityTask;
_capTask = capabilityTask;
}
public LazyCapability(Task<Proxy> proxyTask)
@ -29,7 +30,7 @@ namespace Capnp.Rpc
async Task<ConsumedCapability?> AwaitCap() => (await _proxyTask!).ConsumedCap;
WhenResolved = AwaitCap();
_capTask = AwaitCap();
}
internal override void Freeze(out IRpcEndpoint? boundEndpoint)
@ -40,7 +41,7 @@ namespace Capnp.Rpc
try
{
WhenResolved.Result?.Freeze(out boundEndpoint);
_capTask.Result?.Freeze(out boundEndpoint);
}
catch (AggregateException exception)
{
@ -61,7 +62,7 @@ namespace Capnp.Rpc
{
if (WhenResolved.ReplacementTaskIsCompletedSuccessfully())
{
using var proxy = new Proxy(WhenResolved.Result);
using var proxy = GetResolvedCapability<BareProxy>()!;
return proxy.Export(endpoint, writer);
}
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)
{
ConsumedCapability? cap;
try
{
cap = await WhenResolved;
cap = await _capTask;
}
catch
{

View File

@ -21,9 +21,6 @@ namespace Capnp.Rpc
public LocalAnswerCapability(Task<Proxy> proxyTask)
{
_whenResolvedProxy = proxyTask;
async Task<ConsumedCapability?> AwaitResolved() => (await _whenResolvedProxy).ConsumedCap;
WhenResolved = AwaitResolved();
}
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)
{

View File

@ -16,11 +16,12 @@ namespace Capnp.Rpc
{
_remoteId = remoteId;
async Task<Proxy> AwaitProxy() => new Proxy(await WhenResolved);
async Task<Proxy> AwaitProxy() => new Proxy(await _resolvedCap.Task);
_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)
{

View File

@ -17,7 +17,7 @@ namespace Capnp.Rpc
/// <typeparam name="T">Capability interface</typeparam>
/// <param name="obj">instance to share</param>
/// <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)
return proxy.Cast<T>(false);
@ -32,18 +32,30 @@ namespace Capnp.Rpc
bool _disposedValue = false;
/// <summary>
/// Will eventually give the resolved capability, if this is a promised capability.
/// Completes when the capability gets resolved.
/// </summary>
public Task<ConsumedCapability?> WhenResolved
public Task WhenResolved
{
get
{
return ConsumedCap is IResolvingCapability resolving ?
resolving.WhenResolved :
Task.FromResult(ConsumedCap);
resolving.WhenResolved : Task.CompletedTask;
}
}
/// <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>
/// Underlying low-level capability
/// </summary>

View File

@ -23,18 +23,6 @@ namespace Capnp.Rpc
_question = question ?? throw new ArgumentNullException(nameof(question));
_access = access ?? throw new ArgumentNullException(nameof(access));
_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)
@ -81,7 +69,7 @@ namespace Capnp.Rpc
{
try
{
return WhenResolved.Result;
return _whenResolvedProxy.Result.ConsumedCap;
}
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)
{

View File

@ -16,7 +16,8 @@ namespace Capnp.Rpc
ILogger Logger { get; } = Logging.CreateLogger<RemoteResolvingCapability>();
#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)
{

View File

@ -9,7 +9,9 @@ namespace Capnp.Rpc
{
while (cap is IResolvingCapability resolving)
{
cap = await resolving.WhenResolved;
await resolving.WhenResolved;
using var proxy = resolving.GetResolvedCapability<BareProxy>()!;
cap = proxy.ConsumedCap;
}
return cap;
@ -30,7 +32,9 @@ namespace Capnp.Rpc
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!);
}
catch (System.Exception exception)
@ -68,5 +72,24 @@ namespace Capnp.Rpc
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;
}
}
}
}