1
+ use rustler_sys:: c_char;
2
+
3
+ use crate :: codegen_runtime:: { NifReturnable , NifReturned } ;
1
4
use crate :: wrapper:: ErlNifTaskFlags ;
2
5
use crate :: Env ;
3
6
@@ -7,7 +10,95 @@ pub enum SchedulerFlags {
7
10
DirtyIo = ErlNifTaskFlags :: ERL_NIF_DIRTY_JOB_IO_BOUND as isize ,
8
11
}
9
12
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
+
10
24
pub fn consume_timeslice ( env : Env , percent : i32 ) -> bool {
11
25
let success = unsafe { rustler_sys:: enif_consume_timeslice ( env. as_c_arg ( ) , percent) } ;
12
26
success == 1
13
27
}
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