cotis 0.1.0-alpha

Modular Rust UI framework core
Documentation
//! Launch hooks for environments where the application entry point is not under the
//! interface developer's control.
//!
//! Some renderers and runtimes own program startup. For example, a web renderer may need
//! to initialize its runtime, bind to the host environment, and only then hand control
//! to application code. In those cases the platform integrator calls `cotis_launch()`
//! or `cotis_launch_async()`, and Cotis forwards execution to the developer's entry
//! through exported hook symbols.
//!
//! Application developers mark their entry function with the `cotis-macros` attributes
//! `#[cotis_start]` or `#[cotis_start_async]`. Those macros generate the `extern "Rust"`
//! hook symbols expected by this module.
//!
//! Enable the `app_launch` feature on the `cotis` crate when using this launch path.
//!
//! # Application developer
//!
//! Depend on `cotis-macros`, annotate your entry function, and implement your UI setup
//! as you would for a normal `main`:
//!
//! ```rust,ignore
//! use cotis_macros::cotis_start;
//!
//! #[cotis_start]
//! fn start() {
//!     // Create CotisApp, then run your frame loop.
//! }
//! ```
//!
//! For async entry points:
//!
//! ```rust,ignore
//! use cotis_macros::cotis_start_async;
//!
//! #[cotis_start_async]
//! async fn start() {
//!     // Create CotisApp, then await async frame computation.
//! }
//! ```
//!
//! `#[cotis_start]` and `#[cotis_start_async]` require a parameterless function. Async
//! functions must use `#[cotis_start_async]`, not `#[cotis_start]`.
//!
//! # Platform integrator
//!
//! After your renderer/runtime setup is complete, call the matching launch function:
//!
//! ```rust,ignore
//! // Synchronous host startup (for apps using #[cotis_start])
//! unsafe { cotis::launch::cotis_launch() };
//! ```
//!
//! ```rust,ignore
//! // Asynchronous host startup (for apps using #[cotis_start_async])
//! cotis::launch::cotis_launch_async().await;
//! ```
//!
//! Without the `app_launch` feature, both launch functions compile but do nothing.

#[cfg(feature = "app_launch")]
use std::pin::Pin;

/// Dispatches to the application entry hook registered by `#[cotis_start]`.
///
/// This is intended for platform integrators that control startup, not for application
/// developers writing UI code directly.
///
/// When the `app_launch` feature is enabled, this calls `hooks::__cotis_launch_hook`,
/// which is typically generated by `#[cotis_start]` in the `cotis-macros` crate on the
/// developer's entry function.
///
/// Without the `app_launch` feature this function is a no-op.
///
/// # Safety
///
/// This forwards to an externally provided `extern "Rust"` hook that must be correctly
/// defined and safe to invoke. Calling this is only sound when that hook was exported
/// by a trusted `#[cotis_start]` entry in the linked application.
///
/// # Examples
///
/// ```rust,ignore
/// // Called by a renderer host after runtime initialization.
/// unsafe { cotis::launch::cotis_launch() };
/// ```
pub unsafe fn cotis_launch() {
    #[cfg(feature = "app_launch")]
    unsafe {
        hooks::__cotis_launch_hook()
    };
}

/// Dispatches to the application entry hook registered by `#[cotis_start_async]`.
///
/// This is intended for platform integrators that control async startup, not for
/// application developers writing UI code directly.
///
/// When the `app_launch` feature is enabled, this awaits `hooks::__cotis_launch_async_hook`,
/// which is typically generated by `#[cotis_start_async]` in the `cotis-macros` crate.
///
/// Without the `app_launch` feature this function is a no-op.
///
/// # Examples
///
/// ```rust,ignore
/// // Called by a renderer host after async runtime initialization.
/// cotis::launch::cotis_launch_async().await;
/// ```
pub async fn cotis_launch_async() {
    #[cfg(feature = "app_launch")]
    unsafe {
        let future = hooks::__cotis_launch_async_hook();
        let future = Pin::from(future);
        future.await;
    }
}

#[cfg(feature = "app_launch")]
/// Symbols exported by `#[cotis_start]` / `#[cotis_start_async]` and invoked by the
/// launch functions in this module.
///
/// Platform code should call [`cotis_launch`] or [`cotis_launch_async`] instead of
/// calling these hooks directly.
pub mod hooks {
    use core::future::Future;

    unsafe extern "Rust" {
        /// Hook generated by `#[cotis_start]`; called by [`super::cotis_launch`].
        pub fn __cotis_launch_hook();

        /// Hook generated by `#[cotis_start_async]`; called by [`super::cotis_launch_async`].
        pub fn __cotis_launch_async_hook() -> Box<dyn Future<Output = ()>>;
    }
}