pub const ext = @import("ext.zig");
const dex = @This();

const std = @import("std");
const compat = @import("compat");
const gio = @import("gio2");
const gobject = @import("gobject2");
const glib = @import("glib2");
const gmodule = @import("gmodule2");
pub const AsyncPair = opaque {
    pub const Parent = dex.Future;
    pub const Implements = [_]type{};
    pub const Class = opaque {
        pub const Instance = AsyncPair;
    };
    pub const virtual_methods = struct {};

    pub const properties = struct {};

    pub const signals = struct {};

    extern fn dex_async_pair_new(p_instance: ?*anyopaque, p_info: *const dex.AsyncPairInfo) *dex.AsyncPair;
    pub const new = dex_async_pair_new;

    /// Gets the cancellable for the async pair.
    ///
    /// If the `dex.AsyncPair` is discarded by its callers, then it will
    /// automatically be cancelled using `gio.Cancellable.cancel`.
    extern fn dex_async_pair_get_cancellable(p_async_pair: *AsyncPair) *gio.Cancellable;
    pub const getCancellable = dex_async_pair_get_cancellable;

    extern fn dex_async_pair_return_boolean(p_async_pair: *AsyncPair, p_value: c_int) void;
    pub const returnBoolean = dex_async_pair_return_boolean;

    /// Resolves `async_pair` with `instance`.
    extern fn dex_async_pair_return_boxed(p_async_pair: *AsyncPair, p_boxed_type: usize, p_instance: ?*anyopaque) void;
    pub const returnBoxed = dex_async_pair_return_boxed;

    /// Rejects `async_pair` with `error`.
    ///
    /// This function is meant to be used when manually wrapping
    /// various `gio.AsyncReadyCallback` based API.
    ///
    /// The ownership of `error` is taken when calling this function.
    extern fn dex_async_pair_return_error(p_async_pair: *AsyncPair, p_error: *glib.Error) void;
    pub const returnError = dex_async_pair_return_error;

    extern fn dex_async_pair_return_int64(p_async_pair: *AsyncPair, p_value: i64) void;
    pub const returnInt64 = dex_async_pair_return_int64;

    /// Resolves `async_pair` with a value of `instance`.
    ///
    /// This function is meant to be used when manually wrapping
    /// various `gio.AsyncReadyCallback` based API.
    ///
    /// The ownership of `instance` is taken when calling this function.
    extern fn dex_async_pair_return_object(p_async_pair: *AsyncPair, p_instance: *gobject.Object) void;
    pub const returnObject = dex_async_pair_return_object;

    /// Resolves `async_pair` with `value`.
    extern fn dex_async_pair_return_string(p_async_pair: *AsyncPair, p_value: ?[*:0]u8) void;
    pub const returnString = dex_async_pair_return_string;

    extern fn dex_async_pair_return_uint64(p_async_pair: *AsyncPair, p_value: u64) void;
    pub const returnUint64 = dex_async_pair_return_uint64;

    /// Resolves `async_pair` with `variant`.
    extern fn dex_async_pair_return_variant(p_async_pair: *AsyncPair, p_variant: *glib.Variant) void;
    pub const returnVariant = dex_async_pair_return_variant;

    /// Sets whether or not the future should cancel the async operation when
    /// the future is discarded. This happens when no more futures are awaiting
    /// the completion of this future.
    extern fn dex_async_pair_set_cancel_on_discard(p_async_pair: *AsyncPair, p_cancel_on_discard: c_int) void;
    pub const setCancelOnDiscard = dex_async_pair_set_cancel_on_discard;

    extern fn dex_async_pair_get_type() usize;
    pub const getGObjectType = dex_async_pair_get_type;

    pub fn as(p_instance: *AsyncPair, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// `DexAsyncResult` is used to integrate a `DexFuture` with `GAsyncResult`.
///
/// Use this class when you need to expose the traditional async/finish
/// behavior of `GAsyncResult`.
pub const AsyncResult = opaque {
    pub const Parent = gobject.Object;
    pub const Implements = [_]type{gio.AsyncResult};
    pub const Class = dex.AsyncResultClass;
    pub const virtual_methods = struct {};

    pub const properties = struct {};

    pub const signals = struct {};

    /// Creates a new `dex.AsyncResult`.
    ///
    /// Use this to integrate with `GAsyncResult` by calling
    /// `dex.AsyncResult.await` to complete when the
    /// dependent future resolves.
    extern fn dex_async_result_new(p_source_object: ?*anyopaque, p_cancellable: ?*gio.Cancellable, p_callback: ?gio.AsyncReadyCallback, p_user_data: ?*anyopaque) *dex.AsyncResult;
    pub const new = dex_async_result_new;

    /// Tracks the result of `future` and uses the value to complete `async_result`,
    /// eventually calling the registered `gio.AsyncReadyCallback`.
    extern fn dex_async_result_await(p_async_result: *AsyncResult, p_future: *dex.Future) void;
    pub const await = dex_async_result_await;

    /// Gets the future for the `dex.AsyncResult`, or `NULL` if a future
    /// is not available.
    extern fn dex_async_result_dup_future(p_async_result: *AsyncResult) ?*dex.Future;
    pub const dupFuture = dex_async_result_dup_future;

    extern fn dex_async_result_get_name(p_async_result: *AsyncResult) [*:0]const u8;
    pub const getName = dex_async_result_get_name;

    extern fn dex_async_result_propagate_boolean(p_async_result: *AsyncResult, p_error: ?*?*glib.Error) c_int;
    pub const propagateBoolean = dex_async_result_propagate_boolean;

    extern fn dex_async_result_propagate_double(p_async_result: *AsyncResult, p_error: ?*?*glib.Error) f64;
    pub const propagateDouble = dex_async_result_propagate_double;

    extern fn dex_async_result_propagate_int(p_async_result: *AsyncResult, p_error: ?*?*glib.Error) isize;
    pub const propagateInt = dex_async_result_propagate_int;

    extern fn dex_async_result_propagate_pointer(p_async_result: *AsyncResult, p_error: ?*?*glib.Error) ?*anyopaque;
    pub const propagatePointer = dex_async_result_propagate_pointer;

    extern fn dex_async_result_set_name(p_async_result: *AsyncResult, p_name: [*:0]const u8) void;
    pub const setName = dex_async_result_set_name;

    extern fn dex_async_result_set_priority(p_async_result: *AsyncResult, p_priority: c_int) void;
    pub const setPriority = dex_async_result_set_priority;

    extern fn dex_async_result_set_static_name(p_async_result: *AsyncResult, p_name: [*:0]const u8) void;
    pub const setStaticName = dex_async_result_set_static_name;

    extern fn dex_async_result_get_type() usize;
    pub const getGObjectType = dex_async_result_get_type;

    extern fn g_object_ref(p_self: *dex.AsyncResult) void;
    pub const ref = g_object_ref;

    extern fn g_object_unref(p_self: *dex.AsyncResult) void;
    pub const unref = g_object_unref;

    pub fn as(p_instance: *AsyncResult, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// `DexBlock` represents a callback closure that can be scheduled to run
/// within a specific `glib.MainContext`.
///
/// You create these by chaining futures together using `dex.Future.then`,
/// `dex.Future.@"catch"`, `dex.Future.finally` and similar.
pub const Block = opaque {
    pub const Parent = dex.Future;
    pub const Implements = [_]type{};
    pub const Class = opaque {
        pub const Instance = Block;
    };
    pub const virtual_methods = struct {};

    pub const properties = struct {};

    pub const signals = struct {};

    /// Gets the kind of block.
    ///
    /// The kind of block relates to what situations the block would be
    /// executed such as for handling a future resolution, rejection, or
    /// both.
    extern fn dex_block_get_kind(p_block: *Block) dex.BlockKind;
    pub const getKind = dex_block_get_kind;

    /// Gets the scheduler to use when executing a block.
    extern fn dex_block_get_scheduler(p_block: *Block) *dex.Scheduler;
    pub const getScheduler = dex_block_get_scheduler;

    extern fn dex_block_get_type() usize;
    pub const getGObjectType = dex_block_get_type;

    pub fn as(p_instance: *Block, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// `DexCancellable` is a simple cancellation primitive which allows
/// for you to create `dex.Future` that will reject upon cancellation.
///
/// Use this combined with other futures using `dex.Future.allRace`
/// to create a future that resolves when all other futures complete
/// or `dex.Cancellable.cancel` is called to reject.
pub const Cancellable = opaque {
    pub const Parent = dex.Future;
    pub const Implements = [_]type{};
    pub const Class = opaque {
        pub const Instance = Cancellable;
    };
    pub const virtual_methods = struct {};

    pub const properties = struct {};

    pub const signals = struct {};

    /// Create a new cancellable
    extern fn dex_cancellable_new() *dex.Cancellable;
    pub const new = dex_cancellable_new;

    /// Creates a new `dex.Cancellable` that will reject
    /// when `cancellable` is cancelled or
    /// `dex.Cancellable.cancel` is called.
    extern fn dex_cancellable_new_from_cancellable(p_cancellable: ?*gio.Cancellable) *dex.Cancellable;
    pub const newFromCancellable = dex_cancellable_new_from_cancellable;

    /// Rejects `cancellable`.
    ///
    /// Any future that is dependent on this cancellable will be notified
    /// of the rejection. For some futures, that may cause them to also
    /// reject or resolve.
    extern fn dex_cancellable_cancel(p_cancellable: *Cancellable) void;
    pub const cancel = dex_cancellable_cancel;

    extern fn dex_cancellable_get_type() usize;
    pub const getGObjectType = dex_cancellable_get_type;

    pub fn as(p_instance: *Cancellable, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

pub const Channel = opaque {
    pub const Parent = dex.Object;
    pub const Implements = [_]type{};
    pub const Class = opaque {
        pub const Instance = Channel;
    };
    pub const virtual_methods = struct {};

    pub const properties = struct {};

    pub const signals = struct {};

    /// Creates a new `dex.Channel`.
    ///
    /// If capacity is non-zero, it can be used to limit the size of the channel
    /// so that functions can asynchronously stall until items have been removed
    /// from the channel. This is useful in buffering situations so that the
    /// producer does not outpace the consumer.
    extern fn dex_channel_new(p_capacity: c_uint) *dex.Channel;
    pub const new = dex_channel_new;

    extern fn dex_channel_can_receive(p_channel: *Channel) c_int;
    pub const canReceive = dex_channel_can_receive;

    extern fn dex_channel_can_send(p_channel: *Channel) c_int;
    pub const canSend = dex_channel_can_send;

    extern fn dex_channel_close_receive(p_channel: *Channel) void;
    pub const closeReceive = dex_channel_close_receive;

    extern fn dex_channel_close_send(p_channel: *Channel) void;
    pub const closeSend = dex_channel_close_send;

    /// Receives the next item from the channel.
    ///
    /// The resulting future will resolve or reject when an item is available
    /// to the channel or when send side has closed (in that order).
    extern fn dex_channel_receive(p_channel: *Channel) *dex.Future;
    pub const receive = dex_channel_receive;

    /// Will attempt to receive all items in the channel as a `dex.FutureSet`.
    ///
    /// If the receive side of the channel is closed, then the future will
    /// reject with an error.
    ///
    /// If there are items in the queue, then they will be returned as part
    /// of a `dex.FutureSet` containing each of the futures.
    ///
    /// Otherwise, a `dex.FutureSet` will be returned which will resolve or
    /// reject when the next item is available in the channel (or the send
    /// or receive sides are closed).
    extern fn dex_channel_receive_all(p_channel: *Channel) *dex.Future;
    pub const receiveAll = dex_channel_receive_all;

    /// Queues `future` into the channel.
    ///
    /// The other end of the channel can receive the future (or a future that will
    /// eventually resolve to `future`) using `dex.Channel.receive`.
    ///
    /// This function returns a `dex.Future` that will resolve when the channels
    /// capacity is low enough to queue more items.
    ///
    /// If the send side of the channel is closed, the returned `dex.Future` will be
    /// rejected with `DEX_ERROR_CHANNEL_CLOSED`.
    extern fn dex_channel_send(p_channel: *Channel, p_future: *dex.Future) *dex.Future;
    pub const send = dex_channel_send;

    extern fn dex_channel_get_type() usize;
    pub const getGObjectType = dex_channel_get_type;

    pub fn as(p_instance: *Channel, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// `dex.DBusInterfaceSkeleton` provides integration between libdex and the GDBus
/// codegen. If the gdbus-codegen dex extension is used, all generated
/// InterfaceSkeletons inherit from `dex.DBusInterfaceSkeleton` instead of
/// `gio.DBusInterfaceSkeleton`, which allows the use of the API exposed here.
pub const DBusInterfaceSkeleton = extern struct {
    pub const Parent = gio.DBusInterfaceSkeleton;
    pub const Implements = [_]type{gio.DBusInterface};
    pub const Class = dex.DBusInterfaceSkeletonClass;
    f_parent_instance: gio.DBusInterfaceSkeleton,

    pub const virtual_methods = struct {};

    pub const properties = struct {};

    pub const signals = struct {};

    /// Cancels all in-flight fibers.
    extern fn dex_dbus_interface_skeleton_cancel(p_interface_: *DBusInterfaceSkeleton) void;
    pub const cancel = dex_dbus_interface_skeleton_cancel;

    /// Gets the `dex.DBusInterfaceSkeletonFlags` that describes the behavior
    /// of `interface_`
    extern fn dex_dbus_interface_skeleton_get_flags(p_interface_: *DBusInterfaceSkeleton) dex.DBusInterfaceSkeletonFlags;
    pub const getFlags = dex_dbus_interface_skeleton_get_flags;

    /// Sets flags describing what the behavior of `interface_` should be.
    extern fn dex_dbus_interface_skeleton_set_flags(p_interface_: *DBusInterfaceSkeleton, p_flags: dex.DBusInterfaceSkeletonFlags) void;
    pub const setFlags = dex_dbus_interface_skeleton_set_flags;

    extern fn dex_dbus_interface_skeleton_get_type() usize;
    pub const getGObjectType = dex_dbus_interface_skeleton_get_type;

    extern fn g_object_ref(p_self: *dex.DBusInterfaceSkeleton) void;
    pub const ref = g_object_ref;

    extern fn g_object_unref(p_self: *dex.DBusInterfaceSkeleton) void;
    pub const unref = g_object_unref;

    pub fn as(p_instance: *DBusInterfaceSkeleton, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// `DexDelayed` is a future which will resolve or reject the value of another
/// `dex.Future` when `dex.Delayed.release` is called.
///
/// This allows you to gate the resolution of a future which has already
/// resolved or rejected until a later moment.
pub const Delayed = opaque {
    pub const Parent = dex.Future;
    pub const Implements = [_]type{};
    pub const Class = opaque {
        pub const Instance = Delayed;
    };
    pub const virtual_methods = struct {};

    pub const properties = struct {};

    pub const signals = struct {};

    /// Creates a new `dex.Delayed`
    extern fn dex_delayed_new(p_future: *dex.Future) *dex.Delayed;
    pub const new = dex_delayed_new;

    /// Retrieves the delayed future provided to `dex.Delayed.new`.
    ///
    /// This function can only return a `dex.Future` before
    /// `dex.Delayed.release` is called. After that, the delayed future is
    /// released and this function will return `NULL`.
    extern fn dex_delayed_dup_future(p_delayed: *Delayed) ?*dex.Future;
    pub const dupFuture = dex_delayed_dup_future;

    /// Completes `delayed` using the value provided at construction.
    extern fn dex_delayed_release(p_delayed: *Delayed) void;
    pub const release = dex_delayed_release;

    extern fn dex_delayed_get_type() usize;
    pub const getGObjectType = dex_delayed_get_type;

    pub fn as(p_instance: *Delayed, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// `DexFiber` is a fiber (a stack-based coroutine) which itself is a
/// `dex.Future`.
///
/// When the fiber completes execution it will either resolve or reject the
/// with the result or error.
///
/// You may treat a `DexFiber` like any other `DexFuture` which makes it simple
/// to integrate fibers into other processing chains.
///
/// `DexFiber` are provided their own stack separate from a thread's main stack,
/// and are automatically scheduled as necessary.
///
/// Use `dex.Future.await` and similar functions to await the result of
/// another future within the fiber and the fiber will be suspended allowing
/// another fiber to run and/or the rest of the application's main loop.
///
/// Once a fiber is created, it is pinned to that scheduler. Use
/// `dex.Scheduler.spawn` to create a fiber on a specific scheduler.
pub const Fiber = opaque {
    pub const Parent = dex.Future;
    pub const Implements = [_]type{};
    pub const Class = opaque {
        pub const Instance = Fiber;
    };
    pub const virtual_methods = struct {};

    pub const properties = struct {};

    pub const signals = struct {};

    extern fn dex_fiber_get_type() usize;
    pub const getGObjectType = dex_fiber_get_type;

    pub fn as(p_instance: *Fiber, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// `DexFuture` is the base class representing a future which may resolve with
/// a value or reject with error at some point in the future.
///
/// It is the basis for libdex's concurrency and parallelism model.
///
/// Use futures to represent work in progress and allow consumers to build
/// robust processing chains up front which will complete or fail as futures
/// resolve or reject.
///
/// When running on a `dex.Fiber`, you may use `dex.Future.await`
/// and similar functions to suspend the current thread and return upon
/// completion of the dependent future.
pub const Future = opaque {
    pub const Parent = dex.Object;
    pub const Implements = [_]type{};
    pub const Class = opaque {
        pub const Instance = Future;
    };
    pub const virtual_methods = struct {};

    pub const properties = struct {};

    pub const signals = struct {};

    /// Creates a new `dex.Future` that will resolve or reject when all futures
    /// either resolve or reject.
    ///
    /// This method will return a `dex.FutureSet` which provides API to get
    /// the exact values of the dependent futures. The value of the future
    /// if resolved will be a `G_TYPE_BOOLEAN` of `TRUE`.
    extern fn dex_future_all(p_first_future: *dex.Future, ...) *dex.Future;
    pub const all = dex_future_all;

    /// Creates a new `dex.Future` that will resolve when all futures resolve
    /// or reject as soon as the first future rejects.
    ///
    /// This method will return a `dex.FutureSet` which provides API to get
    /// the exact values of the dependent futures. The value of the future
    /// will be propagated from the resolved or rejected future.
    ///
    /// Since the futures race to complete, some futures retrieved with the
    /// `dex.FutureSet.getFutureAt` API will still be
    /// `DEX_FUTURE_STATUS_PENDING`.
    extern fn dex_future_all_race(p_first_future: *dex.Future, ...) *dex.Future;
    pub const allRace = dex_future_all_race;

    /// Creates a new `dex.Future` that resolves when all futures resolve.
    ///
    /// If any future rejects, the resulting `dex.Future` also rejects immediately.
    extern fn dex_future_all_racev(p_futures: [*]const *dex.Future, p_n_futures: c_uint) *dex.Future;
    pub const allRacev = dex_future_all_racev;

    /// Creates a new `dex.Future` that resolves when all futures resolve.
    ///
    /// The resulting `dex.Future` will not resolve or reject until all futures
    /// have either resolved or rejected.
    extern fn dex_future_allv(p_futures: [*]const *dex.Future, p_n_futures: c_uint) *dex.Future;
    pub const allv = dex_future_allv;

    /// Creates a new `dex.Future` that will resolve when any dependent future
    /// resolves, providing the same result as the resolved future.
    ///
    /// If no futures resolve, then the future will reject.
    extern fn dex_future_any(p_first_future: *dex.Future, ...) *dex.Future;
    pub const any = dex_future_any;

    /// Creates a new `dex.Future` that resolves when the first future resolves.
    ///
    /// If all futures reject, then the `dex.Future` returned will also reject.
    extern fn dex_future_anyv(p_futures: [*]const *dex.Future, p_n_futures: c_uint) *dex.Future;
    pub const anyv = dex_future_anyv;

    /// Calls `callback` when `future` rejects.
    ///
    /// If `future` resolves, then `callback` will not be called.
    extern fn dex_future_catch(p_future: *dex.Future, p_callback: dex.FutureCallback, p_callback_data: ?*anyopaque, p_callback_data_destroy: ?glib.DestroyNotify) *dex.Future;
    pub const @"catch" = dex_future_catch;

    /// Asynchronously calls `callback` when `future` rejects.
    ///
    /// This is similar to `dex.Future.@"catch"` except that it will call
    /// `callback` multiple times as each returned `dex.Future` rejects,
    /// allowing for infinite loops.
    extern fn dex_future_catch_loop(p_future: *dex.Future, p_callback: dex.FutureCallback, p_callback_data: ?*anyopaque, p_callback_data_destroy: ?glib.DestroyNotify) *dex.Future;
    pub const catchLoop = dex_future_catch_loop;

    /// Calls `callback` when `future` resolves or rejects.
    extern fn dex_future_finally(p_future: *dex.Future, p_callback: dex.FutureCallback, p_callback_data: ?*anyopaque, p_callback_data_destroy: ?glib.DestroyNotify) *dex.Future;
    pub const finally = dex_future_finally;

    /// Asynchronously calls `callback` when `future` rejects or resolves.
    ///
    /// This is similar to `dex.Future.finally` except that it will call
    /// `callback` multiple times as each returned `dex.Future` rejects or resolves,
    /// allowing for infinite loops.
    extern fn dex_future_finally_loop(p_future: *dex.Future, p_callback: dex.FutureCallback, p_callback_data: ?*anyopaque, p_callback_data_destroy: ?glib.DestroyNotify) *dex.Future;
    pub const finallyLoop = dex_future_finally_loop;

    /// Creates a new `dex.Future` that resolves or rejects as soon as the
    /// first dependent future resolves or rejects, sharing the same result.
    extern fn dex_future_first(p_first_future: *dex.Future, ...) *dex.Future;
    pub const first = dex_future_first;

    /// Creates a new `dex.Future` that resolves or rejects as soon as the
    /// first dependent future resolves or rejects, sharing the same result.
    extern fn dex_future_firstv(p_futures: [*]const *dex.Future, p_n_futures: c_uint) *dex.Future;
    pub const firstv = dex_future_firstv;

    /// Creates a new `dex.Future` and resolves it with `v_bool`.
    extern fn dex_future_new_for_boolean(p_v_bool: c_int) *dex.Future;
    pub const newForBoolean = dex_future_new_for_boolean;

    /// Creates a new `dex.Future` and resolves it with `v_double`.
    extern fn dex_future_new_for_double(p_v_double: f64) *dex.Future;
    pub const newForDouble = dex_future_new_for_double;

    /// Creates a new rejected future using `errno_` as the value
    /// of errno for the GError.
    ///
    /// The resulting error domain will be `G_IO_ERROR`.
    extern fn dex_future_new_for_errno(p_errno_: c_int) *dex.Future;
    pub const newForErrno = dex_future_new_for_errno;

    /// Creates a read-only `dex.Future` that has rejected.
    extern fn dex_future_new_for_error(p_error: *glib.Error) *dex.Future;
    pub const newForError = dex_future_new_for_error;

    /// Creates a new future that resolves to `fd`.
    ///
    /// This function takes ownership of `fd`.
    extern fn dex_future_new_for_fd(p_fd: c_int) *dex.Future;
    pub const newForFd = dex_future_new_for_fd;

    /// Creates a new `dex.Future` and resolves it with `v_float`.
    extern fn dex_future_new_for_float(p_v_float: f32) *dex.Future;
    pub const newForFloat = dex_future_new_for_float;

    /// Creates a new `dex.Future` and resolves it with `v_int`.
    extern fn dex_future_new_for_int(p_v_int: c_int) *dex.Future;
    pub const newForInt = dex_future_new_for_int;

    /// Creates a new `dex.Future` and resolves it with `v_int64`.
    extern fn dex_future_new_for_int64(p_v_int64: i64) *dex.Future;
    pub const newForInt64 = dex_future_new_for_int64;

    /// Creates a new `dex.Future` that is resolved with `value`.
    extern fn dex_future_new_for_object(p_value: *gobject.Object) *dex.Future;
    pub const newForObject = dex_future_new_for_object;

    /// Creates a new `dex.Future` that is resolved with `pointer` as a `G_TYPE_POINTER`.
    extern fn dex_future_new_for_pointer(p_pointer: ?*anyopaque) *dex.Future;
    pub const newForPointer = dex_future_new_for_pointer;

    /// Creates a new `dex.Future` and resolves it with `string`.
    extern fn dex_future_new_for_string(p_string: [*:0]const u8) *dex.Future;
    pub const newForString = dex_future_new_for_string;

    /// Creates a new `dex.Future` and resolves it with `v_uint`.
    extern fn dex_future_new_for_uint(p_v_uint: c_uint) *dex.Future;
    pub const newForUint = dex_future_new_for_uint;

    /// Creates a new `dex.Future` and resolves it with `v_uint64`.
    extern fn dex_future_new_for_uint64(p_v_uint64: u64) *dex.Future;
    pub const newForUint64 = dex_future_new_for_uint64;

    /// Creates a read-only `dex.Future` that has resolved.
    extern fn dex_future_new_for_value(p_value: *const gobject.Value) *dex.Future;
    pub const newForValue = dex_future_new_for_value;

    /// Creates an infinite future that will never resolve or reject. This can
    /// be useful when you want to mock a situation of "run forever" unless
    /// another future rejects or resolves.
    extern fn dex_future_new_infinite() *dex.Future;
    pub const newInfinite = dex_future_new_infinite;

    /// Creates a new `dex.Future` that is rejected.
    extern fn dex_future_new_reject(p_domain: glib.Quark, p_error_code: c_int, p_format: [*:0]const u8, ...) *dex.Future;
    pub const newReject = dex_future_new_reject;

    /// Creates a new `dex.Future` that is resolved with `value`.
    extern fn dex_future_new_take_boxed(p_boxed_type: usize, p_value: ?*anyopaque) *dex.Future;
    pub const newTakeBoxed = dex_future_new_take_boxed;

    /// Creates a new `dex.Future` that is resolved with `value`.
    extern fn dex_future_new_take_object(p_value: ?*gobject.Object) *dex.Future;
    pub const newTakeObject = dex_future_new_take_object;

    /// Creates a new `dex.Future` and resolves it with `string`.
    extern fn dex_future_new_take_string(p_string: [*:0]u8) *dex.Future;
    pub const newTakeString = dex_future_new_take_string;

    /// Creates a new `dex.Future` that is resolved with `v_variant`.
    extern fn dex_future_new_take_variant(p_v_variant: *glib.Variant) *dex.Future;
    pub const newTakeVariant = dex_future_new_take_variant;

    /// Calls `callback` when `future` resolves.
    ///
    /// If `future` rejects, then `callback` will not be called.
    extern fn dex_future_then(p_future: *dex.Future, p_callback: dex.FutureCallback, p_callback_data: ?*anyopaque, p_callback_data_destroy: ?glib.DestroyNotify) *dex.Future;
    pub const then = dex_future_then;

    /// Asynchronously calls `callback` when `future` resolves.
    ///
    /// This is similar to `dex.Future.then` except that it will call
    /// `callback` multiple times as each returned `dex.Future` resolves or
    /// rejects, allowing for infinite loops.
    extern fn dex_future_then_loop(p_future: *dex.Future, p_callback: dex.FutureCallback, p_callback_data: ?*anyopaque, p_callback_data_destroy: ?glib.DestroyNotify) *dex.Future;
    pub const thenLoop = dex_future_then_loop;

    /// Suspends the current `dex.Fiber` and resumes when `future` has completed.
    ///
    /// If `future` is completed when this function is called, the fiber will handle
    /// the result immediately.
    ///
    /// This function may only be called within a `DexFiber`. To do otherwise will
    /// return `FALSE` and `error` set to `DEX_ERROR_NO_FIBER`.
    ///
    /// It is an error to call this function in a way that would cause
    /// intermediate code to become invalid when resuming the stack. For example,
    /// if a foreach-style function taking a callback was to suspend from the
    /// callback, undefined behavior may occur such as thread-local-storage
    /// having changed.
    extern fn dex_await(p_future: *Future, p_error: ?*?*glib.Error) c_int;
    pub const await = dex_await;

    /// Awaits on `future` and returns the gboolean result.
    ///
    /// If the result is not a `gboolean`, `error` is set.
    extern fn dex_await_boolean(p_future: *Future, p_error: ?*?*glib.Error) c_int;
    pub const awaitBoolean = dex_await_boolean;

    /// Awaits on `future` and returns the `G_TYPE_BOXED` based result.
    extern fn dex_await_boxed(p_future: *Future, p_error: ?*?*glib.Error) ?*anyopaque;
    pub const awaitBoxed = dex_await_boxed;

    /// Awaits on `future` and returns the result as an double.
    ///
    /// The resolved value must be of type `G_TYPE_DOUBLE` or `error` is set.
    extern fn dex_await_double(p_future: *Future, p_error: ?*?*glib.Error) f64;
    pub const awaitDouble = dex_await_double;

    /// Awaits on `future` and returns the enum result.
    ///
    /// If the result is not a `G_TYPE_ENUM`, `error` is set.
    extern fn dex_await_enum(p_future: *Future, p_error: ?*?*glib.Error) c_uint;
    pub const awaitEnum = dex_await_enum;

    /// Awaits on `future` and returns the resulting file-descriptor.
    ///
    /// The resolved value must be of type `DEX_TYPE_FD` or `error` is set.
    extern fn dex_await_fd(p_future: *Future, p_error: ?*?*glib.Error) c_int;
    pub const awaitFd = dex_await_fd;

    /// Awaits on `future` and returns the flags result.
    ///
    /// If the result is not a `G_TYPE_FLAGS`, `error` is set.
    extern fn dex_await_flags(p_future: *Future, p_error: ?*?*glib.Error) c_uint;
    pub const awaitFlags = dex_await_flags;

    /// Awaits on `future` and returns the result as an float.
    ///
    /// The resolved value must be of type `G_TYPE_FLOAT` or `error` is set.
    extern fn dex_await_float(p_future: *Future, p_error: ?*?*glib.Error) f32;
    pub const awaitFloat = dex_await_float;

    /// Awaits on `future` and returns the result as an int.
    ///
    /// The resolved value must be of type `G_TYPE_INT` or `error` is set.
    extern fn dex_await_int(p_future: *Future, p_error: ?*?*glib.Error) c_int;
    pub const awaitInt = dex_await_int;

    /// Awaits on `future` and returns the result as an int64.
    ///
    /// The resolved value must be of type `G_TYPE_INT64` or `error` is set.
    extern fn dex_await_int64(p_future: *Future, p_error: ?*?*glib.Error) i64;
    pub const awaitInt64 = dex_await_int64;

    /// Awaits on `future` and returns the `gobject.Object`-based result.
    extern fn dex_await_object(p_future: *Future, p_error: ?*?*glib.Error) ?*gobject.Object;
    pub const awaitObject = dex_await_object;

    /// Calls `dex.Future.await` and returns the value of
    /// `gobject.Value.getPointer`, otherwise `error` is set if the future
    /// rejected.
    extern fn dex_await_pointer(p_future: *Future, p_error: ?*?*glib.Error) ?*anyopaque;
    pub const awaitPointer = dex_await_pointer;

    /// Awaits on `future` and returns the string result.
    ///
    /// If the result is not a `G_TYPE_STRING`, `error` is set.
    extern fn dex_await_string(p_future: *Future, p_error: ?*?*glib.Error) ?[*:0]u8;
    pub const awaitString = dex_await_string;

    /// Awaits on `future` and returns the result as an uint.
    ///
    /// The resolved value must be of type `G_TYPE_UINT` or `error` is set.
    extern fn dex_await_uint(p_future: *Future, p_error: ?*?*glib.Error) c_uint;
    pub const awaitUint = dex_await_uint;

    /// Awaits on `future` and returns the result as an uint64.
    ///
    /// The resolved value must be of type `G_TYPE_UINT64` or `error` is set.
    extern fn dex_await_uint64(p_future: *Future, p_error: ?*?*glib.Error) u64;
    pub const awaitUint64 = dex_await_uint64;

    /// Awaits on `future` and returns the `G_TYPE_VARIANT` based result.
    extern fn dex_await_variant(p_future: *Future, p_error: ?*?*glib.Error) ?*glib.Variant;
    pub const awaitVariant = dex_await_variant;

    /// Disowns a future, allowing it to run to completion even though there may
    /// be no observer interested in the futures completion or rejection.
    extern fn dex_future_disown(p_future: *Future) void;
    pub const disown = dex_future_disown;

    extern fn dex_future_get_name(p_future: *Future) [*:0]const u8;
    pub const getName = dex_future_get_name;

    extern fn dex_future_get_status(p_future: *Future) dex.FutureStatus;
    pub const getStatus = dex_future_get_status;

    extern fn dex_future_get_value(p_future: *Future, p_error: ?*?*glib.Error) ?*const gobject.Value;
    pub const getValue = dex_future_get_value;

    /// This is a convenience function equivalent to calling
    /// `dex.Future.getStatus` and checking for `DEX_FUTURE_STATUS_PENDING`.
    extern fn dex_future_is_pending(p_future: *Future) c_int;
    pub const isPending = dex_future_is_pending;

    /// This is a convenience function equivalent to calling
    /// `dex.Future.getStatus` and checking for `DEX_FUTURE_STATUS_REJECTED`.
    extern fn dex_future_is_rejected(p_future: *Future) c_int;
    pub const isRejected = dex_future_is_rejected;

    /// This is a convenience function equivalent to calling
    /// `dex.Future.getStatus` and checking for `DEX_FUTURE_STATUS_RESOLVED`.
    extern fn dex_future_is_resolved(p_future: *Future) c_int;
    pub const isResolved = dex_future_is_resolved;

    /// Creates a new list model that will initially be empty and after
    /// `future` resolves contain the items within it.
    extern fn dex_future_list_model_new(p_future: *Future) *gio.ListModel;
    pub const listModelNew = dex_future_list_model_new;

    /// Sets the name of the future with a static/internal string.
    ///
    /// `name` will not be copied, so it must be static/internal which can be done
    /// either by using string literals or by using `glib.internString`.
    extern fn dex_future_set_static_name(p_future: *Future, p_name: [*:0]const u8) void;
    pub const setStaticName = dex_future_set_static_name;

    extern fn dex_future_get_type() usize;
    pub const getGObjectType = dex_future_get_type;

    pub fn as(p_instance: *Future, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// This class provides a `gio.ListModel` implementation that will
/// expand to the contents of another `gio.ListModel` from a
/// `dex.Future`.
pub const FutureListModel = opaque {
    pub const Parent = gobject.Object;
    pub const Implements = [_]type{gio.ListModel};
    pub const Class = dex.FutureListModelClass;
    pub const virtual_methods = struct {};

    pub const properties = struct {};

    pub const signals = struct {};

    /// Gets the future provided when creating the list model.
    extern fn dex_future_list_model_dup_future(p_self: *FutureListModel) *dex.Future;
    pub const dupFuture = dex_future_list_model_dup_future;

    extern fn dex_future_list_model_get_type() usize;
    pub const getGObjectType = dex_future_list_model_get_type;

    extern fn g_object_ref(p_self: *dex.FutureListModel) void;
    pub const ref = g_object_ref;

    extern fn g_object_unref(p_self: *dex.FutureListModel) void;
    pub const unref = g_object_unref;

    pub fn as(p_instance: *FutureListModel, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// `DexFutureSet` represents a set of `dex.Future`.
///
/// You may retrieve each underlying `DexFuture` using
/// `dex.FutureSet.getFutureAt`.
///
/// The `dex.FutureStatus` of of the `DexFutureSet` depends on how the set
/// was created using `dex.Future.all`, `dex.Future.any`, and similar
/// methods.
pub const FutureSet = opaque {
    pub const Parent = dex.Future;
    pub const Implements = [_]type{};
    pub const Class = opaque {
        pub const Instance = FutureSet;
    };
    pub const virtual_methods = struct {};

    pub const properties = struct {};

    pub const signals = struct {};

    /// Gets the `dex.Future` at `position` within `future_set`.
    ///
    /// It is a programmer error to request a `DexFuture` which is outside of the
    /// range of the number of futures contained within the `future_set`. Use
    /// `dex.FutureSet.getSize` to determine the number of `DexFuture` that
    /// are contained within the `dex.FutureSet`.
    extern fn dex_future_set_get_future_at(p_future_set: *FutureSet, p_position: c_uint) *dex.Future;
    pub const getFutureAt = dex_future_set_get_future_at;

    /// Gets the number of futures associated with the `dex.FutureSet`. You
    /// may use `dex.FutureSet.getFutureAt` to obtain the individual
    /// `dex.Future`.
    extern fn dex_future_set_get_size(p_future_set: *FutureSet) c_uint;
    pub const getSize = dex_future_set_get_size;

    /// Gets the result from a `dex.Future` that is part of the
    /// `dex.FutureSet`.
    extern fn dex_future_set_get_value_at(p_future_set: *FutureSet, p_position: c_uint, p_error: ?*?*glib.Error) ?*const gobject.Value;
    pub const getValueAt = dex_future_set_get_value_at;

    extern fn dex_future_set_get_type() usize;
    pub const getGObjectType = dex_future_set_get_type;

    pub fn as(p_instance: *FutureSet, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// `DexMainScheduler` is the scheduler used on the default thread of an
/// application. It is meant to integrate with your main loop.
///
/// This scheduler does the bulk of the work in an application.
///
/// Use `dex.ThreadPoolScheduler` when you want to offload work to a thread
/// and still use future-based programming.
pub const MainScheduler = opaque {
    pub const Parent = dex.Scheduler;
    pub const Implements = [_]type{};
    pub const Class = opaque {
        pub const Instance = MainScheduler;
    };
    pub const virtual_methods = struct {};

    pub const properties = struct {};

    pub const signals = struct {};

    extern fn dex_main_scheduler_get_type() usize;
    pub const getGObjectType = dex_main_scheduler_get_type;

    pub fn as(p_instance: *MainScheduler, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// `DexObject` is the basic building block of types defined within
/// libdex. Futures, Schedulers, and Channels all inherit from `DexObject`
/// which provides features like thread-safe weak pointers and memory
/// management operations.
///
/// Objects that are integrating with GIO instead inherit from their
/// natural type in GIO.
pub const Object = opaque {
    pub const Parent = gobject.TypeInstance;
    pub const Implements = [_]type{};
    pub const Class = opaque {
        pub const Instance = Object;
    };
    pub const virtual_methods = struct {};

    pub const properties = struct {};

    pub const signals = struct {};

    /// Acquires a reference on the given object, and increases its reference count by one.
    extern fn dex_ref(p_object: *Object) *dex.Object;
    pub const ref = dex_ref;

    /// Releases a reference on the given object, and decreases its reference count by one.
    ///
    /// If it was the last reference, the resources associated to the instance are freed.
    extern fn dex_unref(p_object: *Object) void;
    pub const unref = dex_unref;

    extern fn dex_object_get_type() usize;
    pub const getGObjectType = dex_object_get_type;

    pub fn as(p_instance: *Object, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// `DexPromise` is a convenient `dex.Future` for propagating a result or
/// rejection in application and library code.
///
/// Use this when there is not a more specialized `DexFuture` for your needs to
/// propagate a result or rejection to the caller in an asynchronous fashion.
pub const Promise = opaque {
    pub const Parent = dex.Future;
    pub const Implements = [_]type{};
    pub const Class = opaque {
        pub const Instance = Promise;
    };
    pub const virtual_methods = struct {};

    pub const properties = struct {};

    pub const signals = struct {};

    /// Creates a new promise which may be completed or rejected
    /// using the available methods.
    extern fn dex_promise_new() *dex.Promise;
    pub const new = dex_promise_new;

    /// Creates a new `dex.Promise` that can propagate cancellation if the
    /// promise is discarded.
    ///
    /// This can be used to plumb cancellation between promises and
    /// `gio.AsyncReadyCallback` based APIs.
    extern fn dex_promise_new_cancellable() *dex.Promise;
    pub const newCancellable = dex_promise_new_cancellable;

    /// Gets a `gio.Cancellable` that will cancel when the promise has
    /// been discarded (and therefore result no longer necessary).
    ///
    /// This is useful when manually implementing wrappers around various
    /// `gio.AsyncReadyCallback` based API.
    ///
    /// If `promise` was created with `dex.Promise.new`, then `NULL` is returned.
    extern fn dex_promise_get_cancellable(p_promise: *Promise) ?*gio.Cancellable;
    pub const getCancellable = dex_promise_get_cancellable;

    /// Marks the promise as rejected, indicating a failure.
    extern fn dex_promise_reject(p_promise: *Promise, p_error: *glib.Error) void;
    pub const reject = dex_promise_reject;

    /// Sets the result for a `dex.Promise`.
    extern fn dex_promise_resolve(p_promise: *Promise, p_value: *const gobject.Value) void;
    pub const resolve = dex_promise_resolve;

    /// Resolve promise to `value`.
    extern fn dex_promise_resolve_boolean(p_promise: *Promise, p_value: c_int) void;
    pub const resolveBoolean = dex_promise_resolve_boolean;

    extern fn dex_promise_resolve_boxed(p_promise: *Promise, p_boxed_type: usize, p_instance: ?*anyopaque) void;
    pub const resolveBoxed = dex_promise_resolve_boxed;

    /// Resolve promise to `value`.
    extern fn dex_promise_resolve_double(p_promise: *Promise, p_value: f64) void;
    pub const resolveDouble = dex_promise_resolve_double;

    /// Resolves the promise to `fd`.
    ///
    /// The file-descriptor may be `dup`'d by this function and
    /// `fd` closed immediately.
    ///
    /// Use `dex.Future.awaitFd` or similar to retrieve the resolved FD.
    extern fn dex_promise_resolve_fd(p_promise: *Promise, p_fd: c_int) void;
    pub const resolveFd = dex_promise_resolve_fd;

    /// Resolve promise to `value`.
    extern fn dex_promise_resolve_float(p_promise: *Promise, p_value: f32) void;
    pub const resolveFloat = dex_promise_resolve_float;

    /// Resolve promise to `value`.
    extern fn dex_promise_resolve_int(p_promise: *Promise, p_value: c_int) void;
    pub const resolveInt = dex_promise_resolve_int;

    /// Resolve promise to `value`.
    extern fn dex_promise_resolve_int64(p_promise: *Promise, p_value: i64) void;
    pub const resolveInt64 = dex_promise_resolve_int64;

    /// Resolve promise to `value`.
    extern fn dex_promise_resolve_long(p_promise: *Promise, p_value: c_long) void;
    pub const resolveLong = dex_promise_resolve_long;

    extern fn dex_promise_resolve_object(p_promise: *Promise, p_object: ?*gobject.Object) void;
    pub const resolveObject = dex_promise_resolve_object;

    extern fn dex_promise_resolve_string(p_promise: *Promise, p_value: [*:0]u8) void;
    pub const resolveString = dex_promise_resolve_string;

    /// Resolve promise to `value`.
    extern fn dex_promise_resolve_uint(p_promise: *Promise, p_value: c_uint) void;
    pub const resolveUint = dex_promise_resolve_uint;

    /// Resolve promise to `value`.
    extern fn dex_promise_resolve_uint64(p_promise: *Promise, p_value: u64) void;
    pub const resolveUint64 = dex_promise_resolve_uint64;

    /// Resolve promise to `value`.
    extern fn dex_promise_resolve_ulong(p_promise: *Promise, p_value: c_long) void;
    pub const resolveUlong = dex_promise_resolve_ulong;

    /// If `variant` is floating, its reference is consumed.
    extern fn dex_promise_resolve_variant(p_promise: *Promise, p_variant: ?*glib.Variant) void;
    pub const resolveVariant = dex_promise_resolve_variant;

    extern fn dex_promise_get_type() usize;
    pub const getGObjectType = dex_promise_get_type;

    pub fn as(p_instance: *Promise, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// `DexScheduler` is the base class used by schedulers.
///
/// Schedulers are responsible for ensuring asynchronous IO requests and
/// completions are processed. They also schedule closures to be run as part
/// of future result propagation. Additionally, they manage `dex.Fiber`
/// execution and suspension.
///
/// Specialized schedulers such as `dex.ThreadPoolScheduler` will do this
/// for a number of threads and dispatch new work between them.
pub const Scheduler = opaque {
    pub const Parent = dex.Object;
    pub const Implements = [_]type{};
    pub const Class = opaque {
        pub const Instance = Scheduler;
    };
    pub const virtual_methods = struct {};

    pub const properties = struct {};

    pub const signals = struct {};

    /// Gets the default scheduler for the process.
    ///
    /// The default scheduler executes tasks within the default
    /// `glib.MainContext`.  Typically that is the main thread of the
    /// application.
    extern fn dex_scheduler_get_default() *dex.Scheduler;
    pub const getDefault = dex_scheduler_get_default;

    /// Gets the default scheduler for the thread.
    extern fn dex_scheduler_get_thread_default() ?*dex.Scheduler;
    pub const getThreadDefault = dex_scheduler_get_thread_default;

    /// Gets the thread default scheduler with the reference count incremented.
    extern fn dex_scheduler_ref_thread_default() ?*dex.Scheduler;
    pub const refThreadDefault = dex_scheduler_ref_thread_default;

    /// Gets the default main context for a scheduler.
    ///
    /// This may be a different value depending on the calling thread.
    ///
    /// For example, calling this on the `dex.ThreadPoolScheduler` from
    /// outside a worker thread may result in getting a shared
    /// `glib.MainContext` for the process.
    ///
    /// However, calling from a worker thread may give you a `glib.MainContext`
    /// specifically for that thread.
    extern fn dex_scheduler_get_main_context(p_scheduler: *Scheduler) *glib.MainContext;
    pub const getMainContext = dex_scheduler_get_main_context;

    /// Queues `func` to run on `scheduler`.
    extern fn dex_scheduler_push(p_scheduler: *Scheduler, p_func: dex.SchedulerFunc, p_func_data: ?*anyopaque) void;
    pub const push = dex_scheduler_push;

    /// Request `scheduler` to spawn a `dex.Fiber`.
    ///
    /// The fiber will have its own stack and cooperatively schedules among other
    /// fibers sharing the scheduler.
    ///
    /// If `stack_size` is 0, it will set to a sensible default. Otherwise, it is
    /// rounded up to the nearest page size.
    ///
    /// ```c
    /// static DexFuture *
    /// fiber_func (gpointer data)
    /// {
    ///   GInputStream *stream = data;
    ///   g_autoptr(GError) error = NULL;
    ///   g_autoptr(GBytes) bytes = NULL;
    ///
    ///   if (!(bytes = dex_await_boxed (dex_input_stream_read_bytes (stream, 4096, 0), &error)))
    ///     return dex_future_new_for_error (g_steal_pointer (&error));
    ///
    ///   ...
    ///
    ///   return dex_future_new_true ();
    /// }
    ///
    /// DexFuture *
    /// spawn_fiber (GInputStream *stream)
    /// {
    ///   return dex_scheduler_spawn (NULL, 0, fiber_func,
    ///                               g_object_ref (stream),
    ///                               g_object_unref);
    /// }
    /// ```
    extern fn dex_scheduler_spawn(p_scheduler: ?*Scheduler, p_stack_size: usize, p_func: dex.FiberFunc, p_func_data: ?*anyopaque, p_func_data_destroy: ?glib.DestroyNotify) *dex.Future;
    pub const spawn = dex_scheduler_spawn;

    extern fn dex_scheduler_get_type() usize;
    pub const getGObjectType = dex_scheduler_get_type;

    pub fn as(p_instance: *Scheduler, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// `DexStaticFuture` represents a future that is resolved from the initial
/// state.
///
/// Use this when you need to create a future for API reasons but already have
/// the value or rejection at that point.
///
/// `DexStaticFuture` is used internally by functions like
/// `dex.Future.newForBoolean` and similar.
pub const StaticFuture = opaque {
    pub const Parent = dex.Future;
    pub const Implements = [_]type{};
    pub const Class = opaque {
        pub const Instance = StaticFuture;
    };
    pub const virtual_methods = struct {};

    pub const properties = struct {};

    pub const signals = struct {};

    extern fn dex_static_future_get_type() usize;
    pub const getGObjectType = dex_static_future_get_type;

    pub fn as(p_instance: *StaticFuture, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// `DexThreadPoolScheduler` is a `dex.Scheduler` that will dispatch work
/// items and fibers to sub-schedulers on a specific operating system thread.
///
/// `dex.Fiber` will never migrate from the thread they are created on to
/// reduce chances of safety issues involved in tracking state between CPU.
///
/// New work items are placed into a global work queue and then dispatched
/// efficiently to a single thread pool worker using a specialized async
/// semaphore. On modern Linux using io_uring, this wakes up a single worker
/// thread and therefore is not subject to "thundering herd" common with
/// global work queues.
///
/// When a worker creates a new work item, it is placed into a work stealing
/// queue owned by the thread. Other worker threads may steal work items when
/// they have exhausted their own work queue.
pub const ThreadPoolScheduler = opaque {
    pub const Parent = dex.Scheduler;
    pub const Implements = [_]type{};
    pub const Class = opaque {
        pub const Instance = ThreadPoolScheduler;
    };
    pub const virtual_methods = struct {};

    pub const properties = struct {};

    pub const signals = struct {};

    /// Gets the default thread pool scheduler for the instance.
    ///
    /// This function is useful to allow programs and libraries to share
    /// an off-main-thread scheduler without having to coordinate on where
    /// the scheduler instance is created or owned.
    extern fn dex_thread_pool_scheduler_get_default() *dex.Scheduler;
    pub const getDefault = dex_thread_pool_scheduler_get_default;

    /// Creates a new `dex.Scheduler` that executes work items on a thread pool.
    extern fn dex_thread_pool_scheduler_new() *dex.ThreadPoolScheduler;
    pub const new = dex_thread_pool_scheduler_new;

    extern fn dex_thread_pool_scheduler_get_type() usize;
    pub const getGObjectType = dex_thread_pool_scheduler_get_type;

    pub fn as(p_instance: *ThreadPoolScheduler, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// `DexTimeout` is a `dex.Future` that will reject after the configured
/// period of time.
pub const Timeout = opaque {
    pub const Parent = dex.Future;
    pub const Implements = [_]type{};
    pub const Class = opaque {
        pub const Instance = Timeout;
    };
    pub const virtual_methods = struct {};

    pub const properties = struct {};

    pub const signals = struct {};

    /// Creates a new timeout that will reject at a deadline.
    extern fn dex_timeout_new_deadline(p_deadline: i64) *dex.Timeout;
    pub const newDeadline = dex_timeout_new_deadline;

    /// Create a new timeout that will reject in `msec` milliseconds
    extern fn dex_timeout_new_msec(p_msec: c_int) *dex.Timeout;
    pub const newMsec = dex_timeout_new_msec;

    /// Create a new timeout that will reject in `seconds` seconds
    extern fn dex_timeout_new_seconds(p_seconds: c_int) *dex.Timeout;
    pub const newSeconds = dex_timeout_new_seconds;

    /// Create a new timeout that will reject in `usec` microseconds
    extern fn dex_timeout_new_usec(p_usec: i64) *dex.Timeout;
    pub const newUsec = dex_timeout_new_usec;

    /// Postpoone `timeout` to complete at `deadline` in the monotonic
    /// clock. See `glib.getMonotonicTime` for getting the
    /// monotonic time in microseconds.
    extern fn dex_timeout_postpone_until(p_timeout: *Timeout, p_deadline: i64) void;
    pub const postponeUntil = dex_timeout_postpone_until;

    extern fn dex_timeout_get_type() usize;
    pub const getGObjectType = dex_timeout_get_type;

    pub fn as(p_instance: *Timeout, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// `DexUnixSignal` is a `dex.Future` that will resolve when a specific
/// unix signal has been received.
///
/// Use this when you want to handle a signal from your main loop rather than
/// from a resticted operating signal handler.
///
/// On Linux, this uses a signalfd.
pub const UnixSignal = opaque {
    pub const Parent = dex.Future;
    pub const Implements = [_]type{};
    pub const Class = opaque {
        pub const Instance = UnixSignal;
    };
    pub const virtual_methods = struct {};

    pub const properties = struct {};

    pub const signals = struct {};

    /// Creates a new `dex.UnixSignal` that completes when `signum` is delivered
    /// to the process.
    ///
    /// `signum` must be one of SIGHUP, SIGINT, SIGTERM, SIGUSR1, SIGUSR2, or
    /// SIGWINCH.
    ///
    /// This API is only supported on UNIX-like systems.
    extern fn dex_unix_signal_new(p_signum: c_int) *dex.UnixSignal;
    pub const new = dex_unix_signal_new;

    /// Get the signal number that the future represents.
    extern fn dex_unix_signal_get_signum(p_unix_signal: *UnixSignal) c_int;
    pub const getSignum = dex_unix_signal_get_signum;

    extern fn dex_unix_signal_get_type() usize;
    pub const getGObjectType = dex_unix_signal_get_type;

    pub fn as(p_instance: *UnixSignal, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

pub const AioContext = opaque {
    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

pub const AsyncPairInfo = extern struct {
    f_async: ?*anyopaque,
    f_finish: ?*anyopaque,
    f_return_type: usize,
    f__reserved: [13]*anyopaque,

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

pub const AsyncResultClass = extern struct {
    pub const Instance = dex.AsyncResult;

    f_parent_class: gobject.ObjectClass,

    pub fn as(p_instance: *AsyncResultClass, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

pub const DBusInterfaceSkeletonClass = extern struct {
    pub const Instance = dex.DBusInterfaceSkeleton;

    f_parent_class: gio.DBusInterfaceSkeletonClass,

    pub fn as(p_instance: *DBusInterfaceSkeletonClass, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

pub const FutureListModelClass = extern struct {
    pub const Instance = dex.FutureListModel;

    f_parent_class: gobject.ObjectClass,

    pub fn as(p_instance: *FutureListModelClass, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

pub const BlockKind = enum(c_int) {
    then = 1,
    @"catch" = 2,
    finally = 3,
    _,

    extern fn dex_block_kind_get_type() usize;
    pub const getGObjectType = dex_block_kind_get_type;

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

pub const Error = enum(c_int) {
    unknown = 0,
    channel_closed = 1,
    dependency_failed = 2,
    fiber_exited = 3,
    no_fiber = 4,
    pending = 5,
    semaphore_closed = 6,
    timed_out = 7,
    type_mismatch = 8,
    type_not_supported = 9,
    fiber_cancelled = 10,
    _,

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

pub const FutureStatus = enum(c_int) {
    pending = 0,
    resolved = 1,
    rejected = 2,
    _,

    extern fn dex_future_status_get_type() usize;
    pub const getGObjectType = dex_future_status_get_type;

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// Flags describing the behavior of a `gio.DBusInterfaceSkeleton` instance.
pub const DBusInterfaceSkeletonFlags = packed struct(c_uint) {
    handle_method_invocations_in_fiber: bool = false,
    _padding1: bool = false,
    _padding2: bool = false,
    _padding3: bool = false,
    _padding4: bool = false,
    _padding5: bool = false,
    _padding6: bool = false,
    _padding7: bool = false,
    _padding8: bool = false,
    _padding9: bool = false,
    _padding10: bool = false,
    _padding11: bool = false,
    _padding12: bool = false,
    _padding13: bool = false,
    _padding14: bool = false,
    _padding15: bool = false,
    _padding16: bool = false,
    _padding17: bool = false,
    _padding18: bool = false,
    _padding19: bool = false,
    _padding20: bool = false,
    _padding21: bool = false,
    _padding22: bool = false,
    _padding23: bool = false,
    _padding24: bool = false,
    _padding25: bool = false,
    _padding26: bool = false,
    _padding27: bool = false,
    _padding28: bool = false,
    _padding29: bool = false,
    _padding30: bool = false,
    _padding31: bool = false,

    pub const flags_none: DBusInterfaceSkeletonFlags = @bitCast(@as(c_uint, 0));
    pub const flags_handle_method_invocations_in_fiber: DBusInterfaceSkeletonFlags = @bitCast(@as(c_uint, 1));

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// An asynchronous ``pread`` wrapper.
///
/// Generally you want to provide `NULL` for the `aio_context` as that
/// will get the default aio context for your scheduler.
extern fn dex_aio_read(p_aio_context: ?*dex.AioContext, p_fd: c_int, p_buffer: [*]u8, p_count: usize, p_offset: i64) *dex.Future;
pub const aioRead = dex_aio_read;

/// An asynchronous ``pwrite`` wrapper.
///
/// Generally you want to provide `NULL` for the `aio_context` as that
/// will get the default aio context for your scheduler.
extern fn dex_aio_write(p_aio_context: ?*dex.AioContext, p_fd: c_int, p_buffer: [*]const u8, p_count: usize, p_offset: i64) *dex.Future;
pub const aioWrite = dex_aio_write;

/// A helper for `gio.AsyncInitable.initAsync`.
extern fn dex_async_initable_init(p_initable: *gio.AsyncInitable, p_io_priority: c_int) *dex.Future;
pub const asyncInitableInit = dex_async_initable_init;

/// Wrapper for `gio.busGet`.
extern fn dex_bus_get(p_bus_type: gio.BusType) *dex.Future;
pub const busGet = dex_bus_get;

/// Wrapper for `gio.busOwnName`.
///
/// Asks the D-Bus broker to own the well-known name `name` on the connection `connection`.
///
/// `out_name_acquired_future` is a future that awaits owning the name and either
/// resolves to true, or rejects with an error.
///
/// `out_name_lost_future` is a future that rejects when the name was lost.
///
/// If either future is canceled, the name will be unowned.
extern fn dex_bus_own_name_on_connection(p_connection: *gio.DBusConnection, p_name: [*:0]const u8, p_flags: gio.BusNameOwnerFlags, p_out_name_acquired_future: ?**dex.Future, p_out_name_lost_future: ?**dex.Future) void;
pub const busOwnNameOnConnection = dex_bus_own_name_on_connection;

/// Reads a line from the data input stream.
///
/// Wraps `gio.DataInputStream.readLineAsync`.
extern fn dex_data_input_stream_read_line(p_stream: *gio.DataInputStream, p_io_priority: c_int) *dex.Future;
pub const dataInputStreamReadLine = dex_data_input_stream_read_line;

/// Wrapper for `gio.DBusConnection.call`.
extern fn dex_dbus_connection_call(p_connection: *gio.DBusConnection, p_bus_name: ?[*:0]const u8, p_object_path: [*:0]const u8, p_interface_name: [*:0]const u8, p_method_name: [*:0]const u8, p_parameters: ?*glib.Variant, p_reply_type: ?*const glib.VariantType, p_flags: gio.DBusCallFlags, p_timeout_msec: c_int) *dex.Future;
pub const dbusConnectionCall = dex_dbus_connection_call;

/// Wrapper for `gio.DBusConnection.callWithUnixFdList`.
extern fn dex_dbus_connection_call_with_unix_fd_list(p_connection: *gio.DBusConnection, p_bus_name: ?[*:0]const u8, p_object_path: [*:0]const u8, p_interface_name: [*:0]const u8, p_method_name: [*:0]const u8, p_parameters: ?*glib.Variant, p_reply_type: ?*const glib.VariantType, p_flags: gio.DBusCallFlags, p_timeout_msec: c_int, p_fd_list: ?*gio.UnixFDList) *dex.Future;
pub const dbusConnectionCallWithUnixFdList = dex_dbus_connection_call_with_unix_fd_list;

/// Asynchronously closes a connection.
extern fn dex_dbus_connection_close(p_connection: *gio.DBusConnection) *dex.Future;
pub const dbusConnectionClose = dex_dbus_connection_close;

/// Wrapper for `gio.DBusConnection.sendMessageWithReply`.
extern fn dex_dbus_connection_send_message_with_reply(p_connection: *gio.DBusConnection, p_message: *gio.DBusMessage, p_flags: gio.DBusSendMessageFlags, p_timeout_msec: c_int, p_out_serial: ?*u32) *dex.Future;
pub const dbusConnectionSendMessageWithReply = dex_dbus_connection_send_message_with_reply;

extern fn dex_error_quark() glib.Quark;
pub const errorQuark = dex_error_quark;

/// Creates a new GSource that will fire when `events` is satisfied.
///
/// This is primarily useful when integrating with legacy systems on a
/// fiber.
extern fn dex_fd_watch(p_fd: c_int, p_events: c_int) *dex.Future;
pub const fdWatch = dex_fd_watch;

/// Asynchronously copies a file and returns a `dex.Future` which
/// can be observed for the result.
extern fn dex_file_copy(p_source: *gio.File, p_destination: *gio.File, p_flags: gio.FileCopyFlags, p_io_priority: c_int) *dex.Future;
pub const fileCopy = dex_file_copy;

/// Wraps `gio.File.create` as a `dex.Future`.
extern fn dex_file_create(p_file: *gio.File, p_flags: gio.FileCreateFlags, p_io_priority: c_int) *dex.Future;
pub const fileCreate = dex_file_create;

/// Asynchronously deletes a file and returns a `dex.Future` which
/// can be observed for the result.
extern fn dex_file_delete(p_file: *gio.File, p_io_priority: c_int) *dex.Future;
pub const fileDelete = dex_file_delete;

extern fn dex_file_enumerate_children(p_file: *gio.File, p_attributes: [*:0]const u8, p_flags: gio.FileQueryInfoFlags, p_io_priority: c_int) *dex.Future;
pub const fileEnumerateChildren = dex_file_enumerate_children;

/// Wraps `gio.FileEnumerator.nextFilesAsync`.
///
/// Use `dex.Future.awaitBoxed` to await for the result of this function.
///
/// When on a fiber, you can do:
///
/// ```c
/// g_autolist(GFileInfo) infos = dex_await_boxed (dex_file_enumerator_next_files (enumerator, 100, 0), &error);
/// ```
extern fn dex_file_enumerator_next_files(p_file_enumerator: *gio.FileEnumerator, p_num_files: c_int, p_io_priority: c_int) *dex.Future;
pub const fileEnumeratorNextFiles = dex_file_enumerator_next_files;

extern fn dex_file_load_contents_bytes(p_file: *gio.File) *dex.Future;
pub const fileLoadContentsBytes = dex_file_load_contents_bytes;

/// Asynchronously creates a directory and returns `dex.Future` which
/// can be observed for the result.
extern fn dex_file_make_directory(p_file: *gio.File, p_io_priority: c_int) *dex.Future;
pub const fileMakeDirectory = dex_file_make_directory;

/// Creates a directory at `file`.
///
/// If `file` already exists and is a directory, then the future
/// will resolve to `TRUE`.
extern fn dex_file_make_directory_with_parents(p_file: *gio.File) *dex.Future;
pub const fileMakeDirectoryWithParents = dex_file_make_directory_with_parents;

extern fn dex_file_move(p_source: *gio.File, p_destination: *gio.File, p_flags: gio.FileCopyFlags, p_io_priority: c_int, p_progress_callback: gio.FileProgressCallback, p_progress_callback_data: ?*anyopaque, p_progress_callback_data_destroy: ?glib.DestroyNotify) *dex.Future;
pub const fileMove = dex_file_move;

/// Queries to see if `file` exists asynchronously.
extern fn dex_file_query_exists(p_file: *gio.File) *dex.Future;
pub const fileQueryExists = dex_file_query_exists;

extern fn dex_file_query_file_type(p_file: *gio.File, p_flags: gio.FileQueryInfoFlags, p_io_priority: c_int) *dex.Future;
pub const fileQueryFileType = dex_file_query_file_type;

extern fn dex_file_query_info(p_file: *gio.File, p_attributes: [*:0]const u8, p_flags: gio.FileQueryInfoFlags, p_io_priority: c_int) *dex.Future;
pub const fileQueryInfo = dex_file_query_info;

/// Asynchronously opens a file for reading.
extern fn dex_file_read(p_file: *gio.File, p_io_priority: c_int) *dex.Future;
pub const fileRead = dex_file_read;

/// Opens a stream that will replace `file` on disk when the input
/// stream is closed.
extern fn dex_file_replace(p_file: *gio.File, p_etag: ?[*:0]const u8, p_make_backup: c_int, p_flags: gio.FileCreateFlags, p_io_priority: c_int) *dex.Future;
pub const fileReplace = dex_file_replace;

/// Wraps `gio.File.replaceContentsBytesAsync`
extern fn dex_file_replace_contents_bytes(p_file: *gio.File, p_contents: *glib.Bytes, p_etag: ?[*:0]const u8, p_make_backup: c_int, p_flags: gio.FileCreateFlags) *dex.Future;
pub const fileReplaceContentsBytes = dex_file_replace_contents_bytes;

extern fn dex_file_set_attributes(p_file: *gio.File, p_file_info: *gio.FileInfo, p_flags: gio.FileQueryInfoFlags, p_io_priority: c_int) *dex.Future;
pub const fileSetAttributes = dex_file_set_attributes;

/// Locates the first executable named program in the user’s path.
///
/// This runs `glib.findProgramInPath` on a dedicated thread.
extern fn dex_find_program_in_path(p_program: [*:0]const u8) *dex.Future;
pub const findProgramInPath = dex_find_program_in_path;

/// Gets the major version number equivalent to `DEX_MAJOR_VERSION`
/// at compile time of libdex.
extern fn dex_get_major_version() c_int;
pub const getMajorVersion = dex_get_major_version;

/// Gets the micro version number equivalent to `DEX_MICRO_VERSION`
/// at compile time of libdex.
extern fn dex_get_micro_version() c_int;
pub const getMicroVersion = dex_get_micro_version;

extern fn dex_get_min_stack_size() usize;
pub const getMinStackSize = dex_get_min_stack_size;

/// Gets the minor version number equivalent to `DEX_MINOR_VERSION`
/// at compile time of libdex.
extern fn dex_get_minor_version() c_int;
pub const getMinorVersion = dex_get_minor_version;

extern fn dex_get_page_size() usize;
pub const getPageSize = dex_get_page_size;

extern fn dex_init() void;
pub const init = dex_init;

extern fn dex_input_stream_close(p_self: *gio.InputStream, p_io_priority: c_int) *dex.Future;
pub const inputStreamClose = dex_input_stream_close;

/// Reads `count` bytes from an input stream into a pre-allocated `buffer`. The
/// `buffer` must stay valid for the lifetime of this future.
extern fn dex_input_stream_read(p_self: *gio.InputStream, p_buffer: [*]u8, p_count: usize, p_io_priority: c_int) *dex.Future;
pub const inputStreamRead = dex_input_stream_read;

/// Reads `count` bytes from the stream.
extern fn dex_input_stream_read_bytes(p_stream: *gio.InputStream, p_count: usize, p_io_priority: c_int) *dex.Future;
pub const inputStreamReadBytes = dex_input_stream_read_bytes;

extern fn dex_input_stream_skip(p_self: *gio.InputStream, p_count: usize, p_io_priority: c_int) *dex.Future;
pub const inputStreamSkip = dex_input_stream_skip;

extern fn dex_io_stream_close(p_io_stream: *gio.IOStream, p_io_priority: c_int) *dex.Future;
pub const ioStreamClose = dex_io_stream_close;

/// Similar to `glib.mkdirWithParents` but runs on a dedicated thread.
extern fn dex_mkdir_with_parents(p_path: [*:0]const u8, p_mode: c_int) *dex.Future;
pub const mkdirWithParents = dex_mkdir_with_parents;

extern fn dex_output_stream_close(p_self: *gio.OutputStream, p_io_priority: c_int) *dex.Future;
pub const outputStreamClose = dex_output_stream_close;

extern fn dex_output_stream_splice(p_output: *gio.OutputStream, p_input: *gio.InputStream, p_flags: gio.OutputStreamSpliceFlags, p_io_priority: c_int) *dex.Future;
pub const outputStreamSplice = dex_output_stream_splice;

extern fn dex_output_stream_write(p_self: *gio.OutputStream, p_buffer: [*]const u8, p_count: usize, p_io_priority: c_int) *dex.Future;
pub const outputStreamWrite = dex_output_stream_write;

/// Writes `bytes` to `stream`.
///
/// This function takes a reference to `bytes` and may be released after
/// calling this function.
extern fn dex_output_stream_write_bytes(p_stream: *gio.OutputStream, p_bytes: *glib.Bytes, p_io_priority: c_int) *dex.Future;
pub const outputStreamWriteBytes = dex_output_stream_write_bytes;

extern fn dex_resolver_lookup_by_name(p_resolver: *gio.Resolver, p_address: [*:0]const u8) *dex.Future;
pub const resolverLookupByName = dex_resolver_lookup_by_name;

extern fn dex_socket_client_connect(p_socket_client: *gio.SocketClient, p_socket_connectable: *gio.SocketConnectable) *dex.Future;
pub const socketClientConnect = dex_socket_client_connect;

extern fn dex_socket_listener_accept(p_listener: *gio.SocketListener) *dex.Future;
pub const socketListenerAccept = dex_socket_listener_accept;

/// Creates a future that awaits for `subprocess` to complete using
/// `gio.Subprocess.waitCheckAsync`.
extern fn dex_subprocess_wait_check(p_subprocess: *gio.Subprocess) *dex.Future;
pub const subprocessWaitCheck = dex_subprocess_wait_check;

/// Spawns a new thread named `thread_name` running `thread_func` with
/// `user_data` passed to it.
///
/// `thread_func` must return a `dex.Future`.
///
/// If this function is called from a thread that is not running a
/// `dex.Scheduler` then the default scheduler will be used
/// to call `user_data_destroy`.
///
/// If the resulting `dex.Future` has not resolved or rejected,
/// then the same scheduler used to call `user_data_destroy` will be
/// used to propagate the result to the caller.
extern fn dex_thread_spawn(p_thread_name: ?[*:0]const u8, p_thread_func: dex.ThreadFunc, p_user_data: ?*anyopaque, p_user_data_destroy: ?glib.DestroyNotify) *dex.Future;
pub const threadSpawn = dex_thread_spawn;

/// Use this when running on a thread spawned with ``dex.threadSpawn`` and
/// you need to block the thread until `future` has resolved or rejected.
extern fn dex_thread_wait_for(p_future: *dex.Future, p_error: ?*?*glib.Error) c_int;
pub const threadWaitFor = dex_thread_wait_for;

/// This runs `glib.unlink` on a dedicated thread.
extern fn dex_unlink(p_path: [*:0]const u8) *dex.Future;
pub const unlink = dex_unlink;

/// Retrieves the `DexObject` stored inside the given `value`.
extern fn dex_value_dup_object(p_value: *const gobject.Value) ?*dex.Object;
pub const valueDupObject = dex_value_dup_object;

/// Retrieves the `DexObject` stored inside the given `value`.
extern fn dex_value_get_object(p_value: *const gobject.Value) ?*dex.Object;
pub const valueGetObject = dex_value_get_object;

/// Stores the given `DexObject` inside `value`.
///
/// The `gobject.Value` will acquire a reference to the `object`.
extern fn dex_value_set_object(p_value: *gobject.Value, p_object: ?*dex.Object) void;
pub const valueSetObject = dex_value_set_object;

/// Stores the given `DexObject` inside `value`.
///
/// This function transfers the ownership of the `object` to the `GValue`.
extern fn dex_value_take_object(p_value: *gobject.Value, p_object: ?*dex.Object) void;
pub const valueTakeObject = dex_value_take_object;

/// This function prototype is used for spawning fibers. A fiber
/// is a lightweight, cooperative-multitasking feature where the
/// fiber is given its own stack. The fiber runs until it reaches
/// a point of suspension (using `dex.Future.await` or
/// similar) or exits the fiber.
///
/// When suspended, the fiber is placed onto a queue until it is
/// runnable again. Once runnable, the fiber is scheduled to run
/// from within whatever scheduler it was created with.
///
/// See `dex.Scheduler.spawn`
pub const FiberFunc = *const fn (p_user_data: ?*anyopaque) callconv(.c) ?*dex.Future;

/// A `DexFutureCallback` can be executed from a `dex.Block` as response to
/// another `dex.Future` resolving or rejecting.
///
/// The callback will be executed within the scheduler environment the block is
/// created within when using `dex.Future.then`, `dex.Future.@"catch"`
/// `dex.Future.finally`, `dex.Future.all`, and similar functions.
///
/// This is the expected way to handle completion of a future when not using
/// `dex.Fiber` via `dex.Scheduler.spawn`.
pub const FutureCallback = *const fn (p_future: *dex.Future, p_user_data: ?*anyopaque) callconv(.c) ?*dex.Future;

pub const SchedulerFunc = *const fn (p_user_data: ?*anyopaque) callconv(.c) void;

/// A function which will be run on a dedicated thread.
///
/// It must return a `dex.Future` that will eventually resolve
/// to a value or reject with error.
pub const ThreadFunc = *const fn (p_user_data: ?*anyopaque) callconv(.c) *dex.Future;

test {
    @setEvalBranchQuota(100_000);
    std.testing.refAllDecls(@This());
    std.testing.refAllDecls(ext);
}
