go-spawn 0.1.2

a library that provides macros to spawn and join threads with minimal boilerplate
Documentation
use crate as go_spawn;
use go_spawn::{error::*, *};
use std::sync::{
    atomic::{AtomicU16, Ordering},
    Arc,
};

macro_rules! test_independently {
    ( $( $name:ident { $( $body:tt )* } )+ ) => {
        $(
            #[test]
            fn $name() {
                $( $body )*

                drop_all_handles();
            }
        )+
    };
}

test_independently! {
    single_go {
        let _: () = go!(1);
    }

    single_go_semi {
        let _: () = go!(1;);
    }

    single_go_brace {
        let _: () = go! {
            1
        };
    }

    single_go_brace_semi {
        let _: () = go! {
            1;
        };
    }

    single_go_ref {
        let _: () = go_ref!(1);
    }

    single_go_ref_semi {
        let _: () = go_ref!(1;);
    }

    single_go_ref_brace {
        let _: () = go_ref! {
            1
        };
    }

    single_go_ref_brace_semi {
        let _: () = go_ref! {
            1;
        };
    }

    multi_go {
        let _: () = go!(1);
        let _: () = go!(2);
        let _: () = go!(3);
    }

    multi_go_ref {
        let _: () = go_ref!(1);
        let _: () = go_ref!(2);
        let _: () = go_ref!(3);
    }

    mixed_go {
        let _: () = go!(1);
        let _: () = go_ref!(2);
        let _: () = go!(3);
        let _: () = go_ref!(4);
        let _: () = go_ref!(5);
        let _: () = go!(6);
        let _: () = go!(7);
    }

    mixed_go_ref {
        let _: () = go_ref!(1);
        let _: () = go!(2);
        let _: () = go_ref!(3);
        let _: () = go!(4);
        let _: () = go!(5);
        let _: () = go_ref!(6);
        let _: () = go_ref!(7);
    }

    single_join {
        let result = join!();
        assert!(matches!(result, Err(JoinError::NoHandleFound)));
    }

    multi_join {
        let result1 = join!();
        let result2 = join!();
        let result3 = join!();

        assert!(matches!(result1, Err(JoinError::NoHandleFound)));
        assert!(matches!(result2, Err(JoinError::NoHandleFound)));
        assert!(matches!(result3, Err(JoinError::NoHandleFound)));
    }

    single_join_all {
        let _: () = join_all!();
    }

    single_join_all_with_err_handler {
        let _: () = join_all!(|_| panic!("no errors should occur"));
    }

    multi_join_all {
        let _: () = join_all!();
        let _: () = join_all!();
        let _: () = join_all!();
    }

    multi_join_all_with_err_handler {
        let _: () = join_all!(|_| panic!("no errors should occur"));
        let _: () = join_all!(|_| panic!("no errors should occur"));
        let _: () = join_all!(|_| panic!("no errors should occur"));
    }

    mixed_join {
        let result1 = join!();
        let _: () = join_all!();
        let result2 = join!();
        let _: () = join_all!();
        let _: () = join_all!();
        let result3 = join!();
        let result4 = join!();

        assert!(matches!(result1, Err(JoinError::NoHandleFound)));
        assert!(matches!(result2, Err(JoinError::NoHandleFound)));
        assert!(matches!(result3, Err(JoinError::NoHandleFound)));
        assert!(matches!(result4, Err(JoinError::NoHandleFound)));
    }

     mixed_join_all {
        let _: () = join_all!();
        let result1 = join!();
        let _: () = join_all!();
        let result2 = join!();
        let result3 = join!();
        let _: () = join_all!();
        let _: () = join_all!();

        assert!(matches!(result1, Err(JoinError::NoHandleFound)));
        assert!(matches!(result2, Err(JoinError::NoHandleFound)));
        assert!(matches!(result3, Err(JoinError::NoHandleFound)));
    }

     mixed_join_all_with_err_handler {
        let _: () = join_all!(|_| panic!("no errors should occur"));
        let result1 = join!();
        let _: () = join_all!(|_| panic!("no errors should occur"));
        let result2 = join!();
        let result3 = join!();
        let _: () = join_all!(|_| panic!("no errors should occur"));
        let _: () = join_all!(|_| panic!("no errors should occur"));

        assert!(matches!(result1, Err(JoinError::NoHandleFound)));
        assert!(matches!(result2, Err(JoinError::NoHandleFound)));
        assert!(matches!(result3, Err(JoinError::NoHandleFound)));
    }

    single_go_then_join {
        let counter = Arc::new(AtomicU16::new(0));
        let counter_clone = counter.clone();

        go!(counter_clone.fetch_add(1, Ordering::SeqCst));
        join!().expect("thread should not panic");

        assert_eq!(counter.fetch_add(1, Ordering::SeqCst), 1);
    }

    single_go_ref_then_join {
        static COUNTER: AtomicU16 = AtomicU16::new(0);

        go_ref!(COUNTER.fetch_add(1, Ordering::SeqCst));
        join!().expect("thread should not panic");

        assert_eq!(COUNTER.load(Ordering::SeqCst), 1);
    }

    single_go_then_join_twice {
        let counter = Arc::new(AtomicU16::new(0));
        let counter_clone = counter.clone();

        go!(counter_clone.fetch_add(1, Ordering::SeqCst));
        join!().expect("thread should not panic");

        assert_eq!(counter.load(Ordering::SeqCst), 1);

        let result = join!();
        assert!(matches!(result, Err(JoinError::NoHandleFound)));
    }

    single_go_ref_then_join_twice {
        static COUNTER: AtomicU16 = AtomicU16::new(0);

        go_ref!(COUNTER.fetch_add(1, Ordering::SeqCst));
        join!().expect("thread should not panic");

        assert_eq!(COUNTER.load(Ordering::SeqCst), 1);

        let result = join!();
        assert!(matches!(result, Err(JoinError::NoHandleFound)));
    }

    multi_go_then_multi_join {
        let counter = Arc::new(AtomicU16::new(0));
        let counter_clone1 = counter.clone();
        let counter_clone2 = counter.clone();
        let counter_clone3 = counter.clone();

        go!(counter_clone1.fetch_add(1, Ordering::SeqCst));
        go!(counter_clone2.fetch_add(1, Ordering::SeqCst));
        go!(counter_clone3.fetch_add(1, Ordering::SeqCst));
        join!().expect("thread should not panic");
        join!().expect("thread should not panic");
        join!().expect("thread should not panic");

        assert_eq!(counter.load(Ordering::SeqCst), 3);

        let result = join!();
        assert!(matches!(result, Err(JoinError::NoHandleFound)));
    }

     multi_go_then_join_all {
        let counter = Arc::new(AtomicU16::new(0));
        let counter_clone1 = counter.clone();
        let counter_clone2 = counter.clone();
        let counter_clone3 = counter.clone();

        go!(counter_clone1.fetch_add(1, Ordering::SeqCst));
        go!(counter_clone2.fetch_add(1, Ordering::SeqCst));
        go!(counter_clone3.fetch_add(1, Ordering::SeqCst));

        join!().expect("thread should not panic");
        let _: () = join_all!(|_| panic!("no errors should occur"));

        assert_eq!(counter.load(Ordering::SeqCst), 3);

        let result = join!();
        assert!(matches!(result, Err(JoinError::NoHandleFound)));
    }

     multi_go_then_single_join_then_join_all {
        let counter = Arc::new(AtomicU16::new(0));
        let counter_clone1 = counter.clone();
        let counter_clone2 = counter.clone();
        let counter_clone3 = counter.clone();

        go!(counter_clone1.fetch_add(1, Ordering::SeqCst));
        go!(counter_clone2.fetch_add(1, Ordering::SeqCst));
        go!(counter_clone3.fetch_add(1, Ordering::SeqCst));

        let _: () = join_all!(|_| panic!("no errors should occur"));

        assert_eq!(counter.load(Ordering::SeqCst), 3);

        let result = join!();
        assert!(matches!(result, Err(JoinError::NoHandleFound)));
    }

    multi_go_ref_then_multi_join {
        static COUNTER: AtomicU16 = AtomicU16::new(0);

        go_ref!(COUNTER.fetch_add(1, Ordering::SeqCst));
        go_ref!(COUNTER.fetch_add(1, Ordering::SeqCst));
        go_ref!(COUNTER.fetch_add(1, Ordering::SeqCst));
        join!().expect("thread should not panic");
        join!().expect("thread should not panic");
        join!().expect("thread should not panic");

        assert_eq!(COUNTER.load(Ordering::SeqCst), 3);

        let result = join!();
        assert!(matches!(result, Err(JoinError::NoHandleFound)));
    }

    multi_go_ref_then_join_all {
        static COUNTER: AtomicU16 = AtomicU16::new(0);

        go_ref!(COUNTER.fetch_add(1, Ordering::SeqCst));
        go_ref!(COUNTER.fetch_add(1, Ordering::SeqCst));
        go_ref!(COUNTER.fetch_add(1, Ordering::SeqCst));
        let _: () = join_all!(|_| panic!("no errors should occur"));

        assert_eq!(COUNTER.load(Ordering::SeqCst), 3);

        let result = join!();
        assert!(matches!(result, Err(JoinError::NoHandleFound)));
    }

    multi_go_ref_then_single_join_then_join_all {
        static COUNTER: AtomicU16 = AtomicU16::new(0);

        go_ref!(COUNTER.fetch_add(1, Ordering::SeqCst));
        go_ref!(COUNTER.fetch_add(1, Ordering::SeqCst));
        go_ref!(COUNTER.fetch_add(1, Ordering::SeqCst));
        join!().expect("thread should not panic");
        let _: () = join_all!(|_| panic!("no errors should occur"));

        assert_eq!(COUNTER.load(Ordering::SeqCst), 3);

        let result = join!();
        assert!(matches!(result, Err(JoinError::NoHandleFound)));
    }
}