funfun/
lib.rs

1use std::sync::Arc;
2use std::fmt;
3
4/// Boxes (heap-allocates) the given value and returns an Rc to the object.
5#[macro_export]
6macro_rules! rc {
7    ( $f:ident ) => { Box::new($f) };
8    ( $f:expr ) => { Box::new($f) };
9}
10
11/// Boxes (heap-allocates) the given value and returns an Arc to the object.
12#[macro_export]
13macro_rules! arc {
14    ( $f:ident ) => { ::std::sync::Arc::new(Box::new($f)) };
15    ( $f:expr ) => { ::std::sync::Arc::new(Box::new($f)) };
16}
17
18/// Boxes a closure and returns a reference.
19#[macro_export]
20macro_rules! box_fn {
21    ( $f:ident ) => { rc!($f) };
22    ( $f:expr ) => { rc!($f) };
23}
24
25/// Boxes a closure and returns an Arc reference. Slower than just a box, but can derive traits like
26/// Clone.
27#[macro_export]
28macro_rules! arc_fn {
29    ( $f:ident ) => { arc!($f) };
30    ( $f:expr ) => { arc!($f) };
31}
32
33/// Starts a new thread and runs the passed closure with the passed arguments in it, returning the
34/// new thread's hook.
35#[macro_export]
36macro_rules! spawn_fn {
37    ( $f:expr ) => { ::std::thread::spawn($f)};
38    ( $f:ident, $( $arg:ident ),* ) => { {let v = $f.clone(); ::std::thread::spawn(move || {v($($arg),*)})}};
39    ( $f:expr, $( $arg:expr ),* ) => { ::std::thread::spawn(move || {$f($($arg),*)}) };
40}
41
42/// Box<T> alias used for clarity (and later trait implementation) when boxing structures that
43/// implement Fn* traits.
44pub type BoxFn<T> = Box<T>;
45
46/// Arc<Box<T>> alias used for clarity (and later trait implementation) when boxing structures that
47/// implement Fn* traits.
48pub type ArcFn<T> = Arc<Box<T>>;
49
50#[cfg(test)]
51mod tests {
52    use std::thread;
53    use super::*;
54
55    #[test]
56    fn zero_arity_box_fn() {
57        let wrapped_prim = |i: u32| { println!("{}", i + 10) };
58        let wrapped_vec = |v: Vec<&str>| { println!("{:?}", v) };
59
60        let _t = box_fn!(||{println!("Neat!")});
61        let _c = box_fn!(||{println!("Neat!")});
62
63        box_fn!(||{println!("Neat!")})();
64        box_fn!(||{wrapped_prim(10)})();
65        box_fn!(||{wrapped_vec(vec!["nice", "cool"])})();
66    }
67
68    #[test]
69    fn one_arity_box_fn() {
70        box_fn!(|a: &str|{println!("{}", a)})("Awesome!");
71        box_fn!(|i: u32| {println!("{}", i + 10)})(10);
72        box_fn!(|v: Vec<&str>| { println!("{:?}", v) })(vec!["nice", "cool"]);
73    }
74
75    #[test]
76    fn pass_named_box_fn() {
77        let wrapped_prim = |i: u32| { println!("{}", i + 10) };
78        let wrapped_vec = |v: Vec<&str>| { println!("{:?}", v) };
79
80        box_fn!(wrapped_prim)(10);
81        box_fn!(wrapped_vec)(vec!["nice", "cool"])
82    }
83
84    #[test]
85    fn pass_function_box_fn() {
86        fn func(s: &str) { println!("{}", s)}
87
88        box_fn!(func)("Wow!");
89    }
90
91    #[test]
92    fn in_struct_box_fn() {
93        type T = BoxFn<Fn(&str) -> String>;
94
95        struct F {
96            c: T
97        }
98
99        let c: T = box_fn!(|s: &str| -> String {s.to_string()});
100
101        let mut f = F { c };
102
103        f.c = box_fn!(
104            |d: &str| -> String {"reassign once".to_string()}
105        );
106
107        f.c = box_fn!(
108            |_: &str| {"and again".to_string()}
109        );
110    }
111
112
113    #[test]
114    fn in_struct_arc_fn() {
115        type T = ArcFn<Fn(&str) -> String>;
116
117        #[derive(Clone)]
118        struct F {
119            c: T
120        }
121
122        let c: T = arc_fn!(|s: &str| -> String {s.to_string()});
123
124        let mut f = F { c };
125
126        f.c = arc_fn!(
127            |d: &str| -> String {"reassign once".to_string()}
128        );
129
130        f.c = arc_fn!(
131            |_: &str| {"and again".to_string()}
132        );
133    }
134
135    #[test]
136    fn multithreading_box_fn() {
137        let eg = box_fn!(|x: i32| -> i32 {x + 2});
138
139        let mut v1 = Vec::new();
140        for i in 0..1000 {
141            let cl = eg.clone();
142            v1.push(thread::spawn(move ||{cl(i)})); // move is necessary
143            //v2.push(spawn_fn!(eg, i));
144        }
145
146        for res in v1.into_iter() {
147            res.join();
148        }
149    }
150
151    #[test]
152    fn multithreading_spawn_fn() {
153        let eg = box_fn!(|x: i32| -> i32 {x + 2});
154        let also = box_fn!(|x: i32, y: i32| -> i32 {x + y});
155
156        let mut v1 = Vec::new();
157        for i1 in 0..10000 {
158            let i2 = i1 + 10;
159            v1.push(spawn_fn!(eg, i1));
160            v1.push(spawn_fn!(also, i1, i2)); // woohoo multi-arity!
161        }
162        v1.push(spawn_fn!(||{println!("accepts closures to run in their own thread!"); 1}));
163
164        for res in v1.into_iter() {
165            res.join();
166        }
167    }
168}