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}