serde_yaml/libyaml/
parser.rs

1use crate::libyaml::cstr::{self, CStr};
2use crate::libyaml::error::{Error, Mark, Result};
3use crate::libyaml::tag::Tag;
4use crate::libyaml::util::Owned;
5use std::borrow::Cow;
6use std::fmt::{self, Debug};
7use std::mem::MaybeUninit;
8use std::ptr::{addr_of_mut, NonNull};
9use std::slice;
10use unsafe_libyaml as sys;
11
12pub(crate) struct Parser<'input> {
13    pin: Owned<ParserPinned<'input>>,
14}
15
16struct ParserPinned<'input> {
17    sys: sys::yaml_parser_t,
18    input: Cow<'input, [u8]>,
19}
20
21#[derive(Debug)]
22pub(crate) enum Event<'input> {
23    StreamStart,
24    StreamEnd,
25    DocumentStart,
26    DocumentEnd,
27    Alias(Anchor),
28    Scalar(Scalar<'input>),
29    SequenceStart(SequenceStart),
30    SequenceEnd,
31    MappingStart(MappingStart),
32    MappingEnd,
33}
34
35pub(crate) struct Scalar<'input> {
36    pub anchor: Option<Anchor>,
37    pub tag: Option<Tag>,
38    pub value: Box<[u8]>,
39    pub style: ScalarStyle,
40    pub repr: Option<&'input [u8]>,
41}
42
43#[derive(Debug)]
44pub(crate) struct SequenceStart {
45    pub anchor: Option<Anchor>,
46    pub tag: Option<Tag>,
47}
48
49#[derive(Debug)]
50pub(crate) struct MappingStart {
51    pub anchor: Option<Anchor>,
52    pub tag: Option<Tag>,
53}
54
55#[derive(Ord, PartialOrd, Eq, PartialEq)]
56pub(crate) struct Anchor(Box<[u8]>);
57
58#[derive(Copy, Clone, PartialEq, Eq, Debug)]
59pub(crate) enum ScalarStyle {
60    Plain,
61    SingleQuoted,
62    DoubleQuoted,
63    Literal,
64    Folded,
65}
66
67impl<'input> Parser<'input> {
68    pub fn new(input: Cow<'input, [u8]>) -> Parser<'input> {
69        let owned = Owned::<ParserPinned>::new_uninit();
70        let pin = unsafe {
71            let parser = addr_of_mut!((*owned.ptr).sys);
72            if sys::yaml_parser_initialize(parser).fail {
73                panic!("malloc error: {}", Error::parse_error(parser));
74            }
75            sys::yaml_parser_set_encoding(parser, sys::YAML_UTF8_ENCODING);
76            sys::yaml_parser_set_input_string(parser, input.as_ptr(), input.len() as u64);
77            addr_of_mut!((*owned.ptr).input).write(input);
78            Owned::assume_init(owned)
79        };
80        Parser { pin }
81    }
82
83    pub fn next(&mut self) -> Result<(Event<'input>, Mark)> {
84        let mut event = MaybeUninit::<sys::yaml_event_t>::uninit();
85        unsafe {
86            let parser = addr_of_mut!((*self.pin.ptr).sys);
87            if (*parser).error != sys::YAML_NO_ERROR {
88                return Err(Error::parse_error(parser));
89            }
90            let event = event.as_mut_ptr();
91            if sys::yaml_parser_parse(parser, event).fail {
92                return Err(Error::parse_error(parser));
93            }
94            let ret = convert_event(&*event, &(*self.pin.ptr).input);
95            let mark = Mark {
96                sys: (*event).start_mark,
97            };
98            sys::yaml_event_delete(event);
99            Ok((ret, mark))
100        }
101    }
102}
103
104unsafe fn convert_event<'input>(
105    sys: &sys::yaml_event_t,
106    input: &Cow<'input, [u8]>,
107) -> Event<'input> {
108    match sys.type_ {
109        sys::YAML_STREAM_START_EVENT => Event::StreamStart,
110        sys::YAML_STREAM_END_EVENT => Event::StreamEnd,
111        sys::YAML_DOCUMENT_START_EVENT => Event::DocumentStart,
112        sys::YAML_DOCUMENT_END_EVENT => Event::DocumentEnd,
113        sys::YAML_ALIAS_EVENT => {
114            Event::Alias(unsafe { optional_anchor(sys.data.alias.anchor) }.unwrap())
115        }
116        sys::YAML_SCALAR_EVENT => Event::Scalar(Scalar {
117            anchor: unsafe { optional_anchor(sys.data.scalar.anchor) },
118            tag: unsafe { optional_tag(sys.data.scalar.tag) },
119            value: Box::from(unsafe {
120                slice::from_raw_parts(sys.data.scalar.value, sys.data.scalar.length as usize)
121            }),
122            style: match unsafe { sys.data.scalar.style } {
123                sys::YAML_PLAIN_SCALAR_STYLE => ScalarStyle::Plain,
124                sys::YAML_SINGLE_QUOTED_SCALAR_STYLE => ScalarStyle::SingleQuoted,
125                sys::YAML_DOUBLE_QUOTED_SCALAR_STYLE => ScalarStyle::DoubleQuoted,
126                sys::YAML_LITERAL_SCALAR_STYLE => ScalarStyle::Literal,
127                sys::YAML_FOLDED_SCALAR_STYLE => ScalarStyle::Folded,
128                sys::YAML_ANY_SCALAR_STYLE | _ => unreachable!(),
129            },
130            repr: if let Cow::Borrowed(input) = input {
131                Some(&input[sys.start_mark.index as usize..sys.end_mark.index as usize])
132            } else {
133                None
134            },
135        }),
136        sys::YAML_SEQUENCE_START_EVENT => Event::SequenceStart(SequenceStart {
137            anchor: unsafe { optional_anchor(sys.data.sequence_start.anchor) },
138            tag: unsafe { optional_tag(sys.data.sequence_start.tag) },
139        }),
140        sys::YAML_SEQUENCE_END_EVENT => Event::SequenceEnd,
141        sys::YAML_MAPPING_START_EVENT => Event::MappingStart(MappingStart {
142            anchor: unsafe { optional_anchor(sys.data.mapping_start.anchor) },
143            tag: unsafe { optional_tag(sys.data.mapping_start.tag) },
144        }),
145        sys::YAML_MAPPING_END_EVENT => Event::MappingEnd,
146        sys::YAML_NO_EVENT => unreachable!(),
147        _ => unimplemented!(),
148    }
149}
150
151unsafe fn optional_anchor(anchor: *const u8) -> Option<Anchor> {
152    let ptr = NonNull::new(anchor as *mut i8)?;
153    let cstr = unsafe { CStr::from_ptr(ptr) };
154    Some(Anchor(Box::from(cstr.to_bytes())))
155}
156
157unsafe fn optional_tag(tag: *const u8) -> Option<Tag> {
158    let ptr = NonNull::new(tag as *mut i8)?;
159    let cstr = unsafe { CStr::from_ptr(ptr) };
160    Some(Tag(Box::from(cstr.to_bytes())))
161}
162
163impl<'input> Debug for Scalar<'input> {
164    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
165        let Scalar {
166            anchor,
167            tag,
168            value,
169            style,
170            repr: _,
171        } = self;
172
173        struct LossySlice<'a>(&'a [u8]);
174
175        impl<'a> Debug for LossySlice<'a> {
176            fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
177                cstr::debug_lossy(self.0, formatter)
178            }
179        }
180
181        formatter
182            .debug_struct("Scalar")
183            .field("anchor", anchor)
184            .field("tag", tag)
185            .field("value", &LossySlice(value))
186            .field("style", style)
187            .finish()
188    }
189}
190
191impl Debug for Anchor {
192    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
193        cstr::debug_lossy(&self.0, formatter)
194    }
195}
196
197impl<'input> Drop for ParserPinned<'input> {
198    fn drop(&mut self) {
199        unsafe { sys::yaml_parser_delete(&mut self.sys) }
200    }
201}