Skip to main content

facet_xdr/
parser.rs

1//! XDR parser implementing FormatParser.
2//!
3//! XDR (External Data Representation) is defined in RFC 4506.
4//! Key characteristics:
5//! - Big-endian byte order
6//! - All values are padded to 4-byte boundaries
7//! - Fixed-size integers (4 bytes for i32/u32, 8 bytes for i64/u64)
8//! - No support for i128/u128
9//! - Strings and variable-length data are length-prefixed with 4-byte padding
10//!
11//! XDR is NOT a self-describing format - fields are positional.
12//! This parser uses the `hint_*` methods from `FormatParser` to know what types to expect.
13
14extern crate alloc;
15
16use alloc::{borrow::Cow, string::String, vec::Vec};
17
18use crate::error::codes;
19use facet_format::{
20    ContainerKind, DeserializeErrorKind, EnumVariantHint, FormatParser, ParseError, ParseEvent,
21    ParseEventKind, SavePoint, ScalarTypeHint, ScalarValue,
22};
23use facet_reflect::Span;
24
25/// Create a ParseError from an error code and position.
26fn error_from_code(code: i32, pos: usize) -> ParseError {
27    let message = match code {
28        codes::UNEXPECTED_EOF => "unexpected end of input",
29        codes::INVALID_BOOL => "invalid boolean value (must be 0 or 1)",
30        codes::INVALID_OPTIONAL => "invalid optional discriminant (must be 0 or 1)",
31        codes::INVALID_VARIANT => "invalid enum discriminant",
32        codes::INVALID_UTF8 => "invalid UTF-8 in string",
33        codes::UNSUPPORTED_TYPE => "unsupported type for XDR",
34        codes::ALIGNMENT_ERROR => "position not aligned to 4 bytes",
35        _ => "unknown error",
36    };
37    ParseError::new(
38        Span::new(pos, 1),
39        DeserializeErrorKind::InvalidValue {
40            message: message.into(),
41        },
42    )
43}
44
45/// Stored variant metadata for enum parsing.
46#[derive(Debug, Clone)]
47struct VariantMeta {
48    name: String,
49    kind: facet_core::StructKind,
50    field_count: usize,
51}
52
53/// Parser state for tracking nested structures.
54#[derive(Debug, Clone)]
55enum ParserState {
56    /// At the top level or after completing a value.
57    Ready,
58    /// Inside a struct, tracking remaining fields.
59    InStruct { remaining_fields: usize },
60    /// Inside a sequence (variable-length array), tracking remaining elements.
61    InSequence { remaining_elements: u32 },
62    /// Inside a fixed-size array, tracking remaining elements.
63    InArray { remaining_elements: usize },
64    /// Inside an enum variant, tracking parsing progress.
65    InEnum {
66        variant_name: String,
67        variant_kind: facet_core::StructKind,
68        variant_field_count: usize,
69        field_key_emitted: bool,
70        wrapper_start_emitted: bool,
71        wrapper_end_emitted: bool,
72    },
73}
74
75/// XDR parser for deserialization.
76///
77/// XDR is a positional binary format - fields don't have names in the wire format.
78/// This parser relies on `hint_*` methods to know what types to expect.
79pub struct XdrParser<'de> {
80    input: &'de [u8],
81    pos: usize,
82    /// Stack of parser states for nested structures.
83    state_stack: Vec<ParserState>,
84    /// Peeked event (for `peek_event`).
85    peeked: Option<ParseEvent<'de>>,
86    /// Pending struct field count from `hint_struct_fields`.
87    pending_struct_fields: Option<usize>,
88    /// Pending scalar type hint from `hint_scalar_type`.
89    pending_scalar_type: Option<ScalarTypeHint>,
90    /// Pending sequence flag from `hint_sequence`.
91    pending_sequence: bool,
92    /// Pending fixed-size array length from `hint_array`.
93    pending_array: Option<usize>,
94    /// Pending option flag from `hint_option`.
95    pending_option: bool,
96    /// Pending enum variant metadata from `hint_enum`.
97    pending_enum: Option<Vec<VariantMeta>>,
98}
99
100impl<'de> XdrParser<'de> {
101    /// Create a new XDR parser from input bytes.
102    pub const fn new(input: &'de [u8]) -> Self {
103        Self {
104            input,
105            pos: 0,
106            state_stack: Vec::new(),
107            peeked: None,
108            pending_struct_fields: None,
109            pending_scalar_type: None,
110            pending_sequence: false,
111            pending_array: None,
112            pending_option: false,
113            pending_enum: None,
114        }
115    }
116
117    /// Read a u32 in big-endian (XDR standard).
118    fn read_u32(&mut self) -> Result<u32, ParseError> {
119        if self.pos + 4 > self.input.len() {
120            return Err(error_from_code(codes::UNEXPECTED_EOF, self.pos));
121        }
122        let bytes = &self.input[self.pos..self.pos + 4];
123        self.pos += 4;
124        Ok(u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
125    }
126
127    /// Read a u64 in big-endian.
128    fn read_u64(&mut self) -> Result<u64, ParseError> {
129        if self.pos + 8 > self.input.len() {
130            return Err(error_from_code(codes::UNEXPECTED_EOF, self.pos));
131        }
132        let bytes = &self.input[self.pos..self.pos + 8];
133        self.pos += 8;
134        Ok(u64::from_be_bytes([
135            bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
136        ]))
137    }
138
139    /// Read an i32 in big-endian.
140    fn read_i32(&mut self) -> Result<i32, ParseError> {
141        Ok(self.read_u32()? as i32)
142    }
143
144    /// Read an i64 in big-endian.
145    fn read_i64(&mut self) -> Result<i64, ParseError> {
146        Ok(self.read_u64()? as i64)
147    }
148
149    /// Read an f32 in big-endian.
150    fn read_f32(&mut self) -> Result<f32, ParseError> {
151        let bits = self.read_u32()?;
152        Ok(f32::from_bits(bits))
153    }
154
155    /// Read an f64 in big-endian.
156    fn read_f64(&mut self) -> Result<f64, ParseError> {
157        let bits = self.read_u64()?;
158        Ok(f64::from_bits(bits))
159    }
160
161    /// Read variable-length opaque data (with length prefix and padding).
162    fn read_opaque_var(&mut self) -> Result<&'de [u8], ParseError> {
163        let len = self.read_u32()? as usize;
164        if self.pos + len > self.input.len() {
165            return Err(error_from_code(codes::UNEXPECTED_EOF, self.pos));
166        }
167        let data = &self.input[self.pos..self.pos + len];
168        self.pos += len;
169        // Skip padding to align to 4 bytes
170        let pad = (4 - (len % 4)) % 4;
171        if self.pos + pad > self.input.len() {
172            return Err(error_from_code(codes::UNEXPECTED_EOF, self.pos));
173        }
174        self.pos += pad;
175        Ok(data)
176    }
177
178    /// Read a string (variable-length opaque interpreted as UTF-8).
179    fn read_string(&mut self) -> Result<Cow<'de, str>, ParseError> {
180        let start_pos = self.pos;
181        let bytes = self.read_opaque_var()?;
182        core::str::from_utf8(bytes).map(Cow::Borrowed).map_err(|_| {
183            let mut context = [0u8; 16];
184            let context_len = bytes.len().min(16);
185            context[..context_len].copy_from_slice(&bytes[..context_len]);
186            ParseError::new(
187                Span::new(start_pos, bytes.len()),
188                DeserializeErrorKind::InvalidUtf8 {
189                    context,
190                    context_len: context_len as u8,
191                },
192            )
193        })
194    }
195
196    /// Read a boolean (XDR bool is 4 bytes: 0=false, 1=true).
197    fn read_bool(&mut self) -> Result<bool, ParseError> {
198        let val = self.read_u32()?;
199        match val {
200            0 => Ok(false),
201            1 => Ok(true),
202            _ => Err(error_from_code(codes::INVALID_BOOL, self.pos - 4)),
203        }
204    }
205
206    /// Get the current parser state (top of stack or Ready).
207    fn current_state(&self) -> &ParserState {
208        self.state_stack.last().unwrap_or(&ParserState::Ready)
209    }
210
211    /// Generate the next event based on current state and hints.
212    fn generate_next_event(&mut self) -> Result<ParseEvent<'de>, ParseError> {
213        // Check if we have a pending option hint
214        if self.pending_option {
215            self.pending_option = false;
216            let discriminant = self.read_u32()?;
217            match discriminant {
218                0 => {
219                    return Ok(self.event(ParseEventKind::Scalar(ScalarValue::Null)));
220                }
221                1 => {
222                    // Some(value) - return placeholder, deserializer will call hint for inner
223                    return Ok(self.event(ParseEventKind::OrderedField));
224                }
225                _ => {
226                    return Err(error_from_code(codes::INVALID_OPTIONAL, self.pos - 4));
227                }
228            }
229        }
230
231        // Check if we have a pending enum hint
232        if let Some(variants) = self.pending_enum.take() {
233            let discriminant = self.read_u32()? as usize;
234
235            if discriminant >= variants.len() {
236                return Err(error_from_code(codes::INVALID_VARIANT, self.pos - 4));
237            }
238            let variant = &variants[discriminant];
239
240            self.state_stack.push(ParserState::InEnum {
241                variant_name: variant.name.clone(),
242                variant_kind: variant.kind,
243                variant_field_count: variant.field_count,
244                field_key_emitted: false,
245                wrapper_start_emitted: false,
246                wrapper_end_emitted: false,
247            });
248            return Ok(self.event(ParseEventKind::StructStart(ContainerKind::Object)));
249        }
250
251        // Check if we have a pending scalar type hint
252        if let Some(hint) = self.pending_scalar_type.take() {
253            return self.parse_scalar_with_hint(hint);
254        }
255
256        // Check if we have a pending sequence hint (variable-length)
257        if self.pending_sequence {
258            self.pending_sequence = false;
259            let count = self.read_u32()?;
260            self.state_stack.push(ParserState::InSequence {
261                remaining_elements: count,
262            });
263            return Ok(self.event(ParseEventKind::SequenceStart(ContainerKind::Array)));
264        }
265
266        // Check if we have a pending fixed-size array hint
267        if let Some(len) = self.pending_array.take() {
268            self.state_stack.push(ParserState::InArray {
269                remaining_elements: len,
270            });
271            return Ok(self.event(ParseEventKind::SequenceStart(ContainerKind::Array)));
272        }
273
274        // Check if we have a pending struct hint
275        if let Some(num_fields) = self.pending_struct_fields.take() {
276            self.state_stack.push(ParserState::InStruct {
277                remaining_fields: num_fields,
278            });
279            return Ok(self.event(ParseEventKind::StructStart(ContainerKind::Object)));
280        }
281
282        // Check current state
283        match self.current_state().clone() {
284            ParserState::Ready => {
285                // At top level without a hint - error
286                Err(ParseError::new(
287                    Span::new(self.pos, 1),
288                    DeserializeErrorKind::InvalidValue {
289                        message: "XDR parser needs type hints (use hint_scalar_type, hint_struct_fields, or hint_sequence)".into(),
290                    },
291                ))
292            }
293            ParserState::InStruct { remaining_fields } => {
294                if remaining_fields == 0 {
295                    self.state_stack.pop();
296                    Ok(self.event(ParseEventKind::StructEnd))
297                } else {
298                    if let Some(ParserState::InStruct { remaining_fields }) =
299                        self.state_stack.last_mut()
300                    {
301                        *remaining_fields -= 1;
302                    }
303                    Ok(self.event(ParseEventKind::OrderedField))
304                }
305            }
306            ParserState::InSequence { remaining_elements } => {
307                if remaining_elements == 0 {
308                    self.state_stack.pop();
309                    Ok(self.event(ParseEventKind::SequenceEnd))
310                } else {
311                    if let Some(ParserState::InSequence { remaining_elements }) =
312                        self.state_stack.last_mut()
313                    {
314                        *remaining_elements -= 1;
315                    }
316                    Ok(self.event(ParseEventKind::OrderedField))
317                }
318            }
319            ParserState::InArray { remaining_elements } => {
320                if remaining_elements == 0 {
321                    self.state_stack.pop();
322                    Ok(self.event(ParseEventKind::SequenceEnd))
323                } else {
324                    if let Some(ParserState::InArray { remaining_elements }) =
325                        self.state_stack.last_mut()
326                    {
327                        *remaining_elements -= 1;
328                    }
329                    Ok(self.event(ParseEventKind::OrderedField))
330                }
331            }
332            ParserState::InEnum {
333                variant_name,
334                variant_kind,
335                variant_field_count,
336                field_key_emitted,
337                wrapper_start_emitted,
338                wrapper_end_emitted,
339            } => {
340                use facet_core::StructKind;
341
342                if !field_key_emitted {
343                    if let Some(ParserState::InEnum {
344                        field_key_emitted, ..
345                    }) = self.state_stack.last_mut()
346                    {
347                        *field_key_emitted = true;
348                    }
349                    Ok(
350                        self.event(ParseEventKind::FieldKey(facet_format::FieldKey::new(
351                            Cow::Owned(variant_name),
352                            facet_format::FieldLocationHint::KeyValue,
353                        ))),
354                    )
355                } else if !wrapper_start_emitted {
356                    match variant_kind {
357                        StructKind::Unit => {
358                            self.state_stack.pop();
359                            Ok(self.event(ParseEventKind::StructEnd))
360                        }
361                        StructKind::Tuple | StructKind::TupleStruct => {
362                            if variant_field_count == 1 {
363                                // Newtype variant
364                                if let Some(ParserState::InEnum {
365                                    wrapper_start_emitted,
366                                    wrapper_end_emitted,
367                                    ..
368                                }) = self.state_stack.last_mut()
369                                {
370                                    *wrapper_start_emitted = true;
371                                    *wrapper_end_emitted = true;
372                                }
373                                self.generate_next_event()
374                            } else {
375                                if let Some(ParserState::InEnum {
376                                    wrapper_start_emitted,
377                                    ..
378                                }) = self.state_stack.last_mut()
379                                {
380                                    *wrapper_start_emitted = true;
381                                }
382                                Ok(self.event(ParseEventKind::SequenceStart(ContainerKind::Array)))
383                            }
384                        }
385                        StructKind::Struct => {
386                            if let Some(ParserState::InEnum {
387                                wrapper_start_emitted,
388                                ..
389                            }) = self.state_stack.last_mut()
390                            {
391                                *wrapper_start_emitted = true;
392                            }
393                            self.state_stack.push(ParserState::InStruct {
394                                remaining_fields: variant_field_count,
395                            });
396                            Ok(self.event(ParseEventKind::StructStart(ContainerKind::Object)))
397                        }
398                    }
399                } else if !wrapper_end_emitted {
400                    match variant_kind {
401                        StructKind::Unit => unreachable!(),
402                        StructKind::Tuple | StructKind::TupleStruct => {
403                            if variant_field_count > 1 {
404                                if let Some(ParserState::InEnum {
405                                    wrapper_end_emitted,
406                                    ..
407                                }) = self.state_stack.last_mut()
408                                {
409                                    *wrapper_end_emitted = true;
410                                }
411                                Ok(self.event(ParseEventKind::SequenceEnd))
412                            } else {
413                                self.state_stack.pop();
414                                Ok(self.event(ParseEventKind::StructEnd))
415                            }
416                        }
417                        StructKind::Struct => {
418                            self.state_stack.pop();
419                            Ok(self.event(ParseEventKind::StructEnd))
420                        }
421                    }
422                } else {
423                    self.state_stack.pop();
424                    Ok(self.event(ParseEventKind::StructEnd))
425                }
426            }
427        }
428    }
429
430    /// Parse a scalar value with the given type hint.
431    fn parse_scalar_with_hint(
432        &mut self,
433        hint: ScalarTypeHint,
434    ) -> Result<ParseEvent<'de>, ParseError> {
435        let scalar = match hint {
436            ScalarTypeHint::Bool => {
437                let val = self.read_bool()?;
438                ScalarValue::Bool(val)
439            }
440            // XDR encodes smaller integers as 4 bytes
441            ScalarTypeHint::U8 => {
442                let val = self.read_u32()? as u8;
443                ScalarValue::U64(val as u64)
444            }
445            ScalarTypeHint::U16 => {
446                let val = self.read_u32()? as u16;
447                ScalarValue::U64(val as u64)
448            }
449            ScalarTypeHint::U32 => {
450                let val = self.read_u32()?;
451                ScalarValue::U64(val as u64)
452            }
453            ScalarTypeHint::U64 => {
454                let val = self.read_u64()?;
455                ScalarValue::U64(val)
456            }
457            ScalarTypeHint::U128 => {
458                // XDR doesn't support u128
459                return Err(error_from_code(codes::UNSUPPORTED_TYPE, self.pos));
460            }
461            ScalarTypeHint::Usize => {
462                // Encode usize as u64
463                let val = self.read_u64()?;
464                ScalarValue::U64(val)
465            }
466            ScalarTypeHint::I8 => {
467                let val = self.read_i32()? as i8;
468                ScalarValue::I64(val as i64)
469            }
470            ScalarTypeHint::I16 => {
471                let val = self.read_i32()? as i16;
472                ScalarValue::I64(val as i64)
473            }
474            ScalarTypeHint::I32 => {
475                let val = self.read_i32()?;
476                ScalarValue::I64(val as i64)
477            }
478            ScalarTypeHint::I64 => {
479                let val = self.read_i64()?;
480                ScalarValue::I64(val)
481            }
482            ScalarTypeHint::I128 => {
483                // XDR doesn't support i128
484                return Err(error_from_code(codes::UNSUPPORTED_TYPE, self.pos));
485            }
486            ScalarTypeHint::Isize => {
487                // Encode isize as i64
488                let val = self.read_i64()?;
489                ScalarValue::I64(val)
490            }
491            ScalarTypeHint::F32 => {
492                let val = self.read_f32()?;
493                ScalarValue::F64(val as f64)
494            }
495            ScalarTypeHint::F64 => {
496                let val = self.read_f64()?;
497                ScalarValue::F64(val)
498            }
499            ScalarTypeHint::String => {
500                let val = self.read_string()?;
501                ScalarValue::Str(val)
502            }
503            ScalarTypeHint::Bytes => {
504                let val = self.read_opaque_var()?;
505                ScalarValue::Bytes(Cow::Borrowed(val))
506            }
507            ScalarTypeHint::Char => {
508                // XDR encodes char as u32
509                let val = self.read_u32()?;
510                let c = char::from_u32(val).ok_or_else(|| {
511                    ParseError::new(
512                        Span::new(self.pos - 4, 4),
513                        DeserializeErrorKind::InvalidValue {
514                            message: "invalid char codepoint".into(),
515                        },
516                    )
517                })?;
518                ScalarValue::Str(Cow::Owned(c.to_string()))
519            }
520        };
521        Ok(self.event(ParseEventKind::Scalar(scalar)))
522    }
523}
524
525impl<'de> FormatParser<'de> for XdrParser<'de> {
526    fn next_event(&mut self) -> Result<Option<ParseEvent<'de>>, ParseError> {
527        if let Some(event) = self.peeked.take() {
528            return Ok(Some(event));
529        }
530        Ok(Some(self.generate_next_event()?))
531    }
532
533    fn peek_event(&mut self) -> Result<Option<ParseEvent<'de>>, ParseError> {
534        if self.peeked.is_none() {
535            self.peeked = Some(self.generate_next_event()?);
536        }
537        Ok(self.peeked.clone())
538    }
539
540    fn skip_value(&mut self) -> Result<(), ParseError> {
541        // XDR is not self-describing, so we can't skip arbitrary values
542        Err(ParseError::new(
543            Span::new(self.pos, 1),
544            DeserializeErrorKind::InvalidValue {
545                message: "skip_value not supported for XDR (non-self-describing format)".into(),
546            },
547        ))
548    }
549
550    fn current_span(&self) -> Option<Span> {
551        Some(Span::new(self.pos, 1))
552    }
553
554    fn save(&mut self) -> SavePoint {
555        // XDR is positional - save/restore not meaningful
556        unimplemented!("save/restore not supported for XDR (positional format)")
557    }
558
559    fn restore(&mut self, _save_point: SavePoint) {
560        unimplemented!("save/restore not supported for XDR (positional format)")
561    }
562
563    fn is_self_describing(&self) -> bool {
564        false
565    }
566
567    fn hint_struct_fields(&mut self, num_fields: usize) {
568        self.pending_struct_fields = Some(num_fields);
569        if self
570            .peeked
571            .as_ref()
572            .is_some_and(|e| matches!(e.kind, ParseEventKind::OrderedField))
573        {
574            self.peeked = None;
575        }
576    }
577
578    fn hint_scalar_type(&mut self, hint: ScalarTypeHint) {
579        self.pending_scalar_type = Some(hint);
580        if self
581            .peeked
582            .as_ref()
583            .is_some_and(|e| matches!(e.kind, ParseEventKind::OrderedField))
584        {
585            self.peeked = None;
586        }
587    }
588
589    fn hint_sequence(&mut self) {
590        self.pending_sequence = true;
591        if self
592            .peeked
593            .as_ref()
594            .is_some_and(|e| matches!(e.kind, ParseEventKind::OrderedField))
595        {
596            self.peeked = None;
597        }
598    }
599
600    fn hint_array(&mut self, len: usize) {
601        self.pending_array = Some(len);
602        if self
603            .peeked
604            .as_ref()
605            .is_some_and(|e| matches!(e.kind, ParseEventKind::OrderedField))
606        {
607            self.peeked = None;
608        }
609    }
610
611    fn hint_option(&mut self) {
612        self.pending_option = true;
613        if self
614            .peeked
615            .as_ref()
616            .is_some_and(|e| matches!(e.kind, ParseEventKind::OrderedField))
617        {
618            self.peeked = None;
619        }
620    }
621
622    fn hint_enum(&mut self, variants: &[EnumVariantHint]) {
623        let metas: Vec<VariantMeta> = variants
624            .iter()
625            .map(|v| VariantMeta {
626                name: v.name.to_string(),
627                kind: v.kind,
628                field_count: v.field_count,
629            })
630            .collect();
631        self.pending_enum = Some(metas);
632        if self
633            .peeked
634            .as_ref()
635            .is_some_and(|e| matches!(e.kind, ParseEventKind::OrderedField))
636        {
637            self.peeked = None;
638        }
639    }
640}
641
642impl<'de> XdrParser<'de> {
643    /// Create an event with the current span.
644    #[inline]
645    fn event(&self, kind: ParseEventKind<'de>) -> ParseEvent<'de> {
646        ParseEvent::new(kind, Span::new(self.pos, 1))
647    }
648}