Coverage Report

Created: 2025-12-31 06:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/sfv-0.14.0/src/ref_serializer.rs
Line
Count
Source
1
use std::borrow::BorrowMut;
2
3
use crate::{serializer::Serializer, KeyRef, RefBareItem};
4
#[cfg(feature = "parsed-types")]
5
use crate::{Item, ListEntry};
6
7
/// Serializes `Item` field value components incrementally.
8
///
9
/// Note: The serialization conforms to [RFC 9651], meaning that
10
/// [`Dates`][crate::Date] and [`Display Strings`][RefBareItem::DisplayString],
11
/// which cause parsing errors under [RFC 8941], will be serialized
12
/// unconditionally. The consumer of this API is responsible for determining
13
/// whether it is valid to serialize these bare items for any specific field.
14
///
15
/// [RFC 8941]: <https://httpwg.org/specs/rfc8941.html>
16
/// [RFC 9651]: <https://httpwg.org/specs/rfc9651.html>
17
/// ```
18
/// use sfv::{KeyRef, ItemSerializer};
19
///
20
/// # fn main() -> Result<(), sfv::Error> {
21
/// let serialized_item = ItemSerializer::new()
22
///     .bare_item(11)
23
///     .parameter(KeyRef::from_str("foo")?, true)
24
///     .finish();
25
///
26
/// assert_eq!(serialized_item, "11;foo");
27
/// # Ok(())
28
/// # }
29
/// ```
30
// https://httpwg.org/specs/rfc9651.html#ser-item
31
#[derive(Debug)]
32
#[must_use]
33
pub struct ItemSerializer<W> {
34
    buffer: W,
35
}
36
37
impl Default for ItemSerializer<String> {
38
0
    fn default() -> Self {
39
0
        Self::new()
40
0
    }
41
}
42
43
impl ItemSerializer<String> {
44
    /// Creates a serializer that writes into a new string.
45
0
    pub fn new() -> Self {
46
0
        Self {
47
0
            buffer: String::new(),
48
0
        }
49
0
    }
50
}
51
52
impl<'a> ItemSerializer<&'a mut String> {
53
    /// Creates a serializer that writes into the given string.
54
0
    pub fn with_buffer(buffer: &'a mut String) -> Self {
55
0
        Self { buffer }
56
0
    }
57
}
58
59
impl<W: BorrowMut<String>> ItemSerializer<W> {
60
    /// Serializes the given bare item.
61
    ///
62
    /// Returns a serializer for the item's parameters.
63
0
    pub fn bare_item<'b>(
64
0
        mut self,
65
0
        bare_item: impl Into<RefBareItem<'b>>,
66
0
    ) -> ParameterSerializer<W> {
67
0
        Serializer::serialize_bare_item(bare_item, self.buffer.borrow_mut());
68
0
        ParameterSerializer {
69
0
            buffer: self.buffer,
70
0
        }
71
0
    }
72
}
73
74
/// Serializes parameters incrementally.
75
#[derive(Debug)]
76
#[must_use]
77
pub struct ParameterSerializer<W> {
78
    buffer: W,
79
}
80
81
impl<W: BorrowMut<String>> ParameterSerializer<W> {
82
    /// Serializes a parameter with the given name and value.
83
    ///
84
    /// Returns the serializer.
85
0
    pub fn parameter<'b>(mut self, name: &KeyRef, value: impl Into<RefBareItem<'b>>) -> Self {
86
0
        Serializer::serialize_parameter(name, value, self.buffer.borrow_mut());
87
0
        self
88
0
    }
89
90
    /// Serializes the given parameters.
91
    ///
92
    /// Returns the serializer.
93
0
    pub fn parameters<'b>(
94
0
        mut self,
95
0
        params: impl IntoIterator<Item = (impl AsRef<KeyRef>, impl Into<RefBareItem<'b>>)>,
96
0
    ) -> Self {
97
0
        for (name, value) in params {
98
0
            Serializer::serialize_parameter(name.as_ref(), value, self.buffer.borrow_mut());
99
0
        }
100
0
        self
101
0
    }
Unexecuted instantiation: <sfv::ref_serializer::ParameterSerializer<alloc::string::String>>::parameters::<&sfv::key::Key, &sfv::GenericBareItem<sfv::string::String, alloc::vec::Vec<u8>, sfv::token::Token, alloc::string::String>, &indexmap::map::IndexMap<sfv::key::Key, sfv::GenericBareItem<sfv::string::String, alloc::vec::Vec<u8>, sfv::token::Token, alloc::string::String>>>
Unexecuted instantiation: <sfv::ref_serializer::ParameterSerializer<&mut alloc::string::String>>::parameters::<&sfv::key::Key, &sfv::GenericBareItem<sfv::string::String, alloc::vec::Vec<u8>, sfv::token::Token, alloc::string::String>, &indexmap::map::IndexMap<sfv::key::Key, sfv::GenericBareItem<sfv::string::String, alloc::vec::Vec<u8>, sfv::token::Token, alloc::string::String>>>
102
103
    /// Finishes parameter serialization and returns the serializer's output.
