synthez_core/
field.rs

1//! Batteries for working with struct fields.
2
3use std::{
4    collections::{BTreeMap, BTreeSet, HashMap, HashSet},
5    hash::{BuildHasher, Hash},
6    iter, mem,
7    ops::{Deref, DerefMut},
8};
9
10/// Returns a function checking whether the provided [`Container::is_empty`] and
11/// if so, setting the value `parse`d from the provided `Input` into it.
12///
13/// # Errors
14///
15/// Propagates the error returned by `parse` function, if any.
16///
17/// # Example
18///
19/// Intended to be used as a predicate in a `#[parse]` attribute.
20///
21/// ```rust
22/// # use synthez::{field, parse, ParseAttrs};
23/// #
24/// #[derive(Default, ParseAttrs)]
25/// struct MyAttributes {
26///     #[parse(value, fallback = field::if_empty(parse::attr::doc))]
27///     description: Option<syn::LitStr>,
28/// }
29/// ```
30pub fn if_empty<V, C, Parser, Input>(
31    parse: Parser,
32) -> impl FnOnce(&mut C, Input) -> syn::Result<()>
33where
34    C: Container<V> + ?Sized,
35    Parser: FnOnce(Input) -> syn::Result<Option<V>>,
36{
37    move |container, input| {
38        if container.is_empty() {
39            if let Some(val) = parse(input)? {
40                container.set(val);
41            }
42        }
43        Ok(())
44    }
45}
46
47/// Container containing field values.
48pub trait Container<V> {
49    /// Type of values contained in this [`Container`].
50    type Value;
51
52    /// Indicates whether this [`Container`] is empty (contains no values).
53    #[must_use]
54    fn is_empty(&self) -> bool;
55
56    /// Indicates whether the provided `value` is present in this [`Container`].
57    #[must_use]
58    fn has(&self, value: &V) -> bool;
59
60    /// Replaces the `value` contained in this [`Container`] with the provided
61    /// one, and returns the replaced one, if any.
62    fn replace(&mut self, value: V) -> Option<V>;
63
64    /// Sets the provided `value` into this  [`Container`], dropping the
65    /// previous one, if any.
66    fn set(&mut self, value: V) {
67        drop(self.replace(value));
68    }
69}
70
71impl<V> Container<V> for Option<V> {
72    type Value = V;
73
74    fn is_empty(&self) -> bool {
75        self.is_none()
76    }
77
78    fn has(&self, _: &V) -> bool {
79        self.is_some()
80    }
81
82    fn replace(&mut self, val: V) -> Self {
83        Self::replace(self, val)
84    }
85}
86
87impl<V> Container<V> for Required<V> {
88    type Value = V;
89
90    fn is_empty(&self) -> bool {
91        !self.is_present()
92    }
93
94    fn has(&self, _: &V) -> bool {
95        self.is_present()
96    }
97
98    fn replace(&mut self, val: V) -> Option<V> {
99        Self::replace_with(self, val)
100    }
101}
102
103impl<V: PartialEq> Container<V> for Vec<V> {
104    type Value = V;
105
106    fn is_empty(&self) -> bool {
107        Self::is_empty(self)
108    }
109
110    fn has(&self, val: &V) -> bool {
111        self.contains(val)
112    }
113
114    fn replace(&mut self, val: V) -> Option<V> {
115        if let Some(old) = self.iter_mut().find(|v| *v == &val) {
116            Some(mem::replace(old, val))
117        } else {
118            self.push(val);
119            None
120        }
121    }
122}
123
124impl<V, S> Container<V> for HashSet<V, S>
125where
126    V: Eq + Hash,
127    S: BuildHasher,
128{
129    type Value = V;
130
131    fn is_empty(&self) -> bool {
132        Self::is_empty(self)
133    }
134
135    fn has(&self, val: &V) -> bool {
136        self.contains(val)
137    }
138
139    fn replace(&mut self, val: V) -> Option<V> {
140        Self::replace(self, val)
141    }
142}
143
144impl<V: Ord> Container<V> for BTreeSet<V> {
145    type Value = V;
146
147    fn is_empty(&self) -> bool {
148        Self::is_empty(self)
149    }
150
151    fn has(&self, val: &V) -> bool {
152        self.contains(val)
153    }
154
155    fn replace(&mut self, val: V) -> Option<V> {
156        Self::replace(self, val)
157    }
158}
159
160impl<K, V, S> Container<(K, V)> for HashMap<K, V, S>
161where
162    K: Eq + Hash,
163    S: BuildHasher,
164{
165    type Value = (K, V);
166
167    fn is_empty(&self) -> bool {
168        Self::is_empty(self)
169    }
170
171    fn has(&self, val: &(K, V)) -> bool {
172        self.contains_key(&val.0)
173    }
174
175    fn replace(&mut self, val: (K, V)) -> Option<(K, V)> {
176        let prev = self.remove_entry(&val.0);
177        drop(self.insert(val.0, val.1));
178        prev
179    }
180}
181
182impl<K: Ord, V> Container<(K, V)> for BTreeMap<K, V> {
183    type Value = (K, V);
184
185    fn is_empty(&self) -> bool {
186        Self::is_empty(self)
187    }
188
189    fn has(&self, val: &(K, V)) -> bool {
190        self.contains_key(&val.0)
191    }
192
193    fn replace(&mut self, val: (K, V)) -> Option<(K, V)> {
194        let prev = self.remove_entry(&val.0);
195        drop(self.insert(val.0, val.1));
196        prev
197    }
198}
199
200/// [`Container`] requiring a field to have a value mandatory.
201///
202/// It's similar to an [`Option`], but panics on accessing to an absent
203/// underlying value. So, is not intended to be created directly in user code,
204/// but rather only used for marking types in struct fields, so this library
205/// machinery may kick in and take care of correct values creation without
206/// introducing any panics.
207///
208/// Accessing the underlying value, stored in this wrapper, is intended to be
209/// done via [`Deref`] and [`DerefMut`] in user code.
210#[derive(Clone, Copy, Debug)]
211pub struct Required<T>(Option<T>);
212
213#[doc(hidden)]
214impl<T> Default for Required<T> {
215    fn default() -> Self {
216        Self(None)
217    }
218}
219
220impl<T> Required<T> {
221    /// Indicates whether the underlying value is present in this [`Required`]
222    /// [`Container`].
223    #[must_use]
224    pub(crate) const fn is_present(&self) -> bool {
225        self.0.is_some()
226    }
227
228    /// Replaces the underlying `value` with the given one in this [`Required`]
229    /// [`Container`], returning the previous one, if any.
230    #[must_use]
231    pub(crate) fn replace_with(&mut self, value: T) -> Option<T> {
232        self.0.replace(value)
233    }
234
235    /// Removes the underlying value from this [`Required`] [`Container`],
236    /// returning it, if any.
237    #[must_use]
238    pub(crate) fn take(&mut self) -> Option<T> {
239        self.0.take()
240    }
241
242    /// Unwraps this [`Required`] [`Container`] returning the underlying value.
243    ///
244    /// # Panics
245    ///
246    /// If this [`Container`] hasn't been initialized properly, so contains no
247    /// value.
248    #[must_use]
249    pub fn into_inner(self) -> T {
250        #[allow(clippy::expect_used)]
251        self.0.expect("Uninitialized `Required` value")
252    }
253}
254
255impl<T> Deref for Required<T> {
256    type Target = T;
257
258    fn deref(&self) -> &Self::Target {
259        #[allow(clippy::expect_used)]
260        self.0.as_ref().expect("Uninitialized `Required` value")
261    }
262}
263
264impl<T> DerefMut for Required<T> {
265    fn deref_mut(&mut self) -> &mut Self::Target {
266        #[allow(clippy::expect_used)]
267        self.0.as_mut().expect("Uninitialized `Required` value")
268    }
269}
270
271impl<T> IntoIterator for Required<T> {
272    type Item = T;
273    type IntoIter = iter::Once<T>;
274
275    fn into_iter(self) -> Self::IntoIter {
276        iter::once(self.into_inner())
277    }
278}
279
280impl<'a, T> IntoIterator for &'a Required<T> {
281    type Item = &'a T;
282    type IntoIter = iter::Once<&'a T>;
283
284    fn into_iter(self) -> Self::IntoIter {
285        iter::once(&**self)
286    }
287}
288
289impl<'a, T> IntoIterator for &'a mut Required<T> {
290    type Item = &'a mut T;
291    type IntoIter = iter::Once<&'a mut T>;
292
293    fn into_iter(self) -> Self::IntoIter {
294        iter::once(&mut *self)
295    }
296}