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