/// <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) !);
        }
Example #4
0
 /// <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);
     }
 }
Example #5
0
        /// <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);
            }
        }
Example #6
0
        /// <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) !);
            }
        }
Example #12
0
        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);
        }
Example #13
0
 /// <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)));
 }