• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! The TryInsert trait adds to Option<T> the method
16 //! get_or_try_to_insert_with, which is analogous to
17 //! get_or_insert_with, but allows the called function to fail and propagates the failure.
18 
19 /// The TryInsert trait adds to Option<T> the method
20 /// get_or_try_to_insert_with, which is analogous to
21 /// get_or_insert_with, but allows the called function to fail and propagates the failure.
22 pub trait TryInsert {
23     /// Type of the Ok branch of the Result
24     type Item;
25     /// Inserts a value computed from `f` into the option if it is [`None`],
26     /// then returns a mutable reference to the contained value. If `f`
27     /// returns Err, the Option is unchanged.
28     ///
29     /// # Examples
30     ///
31     /// ```
32     /// let mut x = None;
33     /// assert_eq!(x.get_or_try_to_insert_with(Err("oops".to_string())), Err("oops".to_string()))
34     /// {
35     ///     let y: &mut u32 = x.get_or_try_to_insert_with(|| Ok(5))?;
36     ///     assert_eq!(y, &5);
37     ///
38     ///     *y = 7;
39     /// }
40     ///
41     /// assert_eq!(x, Some(7));
42     /// ```
get_or_try_to_insert_with<E, F: FnOnce() -> Result<Self::Item, E>>( &mut self, f: F, ) -> Result<&mut Self::Item, E>43     fn get_or_try_to_insert_with<E, F: FnOnce() -> Result<Self::Item, E>>(
44         &mut self,
45         f: F,
46     ) -> Result<&mut Self::Item, E>;
47 }
48 
49 impl<T> TryInsert for Option<T> {
50     type Item = T;
get_or_try_to_insert_with<E, F: FnOnce() -> Result<Self::Item, E>>( &mut self, f: F, ) -> Result<&mut Self::Item, E>51     fn get_or_try_to_insert_with<E, F: FnOnce() -> Result<Self::Item, E>>(
52         &mut self,
53         f: F,
54     ) -> Result<&mut Self::Item, E> {
55         if self.is_none() {
56             *self = Some(f()?);
57         }
58 
59         match self {
60             Some(v) => Ok(v),
61             // SAFETY: a `None` variant for `self` would have been replaced by a `Some`
62             // variant in the code above.
63             None => unsafe { std::hint::unreachable_unchecked() },
64         }
65     }
66 }
67 
68 #[cfg(test)]
69 mod test {
70     use super::*;
71 
fails() -> Result<i32, String>72     fn fails() -> Result<i32, String> {
73         Err("fail".to_string())
74     }
75 
succeeds() -> Result<i32, String>76     fn succeeds() -> Result<i32, String> {
77         Ok(99)
78     }
79 
80     #[test]
test()81     fn test() {
82         let mut x = None;
83         assert_eq!(x.get_or_try_to_insert_with(fails), Err("fail".to_string()));
84         assert_eq!(x, None);
85         assert_eq!(*x.get_or_try_to_insert_with(succeeds).unwrap(), 99);
86         assert_eq!(x, Some(99));
87         x = Some(42);
88         assert_eq!(*x.get_or_try_to_insert_with(fails).unwrap(), 42);
89         assert_eq!(x, Some(42));
90         assert_eq!(*x.get_or_try_to_insert_with(succeeds).unwrap(), 42);
91         assert_eq!(x, Some(42));
92         *x.get_or_try_to_insert_with(fails).unwrap() = 2;
93         assert_eq!(x, Some(2));
94         *x.get_or_try_to_insert_with(succeeds).unwrap() = 3;
95         assert_eq!(x, Some(3));
96         x = None;
97         *x.get_or_try_to_insert_with(succeeds).unwrap() = 5;
98         assert_eq!(x, Some(5));
99     }
100 }
101