crossmist 1.1.2

Efficient and seamless cross-process communication, both synchronously and asynchronously
Documentation
use crossmist::{
    channel, duplex, static_ref, BindValue, Duplex, FnOnceObject, Object, Receiver, Sender,
    StaticRef,
};

#[ctor::ctor]
fn ctor() {
    crossmist::init();
}

#[derive(Debug, PartialEq, Object)]
struct SimplePair {
    x: i32,
    y: i32,
}

#[test]
fn simple() {
    #[crossmist::func]
    fn inner() -> i64 {
        0x123456789abcdef
    }
    assert_eq!(inner.run().unwrap(), 0x123456789abcdef);
}

#[test]
fn ret_string() {
    #[crossmist::func]
    fn inner() -> String {
        "hello".to_string()
    }
    assert_eq!(inner.spawn().unwrap().join().unwrap(), "hello");
}

#[crossmist::func]
fn add_with_arguments_impl(x: i32, y: i32) -> i32 {
    x + y
}

#[test]
fn add_with_arguments_spawn() {
    assert_eq!(
        add_with_arguments_impl.spawn(5, 7).unwrap().join().unwrap(),
        12
    );
}

#[test]
fn add_with_arguments_call() {
    assert_eq!(add_with_arguments_impl.call_object_once((5, 7)), 12);
    #[cfg(feature = "nightly")]
    assert_eq!(add_with_arguments_impl(5, 7), 12);
}

#[test]
fn add_with_template() {
    #[crossmist::func]
    fn inner<T: std::ops::Add<Output = T> + Object + 'static>(x: T, y: T) -> T {
        x + y
    }
    assert_eq!(inner.spawn(5, 7).unwrap().join().unwrap(), 12);
}

#[test]
fn swap_complex_argument() {
    #[crossmist::func]
    fn inner(pair: SimplePair) -> SimplePair {
        SimplePair {
            x: pair.y,
            y: pair.x,
        }
    }
    assert_eq!(
        inner
            .spawn(SimplePair { x: 5, y: 7 })
            .unwrap()
            .join()
            .unwrap(),
        SimplePair { x: 7, y: 5 }
    );
}

#[test]
fn inc_with_boxed() {
    #[crossmist::func]
    fn inner(item: Box<i32>) -> Box<i32> {
        Box::new(*item + 1)
    }
    assert_eq!(*inner.spawn(Box::new(7)).unwrap().join().unwrap(), 8);
}

#[test]
fn inc_with_vec_and_box() {
    #[crossmist::func]
    fn inner(vec: Vec<i32>, box_: Box<[i32]>) -> (i32, i32) {
        (vec.iter().sum(), box_.iter().sum())
    }
    assert_eq!(
        inner
            .spawn(vec![1, 2, 3], Box::new([4, 5, 6]))
            .unwrap()
            .join()
            .unwrap(),
        (6, 15)
    );
}

trait Trait: Object {
    fn say(&self) -> String;
}

#[derive(Object)]
struct ImplA(String);

#[derive(Object)]
struct ImplB(i32);

impl Trait for ImplA {
    fn say(&self) -> String {
        format!("ImplA says: {}", self.0)
    }
}

impl Trait for ImplB {
    fn say(&self) -> String {
        format!("ImplB says: {}", self.0)
    }
}

impl Trait for bool {
    fn say(&self) -> String {
        format!("bool says: {}", self)
    }
}

#[test]
fn with_passed_trait() {
    #[crossmist::func]
    fn inner(arg: Box<dyn Trait>) -> String {
        arg.say()
    }
    assert_eq!(
        inner
            .spawn(Box::new(ImplA("hello".to_string())))
            .unwrap()
            .join()
            .unwrap(),
        "ImplA says: hello"
    );
    assert_eq!(
        inner.spawn(Box::new(ImplB(5))).unwrap().join().unwrap(),
        "ImplB says: 5"
    );
    assert_eq!(
        inner.spawn(Box::new(true)).unwrap().join().unwrap(),
        "bool says: true"
    );
}