104
    #[must_use]
105
0
    pub fn finish(self) -> W {
106
0
        self.buffer
107
0
    }
108
}
109
110
0
fn maybe_write_separator(buffer: &mut String, first: &mut bool) {
111
0
    if *first {
112
0
        *first = false;
113
0
    } else {
114
0
        buffer.push_str(", ");
115
0
    }
116
0
}
117
118
/// Serializes `List` field value components incrementally.
119
///
120
/// Note: The serialization conforms to [RFC 9651], meaning that
121
/// [`Dates`][crate::Date] and [`Display Strings`][RefBareItem::DisplayString],
122
/// which cause parsing errors under [RFC 8941], will be serialized
123
/// unconditionally. The consumer of this API is responsible for determining
124
/// whether it is valid to serialize these bare items for any specific field.
125
///
126
/// [RFC 8941]: <https://httpwg.org/specs/rfc8941.html>
127
/// [RFC 9651]: <https://httpwg.org/specs/rfc9651.html>
128
/// ```
129
/// use sfv::{KeyRef, StringRef, TokenRef, ListSerializer};
130
///
131
/// # fn main() -> Result<(), sfv::Error> {
132
/// let mut ser = ListSerializer::new();
133
///
134
/// ser.bare_item(11)
135
///     .parameter(KeyRef::from_str("foo")?, true);
136
///
137
/// {
138
///     let mut ser = ser.inner_list();
139
///
140
///     ser.bare_item(TokenRef::from_str("abc")?)
141
///         .parameter(KeyRef::from_str("abc_param")?, false);
142
///
143
///     ser.bare_item(TokenRef::from_str("def")?);
144
///
145
///     ser.finish()
146
///         .parameter(KeyRef::from_str("bar")?, StringRef::from_str("val")?);
147
/// }
148
///
149
/// assert_eq!(
150
///     ser.finish().as_deref(),
151
///     Some(r#"11;foo, (abc;abc_param=?0 def);bar="val""#),
152
/// );
153
/// # Ok(())
154
/// # }
155
/// ```
156
// https://httpwg.org/specs/rfc9651.html#ser-list
157
#[derive(Debug)]
158
#[must_use]
159
pub struct ListSerializer<W> {
160
    buffer: W,
161
    first: bool,
162
}
163
164
impl Default for ListSerializer<String> {
165
0
    fn default() -> Self {
166
0
        Self::new()
167
0
    }
168
}
169
170
impl ListSerializer<String> {
171
    /// Creates a serializer that writes into a new string.
172
0
    pub fn new() -> Self {
173
0
        Self {
174
0
            buffer: String::new(),
175
0
            first: true,
176
0
        }
177
0
    }
178
}
179
180
impl<'a> ListSerializer<&'a mut String> {
181
    /// Creates a serializer that writes into the given string.
182
0
    pub fn with_buffer(buffer: &'a mut String) -> Self {
183
0
        Self {
184
0
            buffer,
185
0
            first: true,
186
0
        }
187
0
    }
188
}
189
190
impl<W: BorrowMut<String>> ListSerializer<W> {
191
    /// Serializes the given bare item as a member of the list.
192
    ///
193
    /// Returns a serializer for the item's parameters.
194
0
    pub fn bare_item<'b>(
195
0
        &mut self,
196
0
        bare_item: impl Into<RefBareItem<'b>>,
197
0
    ) -> ParameterSerializer<&mut String> {
198
0
        let buffer = self.buffer.borrow_mut();
199
0
        maybe_write_separator(buffer, &mut self.first);
200
0
        Serializer::serialize_bare_item(bare_item, buffer);
201
0
        ParameterSerializer { buffer }
202
0
    }
203
204
    /// Opens an inner list, returning a serializer to be used for its items and
205
    /// parameters.
206
0
    pub fn inner_list(&mut self) -> InnerListSerializer {
207
0
        let buffer = self.buffer.borrow_mut();
208
0
        maybe_write_separator(buffer, &mut self.first);
209
0
        buffer.push('(');
210
0
        InnerListSerializer {
211
0
            buffer: Some(buffer),
212
0
        }
213
0
    }
214
215
    /// Serializes the given members of the list.
216
    #[cfg(feature = "parsed-types")]
