1 use crate::libyaml::cstr::{self, CStr};
2 use crate::libyaml::error::{Error, Mark, Result};
3 use crate::libyaml::tag::Tag;
4 use crate::libyaml::util::Owned;
5 use std::borrow::Cow;
6 use std::fmt::{self, Debug};
7 use std::mem::MaybeUninit;
8 use std::ptr::{addr_of_mut, NonNull};
9 use std::slice;
10 use unsafe_libyaml as sys;
11 
12 pub(crate) struct Parser<'input> {
13     pin: Owned<ParserPinned<'input>>,
14 }
15 
16 struct ParserPinned<'input> {
17     sys: sys::yaml_parser_t,
18     input: Cow<'input, [u8]>,
19 }
20 
21 #[derive(Debug)]
22 pub(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 
35 pub(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)]
44 pub(crate) struct SequenceStart {
45     pub anchor: Option<Anchor>,
46     pub tag: Option<Tag>,
47 }
48 
49 #[derive(Debug)]
50 pub(crate) struct MappingStart {
51     pub anchor: Option<Anchor>,
52     pub tag: Option<Tag>,
53 }
54 
55 #[derive(Ord, PartialOrd, Eq, PartialEq)]
56 pub(crate) struct Anchor(Box<[u8]>);
57 
58 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
59 pub(crate) enum ScalarStyle {
60     Plain,
61     SingleQuoted,
62     DoubleQuoted,
63     Literal,
64     Folded,
65 }
66 
67 impl<'input> Parser<'input> {
new(input: Cow<'input, [u8]>) -> 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 
next(&mut self) -> Result<(Event<'input>, Mark)>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 
convert_event<'input>( sys: &sys::yaml_event_t, input: &Cow<'input, [u8]>, ) -> Event<'input>104 unsafe 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 
optional_anchor(anchor: *const u8) -> Option<Anchor>151 unsafe 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 
optional_tag(tag: *const u8) -> Option<Tag>157 unsafe 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 
163 impl<'input> Debug for Scalar<'input> {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result164     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 
191 impl Debug for Anchor {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result192     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
193         cstr::debug_lossy(&self.0, formatter)
194     }
195 }
196 
197 impl<'input> Drop for ParserPinned<'input> {
drop(&mut self)198     fn drop(&mut self) {
199         unsafe { sys::yaml_parser_delete(&mut self.sys) }
200     }
201 }
202