/// <summary> /// Returns a promise-pipelined Proxy for a remote method invocation Task. /// </summary> /// <typeparam name="TInterface">Capability interface type</typeparam> /// <param name="task">Task returning an interface</param> /// <param name="allowNoPipeliningFallback">If this flag is 'false', the <paramref name="task"/> MUST have been returned from a remote /// method invocation on a generated Proxy interface. Since this is the prerequisite for promise pipelining to work, the method throws an /// exception if the requirement is not met (i.e. the passed some Task instance was constructed "somewhere else"). Setting this flag to 'true' /// prevents such an exception. The method falls back to a local "lazy" proxy for the given Task. It is fully usable, but does not perform /// any promise pipelining (as specified for Cap'n Proto).</param> /// <returns>A proxy for the given future.</returns> /// <exception cref="ArgumentNullException"><paramref name="task"/> is null.</exception> /// <exception cref="InvalidCapabilityInterfaceException"><typeparamref name="TInterface"/> did not qualify as capability interface.</exception> /// <exception cref="ArgumentException">The task was not returned from a remote method invocation. Promise pipelining won't work. /// Setting <paramref name="allowNoPipeliningFallback"/>> to 'true' prevents this exception. /// OR: Mismatch between generic type arguments (if capability interface is generic).</exception> /// <exception cref="InvalidOperationException">Mismatch between generic type arguments (if capability interface is generic).</exception> /// <exception cref="System.Reflection.TargetInvocationException">Problem with instatiating the Proxy (constructor threw exception).</exception> /// <exception cref="MemberAccessException">Caller does not have permission to invoke the Proxy constructor.</exception> /// <exception cref="TypeLoadException">Problem with building the Proxy type, or problem with loading some dependent class.</exception> public static TInterface Eager <TInterface>(this Task <TInterface> task, bool allowNoPipeliningFallback = false) where TInterface : class, IDisposable { var answer = TryGetAnswer(task); if (answer == null) { if (!allowNoPipeliningFallback) { throw new ArgumentException("The task was not returned from a remote method invocation. See documentation for details."); } var proxyTask = task.AsProxyTask(); if (proxyTask.ReplacementTaskIsCompletedSuccessfully()) { return(proxyTask.Result.Cast <TInterface>(true)); } else { var lazyCap = new LazyCapability(proxyTask); return((CapabilityReflection.CreateProxy <TInterface>(lazyCap) as TInterface) !); } } else { async Task <IDisposable?> AsDisposableTask() { return(await task); } return((CapabilityReflection.CreateProxy <TInterface>(answer.Access(Path_OneAndOnly, AsDisposableTask())) as TInterface) !); } }
public static TInterface PseudoEager <TInterface>(this Task <TInterface> task) where TInterface : class, IDisposable { var lazyCap = new LazyCapability(task.AsProxyTask()); return((CapabilityReflection.CreateProxy <TInterface>(lazyCap) as TInterface) !); }
public static TInterface PseudoEager <TInterface>(this Task <TInterface> task, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0) where TInterface : class { var lazyCap = new LazyCapability(AwaitProxy(task)); return((CapabilityReflection.CreateProxy <TInterface>(lazyCap, memberName, sourceFilePath, sourceLineNumber) as TInterface) !); }
/// <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> /// Casts this Proxy to a different capability interface. /// </summary> /// <typeparam name="T">Desired capability interface</typeparam> /// <param name="disposeThis">Whether to Dispose() this Proxy instance</param> /// <returns>Proxy for desired capability interface</returns> /// <exception cref="InvalidCapabilityInterfaceException"><typeparamref name="T"/> did not qualify as capability interface.</exception> /// <exception cref="InvalidOperationException">This capability is broken, or mismatch between generic type arguments (if capability interface is generic).</exception> /// <exception cref="ArgumentException">Mismatch between generic type arguments (if capability interface is generic).</exception> /// <exception cref="System.Reflection.TargetInvocationException">Problem with instatiating the Proxy (constructor threw exception).</exception> /// <exception cref="MemberAccessException">Caller does not have permission to invoke the Proxy constructor.</exception> /// <exception cref="TypeLoadException">Problem with building the Proxy type, or problem with loading some dependent class.</exception> public T Cast <T>(bool disposeThis) where T : class { if (IsNull) { throw new InvalidOperationException("Capability is broken"); } using (disposeThis ? this : null) { return(CapabilityReflection.CreateProxy <T>(ConsumedCap) as T); } }
/// <summary> /// Returns the remote bootstrap capability. /// </summary> /// <typeparam name="TProxy">Bootstrap capability interface</typeparam> /// <returns>A proxy for the bootstrap capability</returns> public TProxy GetMain <TProxy>() where TProxy : class { if (!WhenConnected.IsCompleted) { throw new InvalidOperationException("Connection not yet established"); } if (!WhenConnected.IsCompletedSuccessfully) { throw new InvalidOperationException("Connection not successfully established"); } Debug.Assert(_inboundEndpoint != null); return(CapabilityReflection.CreateProxy <TProxy>(_inboundEndpoint.QueryMain()) as TProxy); }
internal static Skeleton GetOrCreateSkeleton <T>(T impl, bool addRef) where T : class { if (impl is Skeleton skel) { return(skel); } skel = _implMap.GetValue(impl, _ => CapabilityReflection.CreateSkeleton(_)); if (addRef) { skel.Claim(); } return(skel); }
/// <summary> /// Unwraps given capability. Unwrapping walks the chain of promised capabilities and awaits their resolutions, /// until we get the finally resolved capability. If it is the capability, the method returns a null reference. /// If the capability is broken (resolved to exception, dependent answer faulted or cancelled, RPC endpoint closed), /// it throws an exception. /// </summary> /// <typeparam name="TInterface">Capability interface</typeparam> /// <param name="cap">capability to unwrap</param> /// <returns>Task returning the eventually resolved capability</returns> /// <exception cref="RpcException">Capability is broken</exception> public static async Task <TInterface?> Unwrap <TInterface>(this TInterface cap) where TInterface : class, IDisposable { using var proxy = cap as Proxy; if (proxy == null) { return(cap); } var unwrapped = await proxy.ConsumedCap.Unwrap(); if (unwrapped == null || unwrapped == NullCapability.Instance) { return(null); } return(((CapabilityReflection.CreateProxy <TInterface>(unwrapped)) as TInterface) !); }
static async Task <Proxy> AwaitProxy <T>(Task <T> task) where T : class { var item = await task; switch (item) { case Proxy proxy: return(proxy); case null: return(CapabilityReflection.CreateProxy <T>(null)); } var skel = Skeleton.GetOrCreateSkeleton(item !, false); var localCap = LocalCapability.Create(skel); return(CapabilityReflection.CreateProxy <T>(localCap)); }
public T?GetResolvedCapability <T>() where T : class { if (_capTask.WrappedTask.IsCompleted) { try { return((CapabilityReflection.CreateProxy <T>(_capTask.Result) as T) !); } catch (AggregateException exception) { throw exception.InnerException !; } } else { return(null); } }
/// <summary> /// Returns a promise-pipelined Proxy for a remote method invocation Task. /// </summary> /// <typeparam name="TInterface">Capability interface type</typeparam> /// <param name="task">Task returning an interface</param> /// <param name="allowNoPipeliningFallback">If this flag is 'false', the <paramref name="task"/> MUST have been returned from a remote /// method invocation on a generated Proxy interface. Since this is the prerequisite for promise pipelining to work, the method throws an /// exception if the requirement is not met (i.e. the passed some Task instance was constructed "somewhere else"). Setting this flag to 'true' /// prevents such an exception. The method falls back to a local "lazy" proxy for the given Task. It is fully usable, but does not perform /// any promise pipelining (as specified for Cap'n Proto).</param> /// <returns>A proxy for the given future.</returns> /// <exception cref="ArgumentNullException"><paramref name="task"/> is null.</exception> /// <exception cref="InvalidCapabilityInterfaceException"><typeparamref name="TInterface"/> did not qualify as capability interface.</exception> /// <exception cref="ArgumentException">The task was not returned from a remote method invocation. Promise pipelining won't work. /// Setting <paramref name="allowNoPipeliningFallback"/>> to 'true' prevents this exception. /// OR: Mismatch between generic type arguments (if capability interface is generic).</exception> /// <exception cref="InvalidOperationException">Mismatch between generic type arguments (if capability interface is generic).</exception> /// <exception cref="System.Reflection.TargetInvocationException">Problem with instatiating the Proxy (constructor threw exception).</exception> /// <exception cref="MemberAccessException">Caller does not have permission to invoke the Proxy constructor.</exception> /// <exception cref="TypeLoadException">Problem with building the Proxy type, or problem with loading some dependent class.</exception> public static TInterface Eager <TInterface>(this Task <TInterface> task, bool allowNoPipeliningFallback = false) where TInterface : class { var answer = TryGetAnswer(task); if (answer == null) { if (!allowNoPipeliningFallback) { throw new ArgumentException("The task was not returned from a remote method invocation. See documentation for details."); } var lazyCap = new LazyCapability(AwaitProxy(task)); return((CapabilityReflection.CreateProxy <TInterface>(lazyCap) as TInterface) !); } else { return((CapabilityReflection.CreateProxy <TInterface>(answer.Access(Path_OneAndOnly)) as TInterface) !); } }
internal static Skeleton GetOrCreateSkeleton <T>(T impl, bool addRef) where T : class { if (impl == null) { throw new ArgumentNullException(nameof(impl)); } if (impl is Skeleton skel) { return(skel); } skel = _implMap.GetValue(impl, _ => CapabilityReflection.CreateSkeleton(_)); if (addRef) { skel.Claim(); } return(skel); }
/// <summary> /// Claims ownership on the given capability, preventing its automatic disposal. /// </summary> /// <typeparam name="T">Capability interface</typeparam> /// <param name="impl">Capability implementation</param> /// <returns>A disposable object. Calling Dispose() on the returned instance relinquishes ownership again.</returns> public static IDisposable Claim <T>(T impl) where T : class { return(new SkeletonRelinquisher(CapabilityReflection.CreateSkeletonInternal(impl))); }