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 std::collections::HashMap;
102

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

            
105
/// The metadata and inner [`Fields`] of a field.
106
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
107
pub struct Field {
108
    doc: String,
109
    fields: Option<Fields>,
110
}
111

            
112
impl Field {
113
    /// Create a new empty field metadata.
114
    #[must_use]
115
1918
    pub const fn empty() -> Self {
116
1918
        Self {
117
1918
            doc: String::new(),
118
1918
            fields: None,
119
1918
        }
120
1918
    }
121

            
122
    /// Create a new field metadata from parts.
123
    pub fn new(doc: impl Into<String>, fields: Option<Fields>) -> Self {
124
        Self {
125
            doc: doc.into(),
126
            fields,
127
        }
128
    }
129

            
130
    /// Get a shared reference to the documentation metadata of this field.
131
    #[inline]
132
    #[must_use]
133
44
    pub fn doc(&self) -> &str {
134
44
        self.doc.as_str()
135
44
    }
136

            
137
    /// Get a mutable reference to the documentation metadata of this field.
138
    #[inline]
139
    #[must_use]
140
    pub fn doc_mut(&mut self) -> &mut String {
141
        &mut self.doc
142
    }
143

            
144
    /// Set the documentation metadata of this field.
145
    ///
146
    /// ```
147
    /// # use ron::ser::path_meta::Field;
148
    ///
149
    /// let mut field = Field::empty();
150
    ///
151
    /// assert_eq!(field.doc(), "");
152
    ///
153
    /// field.with_doc("some meta");
154
    ///
155
    /// assert_eq!(field.doc(), "some meta");
156
    /// ```
157
20
    pub fn with_doc(&mut self, doc: impl Into<String>) -> &mut Self {
158
20
        self.doc = doc.into();
159
20
        self
160
20
    }
161

            
162
    /// Get a shared reference to the inner fields of this field, if it has any.
163
    #[must_use]
164
    pub fn fields(&self) -> Option<&Fields> {
165
        self.fields.as_ref()
166
    }
167

            
168
    /// Get a mutable reference to the inner fields of this field, if it has any.
169
8220
    pub fn fields_mut(&mut self) -> Option<&mut Fields> {
170
8220
        self.fields.as_mut()
171
8220
    }
172

            
173
    /// Return whether this field has inner fields.
174
    ///
175
    /// ```
176
    /// # use ron::ser::path_meta::{Field, Fields};
177
    ///
178
    /// let mut field = Field::empty();
179
    ///
180
    /// assert!(!field.has_fields());
181
    ///
182
    /// field.with_fields(Some(Fields::default()));
183
    ///
184
    /// assert!(field.has_fields());
185
    /// ```
186
    #[must_use]
187
    pub fn has_fields(&self) -> bool {
188
        self.fields.is_some()
189
    }
190

            
191
    /// Set the inner fields of this field.
192
    ///
193
    /// ```
194
    /// # use ron::ser::path_meta::{Field, Fields};
195
    ///
196
    /// let mut field = Field::empty();
197
    ///
198
    /// assert!(!field.has_fields());
199
    ///
200
    /// field.with_fields(Some(Fields::default()));
201
    ///
202
    /// assert!(field.has_fields());
203
    ///
204
    /// field.with_fields(None);
205
    ///  
206
    /// assert!(!field.has_fields());
207
    /// ```
208
548
    pub fn with_fields(&mut self, fields: Option<Fields>) -> &mut Self {
209
548
        self.fields = fields;
210
548
        self
211
548
    }
212

            
213
    /// Ergonomic shortcut for building some inner fields.
214
    ///
215
    /// ```
216
    /// # use ron::ser::path_meta::Field;
217
    ///
218
    /// let mut field = Field::empty();
219
    ///
220
    /// field.build_fields(|fields| {
221
    ///     fields.field("inner field");
222
    /// });
223
    ///
224
    /// assert_eq!(field.fields().map(|fields| fields.contains("inner field")), Some(true));
225
    /// ```
226
8
    pub fn build_fields(&mut self, builder: impl FnOnce(&mut Fields)) -> &mut Self {
227
8
        let mut fields = Fields::default();
228
8
        builder(&mut fields);
229
8
        self.with_fields(Some(fields));
230
8
        self
231
8
    }
232
}
233

            
234
/// Mapping of names to [`Field`]s.
235
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
236
pub struct Fields {
237
    fields: HashMap<String, Field>,
238
}
239

            
240
impl Fields {
241
    /// Return a new, empty metadata field map.
242
    #[must_use]
243
    pub fn new() -> Self {
244
        Self::default()
245
    }
246

            
247
    /// Return whether this field map contains no fields.
248
    ///
249
    /// ```
250
    /// # use ron::ser::path_meta::{Fields, Field};
251
    ///
252
    /// let mut fields = Fields::default();
253
    ///
254
    /// assert!(fields.is_empty());
255
    ///
256
    /// fields.insert("", Field::empty());
257
    ///
258
    /// assert!(!fields.is_empty());
259
    /// ```
260
    #[must_use]
261
    pub fn is_empty(&self) -> bool {
262
        self.fields.is_empty()
263
    }
264

            
265
    /// Return whether this field map contains a field with the given name.
266
    ///
267
    /// ```
268
    /// # use ron::ser::path_meta::{Fields, Field};
269
    ///
270
    /// let fields: Fields = [("a thing", Field::empty())].into_iter().collect();
271
    ///
272
    /// assert!(fields.contains("a thing"));
273
    /// assert!(!fields.contains("not a thing"));
274
    /// ```
275
    pub fn contains(&self, name: impl AsRef<str>) -> bool {
276
        self.fields.contains_key(name.as_ref())
277
    }
278

            
279
    /// Get a reference to the field with the provided `name`, if it exists.
280
    ///
281
    /// ```
282
    /// # use ron::ser::path_meta::{Fields, Field};
283
    ///
284
    /// let fields: Fields = [("a thing", Field::empty())].into_iter().collect();
285
    ///
286
    /// assert!(fields.get("a thing").is_some());
287
    /// assert!(fields.get("not a thing").is_none());
288
    /// ```
289
    pub fn get(&self, name: impl AsRef<str>) -> Option<&Field> {
290
        self.fields.get(name.as_ref())
291
    }
292

            
293
    /// Get a mutable reference to the field with the provided `name`, if it exists.
294
    ///
295
    /// ```
296
    /// # use ron::ser::path_meta::{Fields, Field};
297
    ///
298
    /// let mut fields: Fields = [("a thing", Field::empty())].into_iter().collect();
299
    ///
300
    /// assert!(fields.get_mut("a thing").is_some());
301
    /// assert!(fields.get_mut("not a thing").is_none());
302
    /// ```
303
    pub fn get_mut(&mut self, name: impl AsRef<str>) -> Option<&mut Field> {
304
        self.fields.get_mut(name.as_ref())
305
    }
306

            
307
    /// Insert a field with the given name into the map.
308
    ///
309
    /// ```
310
    /// # use ron::ser::path_meta::{Fields, Field};
311
    ///
312
    /// let mut fields = Fields::default();
313
    ///
314
    /// assert!(fields.insert("field", Field::empty()).is_none());
315
    /// assert!(fields.insert("field", Field::empty()).is_some());
316
    /// ```
317
44
    pub fn insert(&mut self, name: impl Into<String>, field: Field) -> Option<Field> {
318
44
        self.fields.insert(name.into(), field)
319
44
    }
320

            
321
    /// Remove a field with the given name from the map.
322
    ///
323
    /// ```
324
    /// # use ron::ser::path_meta::{Fields, Field};
325
    ///
326
    /// let mut fields: Fields = [("a", Field::empty())].into_iter().collect();
327
    ///
328
    /// assert_eq!(fields.remove("a"), Some(Field::empty()));
329
    /// assert_eq!(fields.remove("a"), None);
330
    /// ```
331
60
    pub fn remove(&mut self, name: impl AsRef<str>) -> Option<Field> {
332
60
        self.fields.remove(name.as_ref())
333
60
    }
334

            
335
    /// Get a mutable reference to the field with the provided `name`,
336
    /// inserting an empty [`Field`] if it didn't exist.
337
    ///
338
    /// ```
339
    /// # use ron::ser::path_meta::Fields;
340
    ///
341
    /// let mut fields = Fields::default();
342
    ///
343
    /// assert!(!fields.contains("thing"));
344
    ///
345
    /// fields.field("thing");
346
    ///
347
    /// assert!(fields.contains("thing"));
348
    /// ```
349
24
    pub fn field(&mut self, name: impl Into<String>) -> &mut Field {
350
24
        self.fields.entry(name.into()).or_insert_with(Field::empty)
351
24
    }
352
}
353

            
354
impl<K: Into<String>> FromIterator<(K, Field)> for Fields {
355
    fn from_iter<T: IntoIterator<Item = (K, Field)>>(iter: T) -> Self {
356
        Self {
357
            fields: iter.into_iter().map(|(k, v)| (k.into(), v)).collect(),
358
        }
359
    }
360
}