217
0
    pub fn members<'b>(&mut self, members: impl IntoIterator<Item = &'b ListEntry>) {
218
0
        for value in members {
219
0
            match value {
220
0
                ListEntry::Item(value) => {
221
0
                    _ = self.bare_item(&value.bare_item).parameters(&value.params);
222
0
                }
223
0
                ListEntry::InnerList(value) => {
224
0
                    let mut ser = self.inner_list();
225
0
                    ser.items(&value.items);
226
0
                    _ = ser.finish().parameters(&value.params);
227
0
                }
228
            }
229
        }
230
0
    }
231
232
    /// Finishes serialization of the list and returns the underlying output.
233
    ///
234
    /// Returns `None` if and only if no members were serialized, as [empty
235
    /// lists are not meant to be serialized at
236
    /// all](https://httpwg.org/specs/rfc9651.html#text-serialize).
237
    #[must_use]
238
0
    pub fn finish(self) -> Option<W> {
239
0
        if self.first {
240
0
            None
241
        } else {
242
0
            Some(self.buffer)
243
        }
244
0
    }
245
}
246
247
/// Serializes `Dictionary` field value components incrementally.
248
///
249
/// Note: The serialization conforms to [RFC 9651], meaning that
250
/// [`Dates`][crate::Date] and [`Display Strings`][RefBareItem::DisplayString],
251
/// which cause parsing errors under [RFC 8941], will be serialized
252
/// unconditionally. The consumer of this API is responsible for determining
253
/// whether it is valid to serialize these bare items for any specific field.
254
///
255
/// [RFC 8941]: <https://httpwg.org/specs/rfc8941.html>
256
/// [RFC 9651]: <https://httpwg.org/specs/rfc9651.html>
257
///
258
/// ```
259
/// use sfv::{KeyRef, StringRef, TokenRef, DictSerializer, Decimal};
260
///
261
/// # fn main() -> Result<(), sfv::Error> {
262
/// let mut ser = DictSerializer::new();
263
///
264
/// ser.bare_item(KeyRef::from_str("member1")?, 11)
265
///     .parameter(KeyRef::from_str("foo")?, true);
266
///
267
/// {
268
///   let mut ser = ser.inner_list(KeyRef::from_str("member2")?);
269
///
270
///   ser.bare_item(TokenRef::from_str("abc")?)
271
///       .parameter(KeyRef::from_str("abc_param")?, false);
272
///
273
///   ser.bare_item(TokenRef::from_str("def")?);
274
///
275
///   ser.finish()
276
///      .parameter(KeyRef::from_str("bar")?, StringRef::from_str("val")?);
277
/// }
278
///
279
/// ser.bare_item(KeyRef::from_str("member3")?, Decimal::try_from(12.34566)?);
280
///
281
/// assert_eq!(
282
///     ser.finish().as_deref(),
283
///     Some(r#"member1=11;foo, member2=(abc;abc_param=?0 def);bar="val", member3=12.346"#),
284
/// );
285
/// # Ok(())
286
/// # }
287
/// ```
288
// https://httpwg.org/specs/rfc9651.html#ser-dictionary
289
#[derive(Debug)]
290
#[must_use]
291
pub struct DictSerializer<W> {
292
    buffer: W,
293
    first: bool,
294
}
295
296
impl Default for DictSerializer<String> {
297
0
    fn default() -> Self {
298
0
        Self::new()
299
0
    }
300
}
301
302
impl DictSerializer<String> {
303
    /// Creates a serializer that writes into a new string.
304
0
    pub fn new() -> Self {
305
0
        Self {
306
0
            buffer: String::new(),
307
0
            first: true,
308
0
        }
309
0
    }
310
}
311
312
impl<'a> DictSerializer<&'a mut String> {
313
    /// Creates a serializer that writes into the given string.
314
0
    pub fn with_buffer(buffer: &'a mut String) -> Self {
315
0
        Self {
316
0
            buffer,
317
0
            first: true,
318
0
        }
319
0
    }
320
}
321
322
impl<W: BorrowMut<String>> DictSerializer<W> {
323
    /// Serializes the given bare item as a member of the dictionary with the
324
    /// given key.
325
    ///
326
    /// Returns a serializer for the item's parameters.
327
0
    pub fn bare_item<'b>(
328
0
        &mut self,
329
0
        name: &KeyRef,
330
0
        value: impl Into<RefBareItem<'b>>,
331
0
    ) -> ParameterSerializer<&mut String> {
332
0
        let buffer = self.buffer.borrow_mut();
333
0
        maybe_write_separator(buffer, &mut self.first);
334
0
        Serializer::serialize_key(name, buffer);
335
0
        let value = value.into();
336
0
        if value != RefBareItem::Boolean(true) {
337
0
            buffer.push('=');
338
0
            Serializer::serialize_bare_item(value, buffer);
339
0
        }
340
0
        ParameterSerializer { buffer }
341
0
    }
