videocall_types/
callback.rs1use std::fmt;
26use std::rc::Rc;
27
28pub struct Callback<IN, OUT = ()> {
32 cb: Rc<dyn Fn(IN) -> OUT>,
33}
34
35impl<IN, OUT, F: Fn(IN) -> OUT + 'static> From<F> for Callback<IN, OUT> {
36 fn from(func: F) -> Self {
37 Callback { cb: Rc::new(func) }
38 }
39}
40
41impl<IN, OUT> Clone for Callback<IN, OUT> {
42 fn clone(&self) -> Self {
43 Self {
44 cb: self.cb.clone(),
45 }
46 }
47}
48
49#[allow(ambiguous_wide_pointer_comparisons)]
50impl<IN, OUT> PartialEq for Callback<IN, OUT> {
51 fn eq(&self, other: &Callback<IN, OUT>) -> bool {
52 Rc::ptr_eq(&self.cb, &other.cb)
53 }
54}
55
56impl<IN, OUT> fmt::Debug for Callback<IN, OUT> {
57 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58 write!(f, "Callback<_>")
59 }
60}
61
62impl<IN, OUT> Callback<IN, OUT> {
63 pub fn emit(&self, value: IN) -> OUT {
65 (*self.cb)(value)
66 }
67}
68
69impl<IN> Callback<IN> {
70 pub fn noop() -> Self {
73 Self::from(|_| ())
74 }
75}
76
77impl<IN> Default for Callback<IN> {
78 fn default() -> Self {
79 Self::noop()
80 }
81}
82
83impl<IN: 'static, OUT: 'static> Callback<IN, OUT> {
84 pub fn reform<F, T>(&self, func: F) -> Callback<T, OUT>
87 where
88 F: Fn(T) -> IN + 'static,
89 {
90 let this = self.clone();
91 let func = move |input| {
92 let output = func(input);
93 this.emit(output)
94 };
95 Callback::from(func)
96 }
97
98 pub fn filter_reform<F, T>(&self, func: F) -> Callback<T, Option<OUT>>
102 where
103 F: Fn(T) -> Option<IN> + 'static,
104 {
105 let this = self.clone();
106 let func = move |input| func(input).map(|output| this.emit(output));
107 Callback::from(func)
108 }
109}
110
111#[cfg(test)]
112mod test {
113 use std::sync::Mutex;
114
115 use super::*;
116
117 fn emit<T, I, R: 'static + Clone, F, OUT>(values: I, f: F) -> Vec<R>
118 where
119 I: IntoIterator<Item = T>,
120 F: FnOnce(Callback<R, ()>) -> Callback<T, OUT>,
121 {
122 let result = Rc::new(Mutex::new(Vec::new()));
123 let cb_result = result.clone();
124 let cb = f(Callback::<R, ()>::from(move |v| {
125 cb_result.lock().unwrap().push(v);
126 }));
127 for value in values {
128 cb.emit(value);
129 }
130 let x = result.lock().unwrap().clone();
131 x
132 }
133
134 #[test]
135 fn test_callback() {
136 assert_eq!(*emit([true, false], |cb| cb), vec![true, false]);
137 }
138
139 #[test]
140 fn test_reform() {
141 assert_eq!(
142 *emit([true, false], |cb| cb.reform(|v: bool| !v)),
143 vec![false, true]
144 );
145 }
146
147 #[test]
148 fn test_filter_reform() {
149 assert_eq!(
150 *emit([1, 2, 3], |cb| cb.filter_reform(|v| match v {
151 1 => Some(true),
152 2 => Some(false),
153 _ => None,
154 })),
155 vec![true, false]
156 );
157 }
158}