ron/ser/
path_meta.rs

1//! Path-based metadata to serialize with a value.
2//!
3//! Path-based in this context means that the metadata is linked
4//! to the data in a relative and hierarchical fashion by tracking
5//! the current absolute path of the field being serialized.
6//!
7//! # Example
8//!
9//! ```
10//! # use ron::ser::{PrettyConfig, path_meta::Field};
11//!
12//! #[derive(serde::Serialize)]
13//! struct Creature {
14//!     seconds_since_existing: usize,
15//!     linked: Option<Box<Self>>,
16//! }
17//!
18//! let mut config = PrettyConfig::default();
19//!
20//! config
21//!     .path_meta
22//!     // The path meta defaults to no root structure,
23//!     // so we either provide a prebuilt one or initialize
24//!     // an empty one to build.
25//!     .get_or_insert_with(Field::empty)
26//!     .build_fields(|fields| {
27//!         fields
28//!             // Get or insert the named field
29//!             .field("seconds_since_existing")
30//!             .with_doc("Outer seconds_since_existing");
31//!         fields
32//!             .field("linked")
33//!             // Doc metadata is serialized preceded by three forward slashes and a space for each line
34//!             .with_doc("Optional.\nProvide another creature to be wrapped.")
35//!             // Even though it's another Creature, the fields have different paths, so they are addressed separately.
36//!             .build_fields(|fields| {
37//!                 fields
38//!                     .field("seconds_since_existing")
39//!                     .with_doc("Inner seconds_since_existing");
40//!             });
41//!     });
42//!
43//! let value = Creature {
44//!     seconds_since_existing: 0,
45//!     linked: Some(Box::new(Creature {
46//!         seconds_since_existing: 0,
47//!         linked: None,
48//!     })),
49//! };
50//!
51//! let s = ron::ser::to_string_pretty(&value, config).unwrap();
52//!
53//! assert_eq!(s, r#"(
54//!     /// Outer seconds_since_existing
55//!     seconds_since_existing: 0,
56//!     /// Optional.
57//!     /// Provide another creature to be wrapped.
58//!     linked: Some((
59//!         /// Inner seconds_since_existing
60//!         seconds_since_existing: 0,
61//!         linked: None,
62//!     )),
63//! )"#);
64//! ```
65//!
66//! # Identical paths
67//!
68//! Especially in enums and tuples it's possible for fields
69//! to share a path, thus being unable to be addressed separately.
70//!
71//! ```no_run
72//! enum Kind {
73//!     A {
74//!         field: (),
75//!     },  // ^
76//!         // cannot be addressed separately because they have the same path
77//!     B { // v
78//!         field: (),
79//!     },
80//! }
81//! ```
82//!
83//! ```no_run
84//! struct A {
85//!     field: (),
86//! }
87//!
88//! struct B {
89//!     field: (),
90//! }
91//!
92//! type Value = (
93//!     A,
94//!  // ^
95//!  // These are different types, but they share the path `field`
96//!  // v
97//!     B,
98//! );
99//! ```
100
101use alloc::string::String;
102
103use serde_derive::{Deserialize, Serialize};
104
105#[cfg(feature = "std")]
106use std::collections::HashMap as FieldsInner;
107
108#[cfg(not(feature = "std"))]
109use alloc::collections::BTreeMap as FieldsInner;
110
111/// The metadata and inner [`Fields`] of a field.
112#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
113pub struct Field {
114    doc: String,
115    fields: Option<Fields>,
116}
117
118impl Field {
119    /// Create a new empty field metadata.
120    #[must_use]
121    pub const fn empty() -> Self {
122        Self {
123            doc: String::new(),
124            fields: None,
125        }
126    }
127
128    /// Create a new field metadata from parts.
129    pub fn new(doc: impl Into<String>, fields: Option<Fields>) -> Self {
130        Self {
131            doc: doc.into(),
132            fields,
133        }
134    }
135
136    /// Get a shared reference to the documentation metadata of this field.
137    #[inline]
138    #[must_use]
139    pub fn doc(&self) -> &str {
140        self.doc.as_str()
141    }
142
143    /// Get a mutable reference to the documentation metadata of this field.
144    #[inline]
145    #[must_use]
146    pub fn doc_mut(&mut self) -> &mut String {
147        &mut self.doc
148    }
149
150    /// Set the documentation metadata of this field.
151    ///
152    /// ```
153    /// # use ron::ser::path_meta::Field;
154    ///
155    /// let mut field = Field::empty();
156    ///
157    /// assert_eq!(field.doc(), "");
158    ///
159    /// field.with_doc("some meta");
160    ///
161    /// assert_eq!(field.doc(), "some meta");
162    /// ```
163    pub fn with_doc(&mut self, doc: impl Into<String>) -> &mut Self {
164        self.doc = doc.into();
165        self
166    }
167
168    /// Get a shared reference to the inner fields of this field, if it has any.
169    #[must_use]
170    pub fn fields(&self) -> Option<&Fields> {
171        self.fields.as_ref()
172    }
173
174    /// Get a mutable reference to the inner fields of this field, if it has any.
175    pub fn fields_mut(&mut self) -> Option<&mut Fields> {
176        self.fields.as_mut()
177    }
178
179    /// Return whether this field has inner fields.
180    ///
181    /// ```
182    /// # use ron::ser::path_meta::{Field, Fields};
183    ///
184    /// let mut field = Field::empty();
185    ///
186    /// assert!(!field.has_fields());
187    ///
188    /// field.with_fields(Some(Fields::default()));
189    ///
190    /// assert!(field.has_fields());
191    /// ```
192    #[must_use]
193    pub fn has_fields(&self) -> bool {
194        self.fields.is_some()
195    }
196
197    /// Set the inner fields of this field.
198    ///
199    /// ```
200    /// # use ron::ser::path_meta::{Field, Fields};
201    ///
202    /// let mut field = Field::empty();
203    ///
204    /// assert!(!field.has_fields());
205    ///
206    /// field.with_fields(Some(Fields::default()));
207    ///
208    /// assert!(field.has_fields());
209    ///
210    /// field.with_fields(None);
211    ///  
212    /// assert!(!field.has_fields());
213    /// ```
214    pub fn with_fields(&mut self, fields: Option<Fields>) -> &mut Self {
215        self.fields = fields;
216        self
217    }
218
219    /// Ergonomic shortcut for building some inner fields.
220    ///
221    /// ```
222    /// # use ron::ser::path_meta::Field;
223    ///
224    /// let mut field = Field::empty();
225    ///
226    /// field.build_fields(|fields| {
227    ///     fields.field("inner field");
228    /// });
229    ///
230    /// assert_eq!(field.fields().map(|fields| fields.contains("inner field")), Some(true));
231    /// ```
232    pub fn build_fields(&mut self, builder: impl FnOnce(&mut Fields)) -> &mut Self {
233        let mut fields = Fields::default();
234        builder(&mut fields);
235        self.with_fields(Some(fields));
236        self
237    }
238}
239
240/// Mapping of names to [`Field`]s.
241#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
242pub struct Fields {
243    fields: FieldsInner<String, Field>,
244}
245
246impl Fields {
247    /// Return a new, empty metadata field map.
248    #[must_use]
249    pub fn new() -> Self {
250        Self::default()
251    }
252
253    /// Return whether this field map contains no fields.
254    ///
255    /// ```
256    /// # use ron::ser::path_meta::{Fields, Field};
257    ///
258    /// let mut fields = Fields::default();
259    ///
260    /// assert!(fields.is_empty());
261    ///
262    /// fields.insert("", Field::empty());
263    ///
264    /// assert!(!fields.is_empty());
265    /// ```
266    #[must_use]
267    pub fn is_empty(&self) -> bool {
268        self.fields.is_empty()
269    }
270
271    /// Return whether this field map contains a field with the given name.
272    ///
273    /// ```
274    /// # use ron::ser::path_meta::{Fields, Field};
275    ///
276    /// let fields: Fields = [("a thing", Field::empty())].into_iter().collect();
277    ///
278    /// assert!(fields.contains("a thing"));
279    /// assert!(!fields.contains("not a thing"));
280    /// ```
281    pub fn contains(&self, name: impl AsRef<str>) -> bool {
282        self.fields.contains_key(name.as_ref())
283    }
284
285    /// Get a reference to the field with the provided `name`, if it exists.
286    ///
287    /// ```
288    /// # use ron::ser::path_meta::{Fields, Field};
289    ///
290    /// let fields: Fields = [("a thing", Field::empty())].into_iter().collect();
291    ///
292    /// assert!(fields.get("a thing").is_some());
293    /// assert!(fields.get("not a thing").is_none());
294    /// ```
295    pub fn get(&self, name: impl AsRef<str>) -> Option<&Field> {
296        self.fields.get(name.as_ref())
297    }
298
299    /// Get a mutable reference to the field with the provided `name`, if it exists.
300    ///
301    /// ```
302    /// # use ron::ser::path_meta::{Fields, Field};
303    ///
304    /// let mut fields: Fields = [("a thing", Field::empty())].into_iter().collect();
305    ///
306    /// assert!(fields.get_mut("a thing").is_some());
307    /// assert!(fields.get_mut("not a thing").is_none());
308    /// ```
309    pub fn get_mut(&mut self, name: impl AsRef<str>) -> Option<&mut Field> {
310        self.fields.get_mut(name.as_ref())
311    }
312
313    /// Insert a field with the given name into the map.
314    ///
315    /// ```
316    /// # use ron::ser::path_meta::{Fields, Field};
317    ///
318    /// let mut fields = Fields::default();
319    ///
320    /// assert!(fields.insert("field", Field::empty()).is_none());
321    /// assert!(fields.insert("field", Field::empty()).is_some());
322    /// ```
323    pub fn insert(&mut self, name: impl Into<String>, field: Field) -> Option<Field> {
324        self.fields.insert(name.into(), field)
325    }
326
327    /// Remove a field with the given name from the map.
328    ///
329    /// ```
330    /// # use ron::ser::path_meta::{Fields, Field};
331    ///
332    /// let mut fields: Fields = [("a", Field::empty())].into_iter().collect();
333    ///
334    /// assert_eq!(fields.remove("a"), Some(Field::empty()));
335    /// assert_eq!(fields.remove("a"), None);
336    /// ```
337    pub fn remove(&mut self, name: impl AsRef<str>) -> Option<Field> {
338        self.fields.remove(name.as_ref())
339    }
340
341    /// Get a mutable reference to the field with the provided `name`,
342    /// inserting an empty [`Field`] if it didn't exist.
343    ///
344    /// ```
345    /// # use ron::ser::path_meta::Fields;
346    ///
347    /// let mut fields = Fields::default();
348    ///
349    /// assert!(!fields.contains("thing"));
350    ///
351    /// fields.field("thing");
352    ///
353    /// assert!(fields.contains("thing"));
354    /// ```
355    pub fn field(&mut self, name: impl Into<String>) -> &mut Field {
356        self.fields.entry(name.into()).or_insert_with(Field::empty)
357    }
358}
359
360impl<K: Into<String>> FromIterator<(K, Field)> for Fields {
361    fn from_iter<T: IntoIterator<Item = (K, Field)>>(iter: T) -> Self {
362        Self {
363            fields: iter.into_iter().map(|(k, v)| (k.into(), v)).collect(),
364        }
365    }
366}