342
343
    /// Opens an inner list with the given key, returning a serializer to be
344
    /// used for its items and parameters.
345
0
    pub fn inner_list(&mut self, name: &KeyRef) -> InnerListSerializer {
346
0
        let buffer = self.buffer.borrow_mut();
347
0
        maybe_write_separator(buffer, &mut self.first);
348
0
        Serializer::serialize_key(name, buffer);
349
0
        buffer.push_str("=(");
350
0
        InnerListSerializer {
351
0
            buffer: Some(buffer),
352
0
        }
353
0
    }
354
355
    /// Serializes the given members of the dictionary.
356
    #[cfg(feature = "parsed-types")]
357
0
    pub fn members<'b>(
358
0
        &mut self,
359
0
        members: impl IntoIterator<Item = (impl AsRef<KeyRef>, &'b ListEntry)>,
360
0
    ) {
361
0
        for (name, value) in members {
362
0
            match value {
363
0
                ListEntry::Item(value) => {
364
0
                    _ = self
365
0
                        .bare_item(name.as_ref(), &value.bare_item)
366
0
                        .parameters(&value.params);
367
0
                }
368
0
                ListEntry::InnerList(value) => {
369
0
                    let mut ser = self.inner_list(name.as_ref());
370
0
                    ser.items(&value.items);
371
0
                    _ = ser.finish().parameters(&value.params);
372
0
                }
373
            }
374
        }
375
0
    }
376
377
    /// Finishes serialization of the dictionary and returns the underlying output.
378
    ///
379
    /// Returns `None` if and only if no members were serialized, as [empty
380
    /// dictionaries are not meant to be serialized at
381
    /// all](https://httpwg.org/specs/rfc9651.html#text-serialize).
382
    #[must_use]
383
0
    pub fn finish(self) -> Option<W> {
384
0
        if self.first {
385
0
            None
386
        } else {
387
0
            Some(self.buffer)
388
        }
389
0
    }
390
}
391
392
/// Serializes inner lists incrementally.
393
///
394
/// The inner list will be closed automatically when the serializer is dropped.
395
/// To set the inner list's parameters, call [`InnerListSerializer::finish`].
396
///
397
/// Failing to drop the serializer or call its `finish` method will result in
398
/// an invalid serialization that lacks a closing `)` character.
399
// https://httpwg.org/specs/rfc9651.html#ser-innerlist
400
#[derive(Debug)]
401
#[must_use]
402
pub struct InnerListSerializer<'a> {
403
    buffer: Option<&'a mut String>,
404
}
405
406
impl Drop for InnerListSerializer<'_> {
407
0
    fn drop(&mut self) {
408
0
        if let Some(ref mut buffer) = self.buffer {
409
0
            buffer.push(')');
410
0
        }
411
0
    }
412
}
413
414
impl<'a> InnerListSerializer<'a> {
415
    /// Serializes the given bare item as a member of the inner list.
416
    ///
417
    /// Returns a serializer for the item's parameters.
418
    #[allow(clippy::missing_panics_doc)] // The unwrap is safe by construction.
419
0
    pub fn bare_item<'b>(
420
0
        &mut self,
421
0
        bare_item: impl Into<RefBareItem<'b>>,
422
0
    ) -> ParameterSerializer<&mut String> {
423
0
        let buffer = self.buffer.as_mut().unwrap();
424
0
        if !buffer.is_empty() && !buffer.ends_with('(') {
425
0
            buffer.push(' ');
426
0
        }
427
0
        Serializer::serialize_bare_item(bare_item, buffer);
428
0
        ParameterSerializer { buffer }
429
0
    }
430
431
    /// Serializes the given items as members of the inner list.
432
    #[cfg(feature = "parsed-types")]
433
0
    pub fn items<'b>(&mut self, items: impl IntoIterator<Item = &'b Item>) {
434
0
        for item in items {
435
0
            _ = self.bare_item(&item.bare_item).parameters(&item.params);
436
0
        }
437
0
    }
438
439
    /// Closes the inner list and returns a serializer for its parameters.
440
    #[allow(clippy::missing_panics_doc)]
441
0
    pub fn finish(mut self) -> ParameterSerializer<&'a mut String> {
442
0
        let buffer = self.buffer.take().unwrap();
443
0
        buffer.push(')');
444
0
        ParameterSerializer { buffer }
445
0
    }
446
}