internal FdbFutureSingle([NotNull] FutureHandle handle, [NotNull] Func <FutureHandle, T> selector, CancellationToken ct)
        {
            Contract.NotNull(handle, nameof(handle));
            Contract.NotNull(selector, nameof(selector));

            m_handle         = handle;
            m_resultSelector = selector;

            try
            {
                if (handle.IsInvalid)
                {                 // it's dead, Jim !
                    SetFlag(FdbFuture.Flags.COMPLETED);
                    m_resultSelector = null;
                    return;
                }

                if (FdbNative.FutureIsReady(handle))
                {                 // either got a value or an error
#if DEBUG_FUTURES
                    Debug.WriteLine("Future<" + typeof(T).Name + "> 0x" + handle.Handle.ToString("x") + " was already ready");
#endif
                    HandleCompletion(fromCallback: false);
#if DEBUG_FUTURES
                    Debug.WriteLine("Future<" + typeof(T).Name + "> 0x" + handle.Handle.ToString("x") + " completed inline");
#endif
                    return;
                }

                // register for cancellation (if needed)
                if (ct.CanBeCanceled)
                {
                    if (ct.IsCancellationRequested)
                    {                     // we have already been cancelled
#if DEBUG_FUTURES
                        Debug.WriteLine("Future<" + typeof(T).Name + "> 0x" + handle.Handle.ToString("x") + " will complete later");
#endif

                        // Abort the future and simulate a Canceled task
                        SetFlag(FdbFuture.Flags.COMPLETED);
                        // note: we don't need to call fdb_future_cancel because fdb_future_destroy will take care of everything
                        handle.Dispose();
                        // also, don't keep a reference on the callback because it won't be needed
                        m_resultSelector = null;
                        this.TrySetCanceled();
                        return;
                    }

                    // token still active
                    RegisterForCancellation(ct);
                }

#if DEBUG_FUTURES
                Debug.WriteLine("Future<" + typeof(T).Name + "> 0x" + handle.Handle.ToString("x") + " will complete later");
#endif

                TrySetFlag(FdbFuture.Flags.READY);

                // add this instance to the list of pending futures
                var prm = RegisterCallback(this);

                // register the callback handler
                var err = FdbNative.FutureSetCallback(handle, CallbackHandler, prm);
                if (Fdb.Failed(err))
                {                 // uhoh
#if DEBUG_FUTURES
                    Debug.WriteLine("Failed to set callback for Future<" + typeof(T).Name + "> 0x" + handle.Handle.ToString("x") + " !!!");
#endif
                    throw Fdb.MapToException(err);
                }
            }
            catch
            {
                // this is bad news, since we are in the constructor, we need to clear everything
                SetFlag(FdbFuture.Flags.DISPOSED);
                UnregisterCancellationRegistration();
                UnregisterCallback(this);

                // kill the future handle
                m_handle.Dispose();

                // this is technically not needed, but just to be safe...
                this.TrySetCanceled();

                throw;
            }
            GC.KeepAlive(this);
        }
 protected override void CloseHandles()
 {
     m_handle?.Dispose();
 }