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