llam 0.1.1

Safe, Go-style Rust bindings for the LLAM runtime
//! Safe, macro-first Rust bindings for the LLAM C runtime.
//!
//! The API is intentionally synchronous: `spawn!`, channels, sleeps, and socket
//! I/O look blocking, but managed LLAM tasks park cooperatively underneath.

pub mod abi;
pub mod blocking;
pub mod cancel;
pub mod channel;
pub mod diagnostics;
pub mod error;
pub mod fs;
pub mod io;
pub mod net;
pub mod runtime;
pub mod sync;
pub mod sys;
pub mod task;
pub mod task_local;
pub mod time;

pub use abi::AbiInfo;
pub use cancel::CancelToken;
pub use error::{Error, Result};
pub use runtime::{Profile, Runtime, RuntimeBuilder, RuntimeHandle, RuntimeStats};
pub use task::{JoinError, JoinHandle, SpawnOptions, StackClass, TaskBatch, TaskClass, TaskGroup};
pub use task_local::TaskLocalKey;

pub mod prelude {
    pub use crate::channel;
    pub use crate::runtime::{Profile, Runtime};
    pub use crate::task::{JoinHandle, SpawnOptions, StackClass, TaskBatch, TaskClass};
    pub use crate::task_local::TaskLocalKey;
    pub use crate::{select, spawn, try_spawn, Error, Result};
}

pub mod __private {
    use crate::{run_with_profile, Profile, Result};
    use std::sync::Mutex;

    static TEST_LOCK: Mutex<()> = Mutex::new(());

    pub trait IntoMainResult {
        fn into_main_result(self) -> Result<()>;
    }

    impl IntoMainResult for () {
        fn into_main_result(self) -> Result<()> {
            Ok(())
        }
    }

    impl IntoMainResult for Result<()> {
        fn into_main_result(self) -> Result<()> {
            self
        }
    }

    pub fn run_test<F>(profile: Profile, f: F) -> Result<()>
    where
        F: FnOnce() -> Result<()> + Send + 'static,
    {
        let _guard = TEST_LOCK.lock().expect("LLAM test mutex poisoned");
        run_with_profile(profile, f)
    }
}

pub fn run<F>(f: F) -> Result<()>
where
    F: FnOnce() -> Result<()> + Send + 'static,
{
    run_with_profile(Profile::Balanced, f)
}

pub fn run_with_profile<F>(profile: Profile, f: F) -> Result<()>
where
    F: FnOnce() -> Result<()> + Send + 'static,
{
    Runtime::builder().profile(profile).run(f)
}

pub fn test<F>(f: F) -> Result<()>
where
    F: FnOnce() -> Result<()> + Send + 'static,
{
    test_with_profile(Profile::Balanced, f)
}

pub fn test_with_profile<F>(profile: Profile, f: F) -> Result<()>
where
    F: FnOnce() -> Result<()> + Send + 'static,
{
    __private::run_test(profile, f)
}

#[macro_export]
macro_rules! spawn {
    (class = $class:expr, stack = $stack:expr, cancel = $cancel:expr, move $body:block) => {{
        let opts = $crate::SpawnOptions::new()
            .class($class)
            .stack($stack)
            .cancel($cancel.clone());
        $crate::task::spawn_with(opts, move || $body)
    }};
    (class = $class:expr, stack = $stack:expr, move $body:block) => {{
        let opts = $crate::SpawnOptions::new().class($class).stack($stack);
        $crate::task::spawn_with(opts, move || $body)
    }};
    (class = $class:expr, move $body:block) => {{
        let opts = $crate::SpawnOptions::new().class($class);
        $crate::task::spawn_with(opts, move || $body)
    }};
    (stack = $stack:expr, move $body:block) => {{
        let opts = $crate::SpawnOptions::new().stack($stack);
        $crate::task::spawn_with(opts, move || $body)
    }};
    (move $body:block) => {{
        $crate::task::spawn(move || $body)
    }};
    ($body:block) => {{
        $crate::task::spawn(|| $body)
    }};
}

#[macro_export]
macro_rules! try_spawn {
    (class = $class:expr, stack = $stack:expr, cancel = $cancel:expr, move $body:block) => {{
        let opts = $crate::SpawnOptions::new()
            .class($class)
            .stack($stack)
            .cancel($cancel.clone());
        $crate::task::try_spawn_with(opts, move || $body)
    }};
    (class = $class:expr, stack = $stack:expr, move $body:block) => {{
        let opts = $crate::SpawnOptions::new().class($class).stack($stack);
        $crate::task::try_spawn_with(opts, move || $body)
    }};
    (class = $class:expr, move $body:block) => {{
        let opts = $crate::SpawnOptions::new().class($class);
        $crate::task::try_spawn_with(opts, move || $body)
    }};
    (stack = $stack:expr, move $body:block) => {{
        let opts = $crate::SpawnOptions::new().stack($stack);
        $crate::task::try_spawn_with(opts, move || $body)
    }};
    (move $body:block) => {{
        $crate::task::try_spawn(move || $body)
    }};
    ($body:block) => {{
        $crate::task::try_spawn(|| $body)
    }};
}

#[macro_export]
macro_rules! select {
    ($($arms:tt)+) => {{
        let mut __llam_select = $crate::channel::Select::new();
        $crate::__llam_select_build!(__llam_select; $($arms)+);
        __llam_select.run()
    }};
}

#[doc(hidden)]
#[macro_export]
macro_rules! __llam_select_build {
    ($builder:ident;) => {};
    ($builder:ident; recv($rx:expr) -> $var:ident => $body:expr $(,)?) => {{
        $builder.recv(&$rx, |$var| $body);
    }};
    ($builder:ident; recv($rx:expr) -> $var:ident => $body:expr, $($rest:tt)+) => {{
        $builder.recv(&$rx, |$var| $body);
        $crate::__llam_select_build!($builder; $($rest)+);
    }};
    ($builder:ident; send($tx:expr, $value:expr) => $body:expr $(,)?) => {{
        $builder.send(&$tx, $value, || $body);
    }};
    ($builder:ident; send($tx:expr, $value:expr) => $body:expr, $($rest:tt)+) => {{
        $builder.send(&$tx, $value, || $body);
        $crate::__llam_select_build!($builder; $($rest)+);
    }};
    ($builder:ident; closed($rx:expr) => $body:expr $(,)?) => {{
        $builder.closed(&$rx, || $body);
    }};
    ($builder:ident; closed($rx:expr) => $body:expr, $($rest:tt)+) => {{
        $builder.closed(&$rx, || $body);
        $crate::__llam_select_build!($builder; $($rest)+);
    }};
    ($builder:ident; after($duration:expr) => $body:expr $(,)?) => {{
        $builder.after($duration, || $body);
    }};
    ($builder:ident; after($duration:expr) => $body:expr, $($rest:tt)+) => {{
        $builder.after($duration, || $body);
        $crate::__llam_select_build!($builder; $($rest)+);
    }};
    ($builder:ident; default => $body:expr $(,)?) => {{
        $builder.default(|| $body);
    }};
    ($builder:ident; default => $body:expr, $($rest:tt)+) => {{
        $builder.default(|| $body);
        $crate::__llam_select_build!($builder; $($rest)+);
    }};
}