fp_rust/
maybe.rs

1/*!
2In this module there're implementations & tests of `Maybe`.
3*/
4
5use std::sync::Arc;
6
7/**
8`Maybe` wraps built-in `Option<T>`,
9and implements `Applicative` and `Chain` of `fantasy-land`.
10
11# Arguments
12
13* `T` - The generic type of data
14
15# Remarks
16
17It implements `Applicative` and `Chain` of `fantasy-land`,
18and use the same interface as `fpEs` & `fpGo`(sister libraries :P)
19
20``
21*/
22#[derive(Clone)]
23pub struct Maybe<T> {
24    r: Arc<Option<T>>,
25}
26
27impl<T: Clone + 'static> Maybe<T> {
28    pub fn option(&self) -> Option<T> {
29        self.r.as_ref().clone()
30    }
31    pub fn unwrap(&self) -> T {
32        self.r.as_ref().clone().unwrap()
33    }
34    pub fn or(&self, val: T) -> T {
35        self.r.as_ref().clone().unwrap_or(val)
36    }
37}
38
39impl<T: 'static> From<T> for Maybe<T> {
40    fn from(r: T) -> Self {
41        Maybe::just(Some(r))
42    }
43}
44
45impl<T: 'static> Maybe<T> {
46    pub fn just(r: Option<T>) -> Maybe<T> {
47        Maybe { r: Arc::new(r) }
48    }
49    pub fn of(r: Option<T>) -> Maybe<T> {
50        Maybe::just(r)
51    }
52    pub fn val(r: T) -> Maybe<T> {
53        Maybe::just(Some(r))
54    }
55
56    pub fn present(&self) -> bool {
57        match self.r.as_ref() {
58            Some(_x) => true,
59            None => false,
60        }
61    }
62    pub fn null(&self) -> bool {
63        match self.r.as_ref() {
64            Some(_x) => false,
65            None => true,
66        }
67    }
68    pub fn let_do<F>(&self, func: F)
69    where
70        F: FnOnce(&T),
71    {
72        match self.r.as_ref() {
73            Some(_x) => func(&_x),
74            None => (),
75        }
76    }
77
78    pub fn fmap<F, G>(&self, func: F) -> Maybe<G>
79    where
80        F: FnOnce(&Option<T>) -> Maybe<G>,
81    {
82        func(self.r.as_ref())
83    }
84    pub fn map<F, G>(&self, func: F) -> Maybe<G>
85    where
86        F: FnOnce(&Option<T>) -> Option<G>,
87        G: 'static,
88    {
89        Maybe::just(func(self.r.as_ref()))
90    }
91    pub fn bind<F, G>(&self, func: F) -> Maybe<G>
92    where
93        F: FnOnce(&Option<T>) -> Option<G>,
94        G: 'static,
95    {
96        self.map(func)
97    }
98    pub fn then<F, G>(&self, func: F) -> Maybe<G>
99    where
100        F: FnOnce(&Option<T>) -> Option<G>,
101        G: 'static,
102    {
103        self.map(func)
104    }
105    pub fn chain<F, G>(&self, func: F) -> Maybe<G>
106    where
107        F: FnOnce(&Option<T>) -> Maybe<G>,
108    {
109        self.fmap(func)
110    }
111    pub fn ap<F, G>(&self, maybe_func: &Maybe<F>) -> Maybe<G>
112    where
113        F: FnOnce(&Option<T>) -> Option<G> + Clone + 'static,
114        G: 'static,
115    {
116        maybe_func.chain(|f| self.map(f.clone().unwrap()))
117    }
118}
119
120#[test]
121fn test_maybe_present() {
122    assert_eq!(false, Maybe::just(None::<bool>).present());
123    assert_eq!(true, Maybe::val(true).present());
124
125    assert_eq!(true, Maybe::just(None::<bool>).null());
126    assert_eq!(false, Maybe::val(true).null());
127
128    let mut val;
129
130    val = false;
131    Maybe::just(None::<bool>).let_do(|x| val = *x);
132    assert_eq!(false, val);
133
134    val = false;
135    Maybe::val(true).let_do(|x| val = *x);
136    assert_eq!(true, val);
137}
138#[test]
139fn test_maybe_flatmap() {
140    assert_eq!(
141        false,
142        Maybe::val(true)
143            .fmap(|x| return Maybe::val(!x.unwrap()))
144            .unwrap()
145    );
146    assert_eq!(
147        true,
148        Maybe::val(false)
149            .fmap(|x| return Maybe::val(!x.unwrap()))
150            .unwrap()
151    );
152
153    assert_eq!(
154        false,
155        Maybe::val(true).map(|x| return Some(!x.unwrap())).unwrap()
156    );
157    assert_eq!(
158        true,
159        Maybe::val(false).map(|x| return Some(!x.unwrap())).unwrap()
160    );
161
162    assert_eq!(
163        true,
164        Maybe::val(1)
165            .ap(&Maybe::val(|x: &Option<i16>| if x.unwrap() > 0 {
166                return Some(true);
167            } else {
168                return Some(false);
169            }))
170            .unwrap()
171    );
172}
173#[test]
174fn test_maybe_unwrap() {
175    assert_eq!(false, Maybe::just(None::<bool>).or(false));
176    assert_eq!(true, Maybe::val(true).or(false));
177    use std::panic;
178
179    let none_unwrap = panic::catch_unwind(|| {
180        Maybe::just(None::<bool>).unwrap();
181    });
182    assert_eq!(true, none_unwrap.is_err());
183    assert_eq!(true, Maybe::val(true).unwrap());
184
185    assert_eq!(
186        true,
187        match Maybe::val(true).option() {
188            None => false,
189            Some(_x) => true,
190        }
191    );
192    assert_eq!(
193        false,
194        match Maybe::just(None::<bool>).option() {
195            None => false,
196            Some(_x) => true,
197        }
198    );
199}