#[test]
fn with_passed_fn() {
    #[crossmist::func]
    fn inner(func: Box<dyn crossmist::FnOnceObject<(i32, i32), Output = i32>>) -> i32 {
        #[cfg(feature = "nightly")]
        {
            func(5, 7)
        }
        #[cfg(not(feature = "nightly"))]
        {
            func.call_object_once((5, 7))
        }
    }
    assert_eq!(
        inner
            .spawn(Box::new(add_with_arguments_impl))
            .unwrap()
            .join()
            .unwrap(),
        12
    );
}

#[test]
fn with_passed_bound_fn() {
    #[crossmist::func]
    fn inner(func: Box<dyn crossmist::FnOnceObject<(i32,), Output = i32>>) -> i32 {
        #[cfg(feature = "nightly")]
        {
            func(7)
        }
        #[cfg(not(feature = "nightly"))]
        {
            func.call_object_once((7,))
        }
    }
    assert_eq!(
        inner
            .spawn(Box::new(add_with_arguments_impl.bind_value(5)))
            .unwrap()
            .join()
            .unwrap(),
        12
    );
}

#[test]
fn with_passed_double_bound_fn() {
    #[crossmist::func]
    fn inner(func: Box<dyn crossmist::FnOnceObject<(), Output = i32>>) -> i32 {
        #[cfg(feature = "nightly")]
        {
            func()
        }
        #[cfg(not(feature = "nightly"))]
        {
            func.call_object_once(())
        }
    }
    assert_eq!(
        inner
            .spawn(Box::new(
                add_with_arguments_impl.bind_value(5).bind_value(7)
            ))
            .unwrap()
            .join()
            .unwrap(),
        12
    );
}

#[test]
fn with_passed_rx() {
    #[crossmist::func]
    fn inner(mut rx: Receiver<i32>) -> i32 {
        let a = rx.recv().unwrap().unwrap();
        let b = rx.recv().unwrap().unwrap();
        a - b
    }
    let (mut tx, rx) = channel::<i32>().unwrap();
    let child = inner.spawn(rx).unwrap();
    tx.send(&5).unwrap();
    tx.send(&7).unwrap();
    assert_eq!(child.join().unwrap(), -2);
}

#[test]
fn with_passed_tx() {
    #[crossmist::func]
    fn inner(mut tx: Sender<i32>) {
        tx.send(&5).unwrap();
        tx.send(&7).unwrap();
    }
    let (tx, mut rx) = channel::<i32>().unwrap();
    let child = inner.spawn(tx).unwrap();
    assert_eq!(
        rx.recv().unwrap().unwrap() - rx.recv().unwrap().unwrap(),
        -2
    );
    child.join().unwrap();
}

#[test]
fn with_passed_duplex() {
    #[crossmist::func]
    fn inner(mut chan: Duplex<i32, (i32, i32)>) {
        while let Some((x, y)) = chan.recv().unwrap() {
            chan.send(&(x - y)).unwrap();
        }
    }
    let (mut local, downstream) = duplex::<(i32, i32), i32>().unwrap();
    let child = inner.spawn(downstream).unwrap();
    for (x, y) in [(5, 7), (100, -1), (53, 2354)] {
        local.send(&(x, y)).unwrap();
        assert_eq!(local.recv().unwrap().unwrap(), x - y);
    }
    drop(local);
    child.join().unwrap();
}

#[test]
fn with_passed_nested_channel() {
    #[crossmist::func]
    fn inner(mut chan: Receiver<Receiver<i32>>) -> i32 {
        let mut chan1 = chan.recv().unwrap().unwrap();
        chan1.recv().unwrap().unwrap()
    }
    let (mut tx, rx) = channel::<i32>().unwrap();
    let (mut tx1, rx1) = channel::<Receiver<i32>>().unwrap();
    tx.send(&5).unwrap();
    tx1.send(&rx).unwrap();
    assert_eq!(inner.run(rx1).unwrap(), 5);
}

#[test]
fn exitting() {
    #[crossmist::func]
    fn inner() {
        std::process::exit(0);
    }
    assert_eq!(inner.run().unwrap(), ());
}

#[test]
fn with_static_ref() {
    #[crossmist::func]
    fn inner(a: StaticRef<&'static str>) -> String {
        a.to_string()
    }
    assert_eq!(
        inner
            .run(static_ref!(&'static str, &"Hello, world!"))
            .unwrap(),
        "Hello, world!"
    );
}