Skip to main content

deser_cbor/
tag.rs

1//! Support for CBOR tags (see the crate documentation).
2use alloc::vec::Vec;
3use core::fmt;
4
5use alloc::borrow::Cow;
6
7use deser_core::State;
8use deser_core::de::{Deserialize, OwnedSink, Sink, SinkHandle};
9use deser_core::ser::{Describe, Emit, Serialize};
10use deser_core::{Atom, ContainerShape, Error};
11
12/// The tags of a data item, attached as event data to its first event.
13///
14/// The deserializer publishes the tags it read, the serializer writes the
15/// tags in front of the data item.  The tags are ordered from the outermost
16/// to the innermost tag.
17#[derive(Debug, Default)]
18pub(crate) struct Tags(pub(crate) Vec<u64>);
19
20// Event data is reset with `clone_from` which retains the memory of the
21// vector only if it's forwarded (derived clones do not do that).
22impl Clone for Tags {
23    fn clone(&self) -> Tags {
24        Tags(self.0.clone())
25    }
26
27    fn clone_from(&mut self, source: &Tags) {
28        self.0.clone_from(&source.0);
29    }
30}
31
32/// Takes the outermost tag of the current data item from the state.
33///
34/// This is intended to be called by sinks from within
35/// [`Sink::atom`], [`Sink::map`] or [`Sink::seq`].  Every call removes one
36/// tag, so calling this repeatedly returns the nested tags from the outside
37/// in.  Returns `None` if there are no (more) tags or the data format does
38/// not support tags.
39///
40/// ```
41/// use deser::State;
42///
43/// fn all_tags(state: &mut State) -> Vec<u64> {
44///     std::iter::from_fn(|| deser_cbor::take_tag(state)).collect()
45/// }
46/// ```
47pub fn take_tag(state: &mut State) -> Option<u64> {
48    if state.event::<Tags>().is_some_and(|tags| !tags.0.is_empty()) {
49        let tags = &mut state.event_mut::<Tags>().0;
50        let tag = tags.remove(0);
51        // without tags left they are detached so that values that capture
52        // event data do not keep an empty list which would replace the tags
53        // of a wrapper
54        if tags.is_empty() {
55            state.take_event::<Tags>();
56        }
57        Some(tag)
58    } else {
59        None
60    }
61}
62
63/// Registers a tag to be written in front of the next data item.
64///
65/// This is what [`Tagged`] uses internally.  It must be called from
66/// [`Serialize::serialize`] and applies to the value serialized from that
67/// call.  The tag is attached to the first event of the value (see
68/// [`State::event`]), serializers which do not support tags ignore it.
69pub fn push_tag(state: &mut State, tag: u64) {
70    state.event_mut::<Tags>().0.push(tag);
71}
72
73/// A value with an optional CBOR tag.
74///
75/// When serialized the tag is written in front of the value, when
76/// deserialized the tag (if there is one) is captured.  If the value has
77/// multiple tags, the outermost tag is captured and the inner tags are left
78/// for the value (so `Tagged<Tagged<T>>` captures two tags).
79///
80/// ```
81/// use deser_cbor::Tagged;
82///
83/// // 1(1363896240): an epoch based date/time
84/// let bytes = deser_cbor::to_vec(&Tagged::new(1, 1363896240u64)).unwrap();
85/// assert_eq!(bytes, [0xc1, 0x1a, 0x51, 0x4b, 0x67, 0xb0]);
86///
87/// let value: Tagged<u64> = deser_cbor::from_slice(&bytes).unwrap();
88/// assert_eq!(value.tag, Some(1));
89/// assert_eq!(value.value, 1363896240);
90/// ```
91///
92/// Other formats do not support tags.  When serializing to such formats the
93/// tag is dropped, when deserializing the tag is `None`.
94#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
95pub struct Tagged<T> {
96    /// The tag of the value.
97    pub tag: Option<u64>,
98    /// The value.
99    pub value: T,
100}
101
102impl<T> Tagged<T> {
103    /// Creates a tagged value.
104    pub fn new(tag: u64, value: T) -> Tagged<T> {
105        Tagged {
106            tag: Some(tag),
107            value,
108        }
109    }
110
111    /// Creates a value without a tag.
112    pub fn untagged(value: T) -> Tagged<T> {
113        Tagged { tag: None, value }
114    }
115
116    /// Returns the inner value.
117    pub fn into_inner(self) -> T {
118        self.value
119    }
120}
121
122impl<T: fmt::Debug> fmt::Debug for Tagged<T> {
123    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
124        match self.tag {
125            Some(tag) => {
126                write!(f, "{}(", tag)?;
127                fmt::Debug::fmt(&self.value, f)?;
128                write!(f, ")")
129            }
130            None => fmt::Debug::fmt(&self.value, f),
131        }
132    }
133}
134
135impl<T: Serialize> Serialize for Tagged<T> {
136    fn serialize<'a>(this: &'a Self, state: &mut State) -> Result<Emit<'a>, Error> {
137        // the tag is added after the value attached its data (the tags of a
138        // recorded value, the tags of inner `Tagged`), in front of its tags
139        let emit = T::serialize(&this.value, state)?;
140        if let Some(tag) = this.tag {
141            state.event_mut::<Tags>().0.insert(0, tag);
142        }
143        Ok(emit)
144    }
145
146    fn finish(this: &Self, state: &mut State) -> Result<(), Error> {
147        T::finish(&this.value, state)
148    }
149
150    fn is_optional(this: &Self) -> bool {
151        T::is_optional(&this.value)
152    }
153
154    fn container_shape(this: &Self) -> ContainerShape {
155        T::container_shape(&this.value)
156    }
157
158    fn describe(this: &Self, d: &mut dyn Describe) {
159        T::describe(&this.value, d)
160    }
161}
162
163impl<'de, T: Deserialize<'de>> Deserialize<'de> for Tagged<T> {
164    fn deserialize_into<'out>(
165        out: &'out mut Option<Self>,
166        state: &mut State,
167    ) -> SinkHandle<'out, 'de> {
168        SinkHandle::arena(
169            TaggedSink {
170                out,
171                slot: None,
172                compound: None,
173                tag: None,
174            },
175            state,
176        )
177    }
178
179    fn expecting() -> Cow<'static, str> {
180        T::expecting()
181    }
182
183    fn describe_type(d: &mut dyn Describe) {
184        T::describe_type(d)
185    }
186}
187
188struct TaggedSink<'a, 'de, T> {
189    out: &'a mut Option<Tagged<T>>,
190    // atoms are deserialized directly into this slot, maps and sequences
191    // need a sink that lives across calls
192    slot: Option<T>,
193    compound: Option<OwnedSink<'de, T>>,
194    tag: Option<u64>,
195}
196
197impl<'a, 'de, T: Deserialize<'de>> TaggedSink<'a, 'de, T> {
198    fn compound(&mut self, state: &mut State) -> &mut dyn Sink<'de> {
199        self.compound
200            .get_or_insert_with(|| OwnedSink::deserialize(state))
201            .get_mut()
202    }
203}
204
205impl<'a, 'de, T: Deserialize<'de>> Sink<'de> for TaggedSink<'a, 'de, T> {
206    fn atom(&mut self, atom: Atom, state: &mut State) -> Result<(), Error> {
207        self.tag = take_tag(state);
208        let mut sink = T::deserialize_into(&mut self.slot, state);
209        sink.atom(atom, state)?;
210        sink.finish(state)
211    }
212
213    fn borrowed_atom(&mut self, atom: Atom<'de>, state: &mut State) -> Result<(), Error> {
214        self.tag = take_tag(state);
215        let mut sink = T::deserialize_into(&mut self.slot, state);
216        sink.borrowed_atom(atom, state)?;
217        sink.finish(state)
218    }
219
220    fn map(&mut self, state: &mut State) -> Result<(), Error> {
221        self.tag = take_tag(state);
222        self.compound(state).map(state)
223    }
224
225    fn seq(&mut self, state: &mut State) -> Result<(), Error> {
226        self.tag = take_tag(state);
227        self.compound(state).seq(state)
228    }
229
230    fn next_key(&mut self, state: &mut State) -> Result<SinkHandle<'_, 'de>, Error> {
231        self.compound(state).next_key(state)
232    }
233
234    fn next_value(&mut self, state: &mut State) -> Result<SinkHandle<'_, 'de>, Error> {
235        self.compound(state).next_value(state)
236    }
237
238    fn value_for_key(
239        &mut self,
240        key: &str,
241        state: &mut State,
242    ) -> Result<Option<SinkHandle<'_, 'de>>, Error> {
243        self.compound(state).value_for_key(key, state)
244    }
245
246    fn recover(&mut self, err: Error, state: &mut State) -> Result<(), Error> {
247        match self.compound {
248            Some(ref mut compound) => compound.get_mut().recover(err, state),
249            None => Err(err),
250        }
251    }
252
253    fn finish(&mut self, state: &mut State) -> Result<(), Error> {
254        let value = match self.compound {
255            Some(ref mut compound) => {
256                compound.get_mut().finish(state)?;
257                compound.take()
258            }
259            None => self.slot.take(),
260        };
261        let tag = self.tag;
262        *self.out = value.map(|value| Tagged { tag, value });
263        Ok(())
264    }
265
266    fn expecting(&self) -> Cow<'_, str> {
267        if let Some(ref compound) = self.compound {
268            return compound.get().expecting();
269        }
270        T::expecting()
271    }
272}