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

            
101
use alloc::string::String;
102

            
103
use serde_derive::{Deserialize, Serialize};
104

            
105
#[cfg(feature = "std")]
106
use std::collections::HashMap as FieldsInner;
107

            
108
#[cfg(not(feature = "std"))]
109
use alloc::collections::BTreeMap as FieldsInner;
110

            
111
/// The metadata and inner [`Fields`] of a field.
112
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
113
pub struct Field {
114
    doc: String,
115
    fields: Option<Fields>,
116
}
117

            
118
impl Field {
119
    /// Create a new empty field metadata.
120
    #[must_use]
121
1946
    pub const fn empty() -> Self {
122
1946
        Self {
123
1946
            doc: String::new(),
124
1946
            fields: None,
125
1946
        }
126
1946
    }
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
44
    pub fn doc(&self) -> &str {
140
44
        self.doc.as_str()
141
44
    }
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
20
    pub fn with_doc(&mut self, doc: impl Into<String>) -> &mut Self {
164
20
        self.doc = doc.into();
165
20
        self
166
20
    }
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
8340
    pub fn fields_mut(&mut self) -> Option<&mut Fields> {
176
8340
        self.fields.as_mut()
177
8340
    }
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
556
    pub fn with_fields(&mut self, fields: Option<Fields>) -> &mut Self {
215
556
        self.fields = fields;
216
556
        self
217
556
    }
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
8
    pub fn build_fields(&mut self, builder: impl FnOnce(&mut Fields)) -> &mut Self {
233
8
        let mut fields = Fields::default();
234
8
        builder(&mut fields);
235
8
        self.with_fields(Some(fields));
236
8
        self
237
8
    }
238
}
239

            
240
/// Mapping of names to [`Field`]s.
241
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
242
pub struct Fields {
243
    fields: FieldsInner<String, Field>,
244
}
245

            
246
impl 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
44
    pub fn insert(&mut self, name: impl Into<String>, field: Field) -> Option<Field> {
324
44
        self.fields.insert(name.into(), field)
325
44
    }
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
60
    pub fn remove(&mut self, name: impl AsRef<str>) -> Option<Field> {
338
60
        self.fields.remove(name.as_ref())
339
60
    }
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
24
    pub fn field(&mut self, name: impl Into<String>) -> &mut Field {
356
24
        self.fields.entry(name.into()).or_insert_with(Field::empty)
357
24
    }
358
}
359

            
360
impl<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
}