1+ use rustler_sys:: c_char;
2+
3+ use crate :: codegen_runtime:: { NifReturnable , NifReturned } ;
14use crate :: wrapper:: ErlNifTaskFlags ;
25use crate :: Env ;
36
@@ -7,7 +10,95 @@ pub enum SchedulerFlags {
710 DirtyIo = ErlNifTaskFlags :: ERL_NIF_DIRTY_JOB_IO_BOUND as isize ,
811}
912
13+ impl SchedulerFlags {
14+ fn from ( n : isize ) -> Self {
15+ match n {
16+ _ if n == Self :: Normal as isize => Self :: Normal ,
17+ _ if n == Self :: DirtyCpu as isize => Self :: DirtyCpu ,
18+ _ if n == Self :: DirtyIo as isize => Self :: DirtyIo ,
19+ _ => unreachable ! ( ) ,
20+ }
21+ }
22+ }
23+
1024pub fn consume_timeslice ( env : Env , percent : i32 ) -> bool {
1125 let success = unsafe { rustler_sys:: enif_consume_timeslice ( env. as_c_arg ( ) , percent) } ;
1226 success == 1
1327}
28+
29+ /// Convenience type for scheduling a future invokation of a NIF.
30+ ///
31+ /// ## Usage:
32+ ///
33+ /// The first generic type should be the NIF that will be scheduled, with a
34+ /// current limitation being that it must be same throughout the lifetime of the
35+ /// NIF.
36+ ///
37+ /// The second generic type defined should be the type of the return value.
38+ ///
39+ /// Every other generic type is optional, but should reflect the non-`rustler`
40+ /// arguments provided to the NIF, in the same order.
41+ ///
42+ /// ## Example:
43+ /// ```rust,ignore
44+ /// #[nif]
45+ /// fn factorial(input: u32, result: Option<u32>) -> Schedule<factorial, u32, u32> {
46+ /// let result = result.unwrap_or(1);
47+ /// if input == 0 {
48+ /// Schedule::Result(result)
49+ /// } else {
50+ /// Schedule::Next2(factorial, input - 1, result * input)
51+ /// }
52+ /// }
53+ /// ```
54+ pub enum Schedule < N : crate :: Nif , T , A = ( ) , B = ( ) , C = ( ) , D = ( ) , E = ( ) , F = ( ) , G = ( ) > {
55+ /// The final result type to return back to the BEAM.
56+ Result ( T ) ,
57+ /// Single- and multiple-argument variants that should reflect the scheduled
58+ /// NIF's function signature.
59+ Next ( N , A ) ,
60+ Next2 ( N , A , B ) ,
61+ Next3 ( N , A , B , C ) ,
62+ Next4 ( N , A , B , C , D ) ,
63+ Next5 ( N , A , B , C , D , E ) ,
64+ Next6 ( N , A , B , C , D , E , F ) ,
65+ Next7 ( N , A , B , C , D , E , F , G ) ,
66+ }
67+
68+ unsafe impl < N , T , A , B , C , D , E , F , G > NifReturnable for Schedule < N , T , A , B , C , D , E , F , G >
69+ where
70+ N : crate :: Nif ,
71+ T : crate :: Encoder ,
72+ A : crate :: Encoder ,
73+ B : crate :: Encoder ,
74+ C : crate :: Encoder ,
75+ D : crate :: Encoder ,
76+ E : crate :: Encoder ,
77+ F : crate :: Encoder ,
78+ G : crate :: Encoder ,
79+ {
80+ #[ inline]
81+ unsafe fn into_returned ( self , env : Env ) -> NifReturned {
82+ macro_rules! branch {
83+ ( $( $arg: tt) ,* ) => (
84+ NifReturned :: Reschedule {
85+ fun_name: std:: ffi:: CStr :: from_ptr( N :: NAME as * const c_char) . into( ) ,
86+ flags: SchedulerFlags :: from( N :: FLAGS as isize ) ,
87+ fun: N :: RAW_FUNC ,
88+ args: vec![ $( $arg. encode( env) . as_c_arg( ) ) ,* ] ,
89+ }
90+ )
91+ }
92+
93+ match self {
94+ Self :: Result ( res) => NifReturned :: Term ( res. encode ( env) . as_c_arg ( ) ) ,
95+ Self :: Next ( _, a) => branch ! ( a) ,
96+ Self :: Next2 ( _, a, b) => branch ! ( a, b) ,
97+ Self :: Next3 ( _, a, b, c) => branch ! ( a, b, c) ,
98+ Self :: Next4 ( _, a, b, c, d) => branch ! ( a, b, c, d) ,
99+ Self :: Next5 ( _, a, b, c, d, e) => branch ! ( a, b, c, d, e) ,
100+ Self :: Next6 ( _, a, b, c, d, e, f) => branch ! ( a, b, c, d, e, f) ,
101+ Self :: Next7 ( _, a, b, c, d, e, f, g) => branch ! ( a, b, c, d, e, f, g) ,
102+ }
103+ }
104+ }
0 commit comments