Skip to main content

ytsaurus_yson/
de.rs

1use crate::access::{AttributesWrapperAccess, CommaSeparated, EmptyMapAccess, EnumAccess};
2use crate::lexer::YsonIterator;
3use crate::node::{Token, YsonNode, YsonValue};
4use crate::{access::FlatStructAccess, error::YsonError};
5use serde::Deserialize;
6use serde::de::{self, MapAccess, SeqAccess, Visitor};
7use std::borrow::Cow;
8use std::collections::BTreeMap;
9
10/// A structure for deserializing YSON data into Rust types.
11pub struct Deserializer<'de> {
12    pub(crate) lexer: YsonIterator<'de>,
13    pub(crate) is_reading_attributes: bool,
14    depth: usize,
15    max_depth: usize,
16}
17
18impl<'de> Deserializer<'de> {
19    /// Creates a new YSON deserializer from the given byte slice.
20    ///
21    /// # Arguments
22    ///
23    /// * `input` - The raw byte slice containing YSON data.
24    /// * `is_binary` - Set to `true` if the input is in YSON binary format,
25    ///   or `false` if it is in YSON text format.
26    ///
27    /// # Examples
28    ///
29    /// ```
30    /// use ytsaurus_yson::de::Deserializer;
31    /// use serde::Deserialize;
32    ///
33    /// let input = b"42";
34    /// let mut de = Deserializer::from_bytes(input, false);
35    /// let value = i64::deserialize(&mut de).unwrap();
36    ///
37    /// assert_eq!(value, 42);
38    /// ```
39    #[must_use]
40    pub fn from_bytes(input: &'de [u8], is_binary: bool) -> Self {
41        Deserializer {
42            lexer: YsonIterator::new(input, is_binary),
43            is_reading_attributes: false,
44            depth: 0,
45            max_depth: 128,
46        }
47    }
48
49    pub(crate) fn enter_recursion(&mut self) -> Result<(), YsonError> {
50        self.depth += 1;
51        if self.depth > self.max_depth {
52            return Err(YsonError::Custom("Recursion limit exceeded".into()));
53        }
54        Ok(())
55    }
56
57    pub(crate) fn leave_recursion(&mut self) {
58        self.depth -= 1;
59    }
60
61    fn skip_attributes(&mut self) -> Result<(), YsonError> {
62        if self.lexer.peek_byte()? == b'<' {
63            self.enter_recursion()?;
64            self.lexer.next_token()?;
65            let mut attr_depth = 1;
66            while attr_depth > 0 {
67                match self.lexer.next_token()? {
68                    Token::BeginAttributes => attr_depth += 1,
69                    Token::EndAttributes => attr_depth -= 1,
70                    _ => {}
71                }
72                if attr_depth > self.max_depth {
73                    return Err(YsonError::Custom("Attributes nesting too deep".into()));
74                }
75            }
76            self.leave_recursion();
77        }
78        Ok(())
79    }
80}
81
82macro_rules! delegate_skip_attributes {
83    ( $($method:ident),* $(,)? ) => {
84        $(
85            fn $method<V>(self, visitor: V) -> Result<V::Value, Self::Error>
86            where
87                V: Visitor<'de>,
88            {
89                if !self.is_reading_attributes {
90                    self.skip_attributes()?;
91                }
92                self.deserialize_any(visitor)
93            }
94        )*
95    };
96}
97
98impl<'de> de::Deserializer<'de> for &mut Deserializer<'de> {
99    type Error = YsonError;
100
101    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
102    where
103        V: Visitor<'de>,
104    {
105        let was_reading_attributes = self.is_reading_attributes;
106        self.is_reading_attributes = false;
107
108        if was_reading_attributes {
109            if self.lexer.peek_byte()? != b'<' {
110                return visitor.visit_map(EmptyMapAccess);
111            }
112            self.lexer.next_token()?;
113            return visitor.visit_map(CommaSeparated::new(self, b'>')?);
114        }
115
116        if self.lexer.peek_byte()? == b'<' {
117            return visitor.visit_map(FlatStructAccess::new(self)?);
118        }
119
120        match self.lexer.next_token()? {
121            Token::Entity => visitor.visit_unit(),
122            Token::Boolean(b) => visitor.visit_bool(b),
123            Token::Int64(i) => visitor.visit_i64(i),
124            Token::Uint64(u) => visitor.visit_u64(u),
125            Token::Double(d) => visitor.visit_f64(d),
126            Token::String(s) => match s {
127                Cow::Borrowed(b) => {
128                    if let Ok(utf8) = std::str::from_utf8(b) {
129                        visitor.visit_borrowed_str(utf8)
130                    } else {
131                        visitor.visit_borrowed_bytes(b)
132                    }
133                }
134                Cow::Owned(vec) => match String::from_utf8(vec) {
135                    Ok(utf8) => visitor.visit_string(utf8),
136                    Err(e) => visitor.visit_byte_buf(e.into_bytes()),
137                },
138            },
139            Token::BeginList => visitor.visit_seq(CommaSeparated::new(self, b']')?),
140            Token::BeginMap => visitor.visit_map(CommaSeparated::new(self, b'}')?),
141            Token::BeginAttributes => visitor.visit_map(CommaSeparated::new(self, b'>')?),
142            t => Err(YsonError::Custom(format!("Unexpected token: {t:?}"))),
143        }
144    }
145
146    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
147    where
148        V: Visitor<'de>,
149    {
150        let was_reading_attributes = self.is_reading_attributes;
151        self.is_reading_attributes = false;
152
153        if was_reading_attributes {
154            if self.lexer.peek_byte()? == b'<' {
155                self.is_reading_attributes = true;
156                let res = visitor.visit_some(&mut *self);
157                self.is_reading_attributes = false;
158                res
159            } else {
160                visitor.visit_none()
161            }
162        } else {
163            self.skip_attributes()?;
164            if self.lexer.peek_byte()? == b'#' {
165                self.lexer.next_token()?;
166                visitor.visit_none()
167            } else {
168                visitor.visit_some(self)
169            }
170        }
171    }
172
173    fn deserialize_struct<V>(
174        self,
175        name: &'static str,
176        fields: &'static [&'static str],
177        visitor: V,
178    ) -> Result<V::Value, Self::Error>
179    where
180        V: Visitor<'de>,
181    {
182        if name == "$__yson_attributes" {
183            return visitor.visit_seq(AttributesWrapperAccess::new(self)?);
184        }
185        if fields.iter().any(|f| f.starts_with('@')) {
186            return visitor.visit_map(FlatStructAccess::new(self)?);
187        }
188
189        if !self.is_reading_attributes {
190            self.skip_attributes()?;
191        }
192        self.deserialize_any(visitor)
193    }
194
195    fn deserialize_enum<V>(
196        self,
197        _name: &'static str,
198        _variants: &'static [&'static str],
199        visitor: V,
200    ) -> Result<V::Value, Self::Error>
201    where
202        V: Visitor<'de>,
203    {
204        if !self.is_reading_attributes {
205            self.skip_attributes()?;
206        }
207
208        let peeked = self.lexer.peek_byte()?;
209        if peeked == b'{' {
210            self.lexer.next_token()?;
211            let val = visitor.visit_enum(EnumAccess::new(self, true))?;
212
213            loop {
214                match self.lexer.peek_byte() {
215                    Ok(b';' | b'}') => break,
216                    Ok(_) => {
217                        self.lexer.next_token()?;
218                    }
219                    Err(_) => break,
220                }
221            }
222
223            if let Ok(b';') = self.lexer.peek_byte() {
224                self.lexer.next_token()?;
225            }
226
227            match self.lexer.next_token()? {
228                Token::EndMap => Ok(val),
229                t => Err(YsonError::Custom(format!(
230                    "Expected '}}' after variant, got {t:?}"
231                ))),
232            }
233        } else {
234            visitor.visit_enum(EnumAccess::new(self, false))
235        }
236    }
237
238    delegate_skip_attributes! {
239        deserialize_bool, deserialize_i8, deserialize_i16, deserialize_i32,
240        deserialize_i64, deserialize_i128, deserialize_u8, deserialize_u16,
241        deserialize_u32, deserialize_u64, deserialize_u128, deserialize_f32,
242        deserialize_f64, deserialize_char, deserialize_str, deserialize_string,
243        deserialize_bytes, deserialize_byte_buf, deserialize_unit,
244        deserialize_seq, deserialize_map, deserialize_identifier,
245        deserialize_ignored_any
246    }
247
248    fn deserialize_unit_struct<V>(
249        self,
250        _name: &'static str,
251        visitor: V,
252    ) -> Result<V::Value, Self::Error>
253    where
254        V: Visitor<'de>,
255    {
256        if !self.is_reading_attributes {
257            self.skip_attributes()?;
258        }
259        self.deserialize_any(visitor)
260    }
261
262    fn deserialize_newtype_struct<V>(
263        self,
264        _name: &'static str,
265        visitor: V,
266    ) -> Result<V::Value, Self::Error>
267    where
268        V: Visitor<'de>,
269    {
270        if !self.is_reading_attributes {
271            self.skip_attributes()?;
272        }
273        self.deserialize_any(visitor)
274    }
275
276    fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error>
277    where
278        V: Visitor<'de>,
279    {
280        if !self.is_reading_attributes {
281            self.skip_attributes()?;
282        }
283        self.deserialize_any(visitor)
284    }
285
286    fn deserialize_tuple_struct<V>(
287        self,
288        _name: &'static str,
289        _len: usize,
290        visitor: V,
291    ) -> Result<V::Value, Self::Error>
292    where
293        V: Visitor<'de>,
294    {
295        if !self.is_reading_attributes {
296            self.skip_attributes()?;
297        }
298        self.deserialize_any(visitor)
299    }
300}
301
302/// A streaming deserializer that reads a sequence of YSON values from an input buffer.
303///
304/// In many YSON use cases, data is provided as a sequence of top-level values
305/// optionally separated by semicolons (e.g., `1; 2; 3;`). `StreamDeserializer`
306/// allows you to lazily iterate through these values without having to wrap
307/// them in a list `[...]`.
308///
309/// # Examples
310///
311/// ```
312/// use ytsaurus_yson::de::StreamDeserializer;
313///
314/// let input = b"1; 2; 3";
315/// let mut stream = StreamDeserializer::<i32>::new(input, false);
316///
317/// assert_eq!(stream.next_item().unwrap(), Some(1));
318/// assert_eq!(stream.next_item().unwrap(), Some(2));
319/// assert_eq!(stream.next_item().unwrap(), Some(3));
320/// assert_eq!(stream.next_item().unwrap(), None); // End of stream
321/// ```
322pub struct StreamDeserializer<'de, T> {
323    de: Deserializer<'de>,
324    first: bool,
325    _marker: std::marker::PhantomData<T>,
326}
327
328impl<'de, T> StreamDeserializer<'de, T>
329where
330    T: de::Deserialize<'de>,
331{
332    /// Creates a new `StreamDeserializer` from the given byte slice.
333    ///
334    /// # Arguments
335    ///
336    /// * `input` - The raw byte slice containing a sequence of YSON values.
337    /// * `is_binary` - `true` for binary format, `false` for text format.
338    #[must_use]
339    pub fn new(input: &'de [u8], is_binary: bool) -> Self {
340        Self {
341            de: Deserializer::from_bytes(input, is_binary),
342            first: true,
343            _marker: std::marker::PhantomData,
344        }
345    }
346
347    /// Deserializes the next item in the stream.
348    ///
349    /// # Returns
350    ///
351    /// - `Ok(Some(T))` if a value was successfully deserialized.
352    /// - `Ok(None)` if the end of the input was reached.
353    /// - `Err(YsonError)` if a parsing error occurred or if the data doesn't match type `T`.
354    ///
355    /// # Errors
356    ///
357    /// This method will return an error if:
358    /// - The YSON syntax is malformed.
359    /// - An item separator (semicolon) is missing where one is expected.
360    /// - The input ends prematurely after a separator.
361    pub fn next_item(&mut self) -> Result<Option<T>, YsonError> {
362        let peek_res = self.de.lexer.peek_byte();
363
364        if matches!(peek_res, Err(YsonError::Eof)) {
365            return Ok(None);
366        }
367
368        let next_byte = peek_res?;
369
370        if self.first {
371            self.first = false;
372        } else if next_byte == b';' {
373            self.de.lexer.next_token()?;
374            if matches!(self.de.lexer.peek_byte(), Err(YsonError::Eof)) {
375                return Ok(None);
376            }
377        }
378
379        let item = T::deserialize(&mut self.de)?;
380        Ok(Some(item))
381    }
382}
383
384/// A YSON map key or attribute name.
385///
386/// YSON keys are byte strings, not UTF-8, and [`YsonNode::Map`] stores them as
387/// `Vec<u8>` — so decoding a key through `String` would reject perfectly legal
388/// documents. This accepts both the UTF-8 and the raw-bytes visitor calls and
389/// keeps the bytes intact either way.
390struct MapKey(Vec<u8>);
391
392impl<'de> Deserialize<'de> for MapKey {
393    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
394    where
395        D: de::Deserializer<'de>,
396    {
397        struct MapKeyVisitor;
398
399        impl Visitor<'_> for MapKeyVisitor {
400            type Value = MapKey;
401
402            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
403                formatter.write_str("a YSON map key (byte string)")
404            }
405
406            fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
407                Ok(MapKey(v.as_bytes().to_vec()))
408            }
409
410            fn visit_string<E: de::Error>(self, v: String) -> Result<Self::Value, E> {
411                Ok(MapKey(v.into_bytes()))
412            }
413
414            fn visit_bytes<E: de::Error>(self, v: &[u8]) -> Result<Self::Value, E> {
415                Ok(MapKey(v.to_vec()))
416            }
417
418            fn visit_byte_buf<E: de::Error>(self, v: Vec<u8>) -> Result<Self::Value, E> {
419                Ok(MapKey(v))
420            }
421        }
422
423        deserializer.deserialize_any(MapKeyVisitor)
424    }
425}
426
427macro_rules! impl_visit_primitives {
428    ( $( $method:ident ( $v_type:ty ) => $node_variant:ident ),* ) => {
429        $(
430            fn $method<E>(self, v: $v_type) -> Result<Self::Value, E> {
431                Ok(YsonValue {
432                    attributes: None,
433                    node: YsonNode::$node_variant(v),
434                })
435            }
436        )*
437    };
438}
439
440impl<'de> Deserialize<'de> for YsonValue {
441    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
442    where
443        D: de::Deserializer<'de>,
444    {
445        struct YsonValueVisitor;
446
447        impl<'de> Visitor<'de> for YsonValueVisitor {
448            type Value = YsonValue;
449
450            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
451                formatter.write_str("any YSON value")
452            }
453
454            impl_visit_primitives! {
455                visit_bool(bool) => Boolean,
456                visit_i64(i64) => Int64,
457                visit_u64(u64) => Uint64,
458                visit_f64(f64) => Double
459            }
460
461            fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
462                Ok(YsonValue {
463                    attributes: None,
464                    node: YsonNode::String(v.as_bytes().to_vec()),
465                })
466            }
467
468            fn visit_bytes<E: de::Error>(self, v: &[u8]) -> Result<Self::Value, E> {
469                Ok(YsonValue {
470                    attributes: None,
471                    node: YsonNode::String(v.to_vec()),
472                })
473            }
474
475            fn visit_byte_buf<E: de::Error>(self, v: Vec<u8>) -> Result<Self::Value, E> {
476                Ok(YsonValue {
477                    attributes: None,
478                    node: YsonNode::String(v),
479                })
480            }
481
482            fn visit_unit<E>(self) -> Result<Self::Value, E> {
483                Ok(YsonValue {
484                    attributes: None,
485                    node: YsonNode::Entity,
486                })
487            }
488
489            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
490            where
491                A: SeqAccess<'de>,
492            {
493                let mut vec = Vec::new();
494                while let Some(elem) = seq.next_element()? {
495                    vec.push(elem);
496                }
497                Ok(YsonValue {
498                    attributes: None,
499                    node: YsonNode::List(vec),
500                })
501            }
502
503            fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
504            where
505                M: MapAccess<'de>,
506            {
507                let mut attributes = BTreeMap::new();
508                let mut plain_map = BTreeMap::new();
509                let mut body_node = None;
510                let mut is_attributed = false;
511
512                while let Some(MapKey(key)) = map.next_key::<MapKey>()? {
513                    if let Some(attr_name) = key.strip_prefix(b"@") {
514                        is_attributed = true;
515                        attributes.insert(attr_name.to_vec(), map.next_value()?);
516                    } else if key == b"$value" {
517                        is_attributed = true;
518                        let val: YsonValue = map.next_value()?;
519                        body_node = Some(val.node);
520                        if let Some(inner_attrs) = val.attributes {
521                            attributes.extend(inner_attrs);
522                        }
523                    } else {
524                        plain_map.insert(key, map.next_value()?);
525                    }
526                }
527
528                if is_attributed {
529                    Ok(YsonValue {
530                        attributes: if attributes.is_empty() {
531                            None
532                        } else {
533                            Some(attributes)
534                        },
535                        node: body_node.unwrap_or(YsonNode::Entity),
536                    })
537                } else {
538                    Ok(YsonValue {
539                        attributes: None,
540                        node: YsonNode::Map(plain_map),
541                    })
542                }
543            }
544        }
545
546        deserializer.deserialize_any(YsonValueVisitor)
547    }
548}