option_entry/
lib.rs

1//! [`Entry`] for [`Option`]s.
2//!
3//! See [`OccupiedEntry::remove`] for why.
4//!
5//! Docs and interface are based on `btree_map::Entry`.
6
7/// [`None`]
8pub struct VacantEntry<'a, T> {
9    option: &'a mut Option<T>,
10}
11
12impl<'a, T> VacantEntry<'a, T> {
13    fn new(option: &'a mut Option<T>) -> Self {
14        assert!(option.is_none());
15        Self { option }
16    }
17
18    /// Sets the value of the [`Option`], and returns a mutable reference to it.
19    pub fn insert(self, value: T) -> &'a mut T {
20        self.option.insert(value)
21    }
22
23    /// Sets the value of the [`Option`], and returns an [`OccupiedEntry`].
24    pub fn insert_entry(self, value: T) -> OccupiedEntry<'a, T> {
25        let Self { option } = self;
26        *option = Some(value);
27        OccupiedEntry::new(option)
28    }
29}
30
31/// [`Some`]
32pub struct OccupiedEntry<'a, T> {
33    option: &'a mut Option<T>,
34}
35
36impl<'a, T> OccupiedEntry<'a, T> {
37    fn new(option: &'a mut Option<T>) -> Self {
38        assert!(option.is_some());
39        Self { option }
40    }
41
42    /// Gets a reference to the value in the [`Option`].
43    pub fn get(&self) -> &T {
44        self.option.as_ref().expect("OccupiedEntry is None?")
45    }
46
47    /// Gets a mutable reference to the value in the [`Option`].
48    ///
49    /// If you need a reference to the [`OccupiedEntry`] that may outlive the destruction of the [`Entry`] value, see [`into_mut`].
50    ///
51    /// [`into_mut`]: Self::into_mut
52    pub fn get_mut(&mut self) -> &mut T {
53        self.option.as_mut().expect("OccupiedEntry is None?")
54    }
55
56    /// [`Option::replace`]. Returns `T` instead of `Option<T>`.
57    pub fn insert(&mut self, value: T) -> T {
58        self.option.replace(value).expect("OccupiedEntry is None?")
59    }
60
61    pub fn into_mut(self) -> &'a mut T {
62        self.option.as_mut().expect("OccupiedEntry is None?")
63    }
64
65    /// [`Option::take`]. Returns `T` instead of `Option<T>`.
66    ///
67    /// This method is the main reason for this crate to exist: this allows avoiding doing
68    /// double-checks in code that needs to do deferred [`take`].
69    ///
70    /// [`take`]: Option::take
71    pub fn remove(self) -> T {
72        self.option.take().expect("OccupiedEntry is None?")
73    }
74}
75
76/// `&mut Option<T>` with strongly typed context of whether it's [`None`] or [`Some`]
77pub enum Entry<'a, T> {
78    /// `None`
79    Vacant(VacantEntry<'a, T>),
80    /// `Some`
81    Occupied(OccupiedEntry<'a, T>),
82}
83
84impl<'a, T> Entry<'a, T> {
85    fn into_option_mut(self) -> &'a mut Option<T> {
86        match self {
87            Entry::Vacant(VacantEntry { option }) => option,
88            Entry::Occupied(OccupiedEntry { option }) => option,
89        }
90    }
91
92    /// Provides in-place mutable access to a [`Some`] before any potential inserts into the option.
93    pub fn and_modify(self, f: impl FnOnce(&mut T)) -> Self {
94        let option = self.into_option_mut();
95        if let Some(value) = option {
96            f(value);
97        }
98        option.entry()
99    }
100
101    /// Sets the value of the option, and returns an [`OccupiedEntry`].
102    pub fn insert_entry(self, value: T) -> OccupiedEntry<'a, T> {
103        match self {
104            Entry::Occupied(mut entry) => {
105                entry.insert(value);
106                entry
107            }
108            Entry::Vacant(entry) => entry.insert_entry(value),
109        }
110    }
111
112    /// Ensures a value is in the option by inserting the default value if [`None`], and returns a
113    /// mutable reference to that (already present or default) value.
114    pub fn or_default(self) -> &'a mut T
115    where
116        T: Default,
117    {
118        self.into_option_mut().get_or_insert_default()
119    }
120
121    /// Ensures a value is in the option by inserting `default` if [`None`], and returns a mutable
122    /// reference to that (already present or `default`) value.
123    pub fn or_insert(self, default: T) -> &'a mut T {
124        match self {
125            Entry::Occupied(entry) => entry.into_mut(),
126            Entry::Vacant(entry) => entry.insert(default),
127        }
128    }
129
130    /// Ensures a value is in the option by inserting `default()` if [`None`], and returns a mutable
131    /// reference to that (already present or `default()`) value.
132    pub fn or_insert_with(self, default: impl FnOnce() -> T) -> &'a mut T {
133        match self {
134            Entry::Occupied(entry) => entry.into_mut(),
135            Entry::Vacant(entry) => entry.insert(default()),
136        }
137    }
138}
139
140mod private {
141    pub trait Sealed {}
142}
143
144/// Extension trait for viewing [`Option`] as [`Entry`].
145pub trait OptionEntry: private::Sealed {
146    type T;
147    /// View the current [`Option`] as an [`Entry`], primarily for [`OccupiedEntry::remove`].
148    fn entry(&mut self) -> Entry<'_, Self::T>;
149}
150
151impl<T> private::Sealed for Option<T> {}
152
153impl<T> OptionEntry for Option<T> {
154    type T = T;
155
156    fn entry(&mut self) -> Entry<'_, Self::T> {
157        if self.is_none() {
158            Entry::Vacant(VacantEntry::new(self))
159        } else {
160            Entry::Occupied(OccupiedEntry::new(self))
161        }
162    }
163}