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 in the [`Option`].
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 in the [`Option`].
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`.
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`]
87pub enum Entry<'a, T> {
88    /// `None`
89    Vacant(VacantEntry<'a, T>),
90    /// `Some`
91    Occupied(OccupiedEntry<'a, T>),
92}
93
94impl<'a, T> Entry<'a, T> {
95    fn into_option_mut(self) -> &'a mut Option<T> {
96        match self {
97            Entry::Vacant(VacantEntry { option }) => option,
98            Entry::Occupied(OccupiedEntry { option }) => option,
99        }
100    }
101
102    /// Provides in-place mutable access to a [`Some`] before any potential inserts into the option.
103    pub fn and_modify(self, f: impl FnOnce(&mut T)) -> Self {
104        let option = self.into_option_mut();
105        if let Some(value) = option {
106            f(value);
107        }
108        option.entry()
109    }
110
111    /// Sets the value of the option, and returns an [`OccupiedEntry`].
112    pub fn insert_entry(self, value: T) -> OccupiedEntry<'a, T> {
113        match self {
114            Entry::Occupied(mut entry) => {
115                entry.insert(value);
116                entry
117            }
118            Entry::Vacant(entry) => entry.insert_entry(value),
119        }
120    }
121
122    /// Ensures a value is in the option by inserting the default value if [`None`], and returns a
123    /// mutable reference to that (already present or default) value.
124    pub fn or_default(self) -> &'a mut T
125    where
126        T: Default,
127    {
128        self.into_option_mut().get_or_insert_default()
129    }
130
131    /// Ensures a value is in the option by inserting `default` if [`None`], and returns a mutable
132    /// reference to that (already present or `default`) value.
133    pub fn or_insert(self, default: T) -> &'a mut T {
134        match self {
135            Entry::Occupied(entry) => entry.into_mut(),
136            Entry::Vacant(entry) => entry.insert(default),
137        }
138    }
139
140    /// Ensures a value is in the option by inserting `default()` if [`None`], and returns a mutable
141    /// reference to that (already present or `default()`) value.
142    pub fn or_insert_with(self, default: impl FnOnce() -> T) -> &'a mut T {
143        match self {
144            Entry::Occupied(entry) => entry.into_mut(),
145            Entry::Vacant(entry) => entry.insert(default()),
146        }
147    }
148}
149
150mod private {
151    pub trait Sealed {}
152}
153
154/// Extension trait for viewing [`Option`] as [`Entry`].
155pub trait OptionEntry: private::Sealed {
156    /// `T` in `Option<T>`.
157    type T;
158    /// View the current [`Option`] as an [`Entry`], primarily for [`OccupiedEntry::remove`].
159    fn entry(&mut self) -> Entry<'_, Self::T>;
160}
161
162impl<T> private::Sealed for Option<T> {}
163
164impl<T> OptionEntry for Option<T> {
165    type T = T;
166
167    fn entry(&mut self) -> Entry<'_, Self::T> {
168        if self.is_none() {
169            Entry::Vacant(VacantEntry::new(self))
170        } else {
171            Entry::Occupied(OccupiedEntry::new(self))
172        }
173    }
174}