1 use crate::libyaml;
2 use crate::libyaml::util::Owned;
3 use std::ffi::c_void;
4 use std::io;
5 use std::mem::{self, MaybeUninit};
6 use std::ptr::{self, addr_of_mut};
7 use std::slice;
8 use unsafe_libyaml as sys;
9 
10 #[derive(Debug)]
11 pub(crate) enum Error {
12     Libyaml(libyaml::error::Error),
13     Io(io::Error),
14 }
15 
16 pub(crate) struct Emitter<'a> {
17     pin: Owned<EmitterPinned<'a>>,
18 }
19 
20 struct EmitterPinned<'a> {
21     sys: sys::yaml_emitter_t,
22     write: Box<dyn io::Write + 'a>,
23     write_error: Option<io::Error>,
24 }
25 
26 #[derive(Debug)]
27 pub(crate) enum Event<'a> {
28     StreamStart,
29     StreamEnd,
30     DocumentStart,
31     DocumentEnd,
32     Scalar(Scalar<'a>),
33     SequenceStart(Sequence),
34     SequenceEnd,
35     MappingStart(Mapping),
36     MappingEnd,
37 }
38 
39 #[derive(Debug)]
40 pub(crate) struct Scalar<'a> {
41     pub tag: Option<String>,
42     pub value: &'a str,
43     pub style: ScalarStyle,
44 }
45 
46 #[derive(Debug)]
47 pub(crate) enum ScalarStyle {
48     Any,
49     Plain,
50     SingleQuoted,
51     Literal,
52 }
53 
54 #[derive(Debug)]
55 pub(crate) struct Sequence {
56     pub tag: Option<String>,
57 }
58 
59 #[derive(Debug)]
60 pub(crate) struct Mapping {
61     pub tag: Option<String>,
62 }
63 
64 impl<'a> Emitter<'a> {
new(write: Box<dyn io::Write + 'a>) -> Emitter<'a>65     pub fn new(write: Box<dyn io::Write + 'a>) -> Emitter<'a> {
66         let owned = Owned::<EmitterPinned>::new_uninit();
67         let pin = unsafe {
68             let emitter = addr_of_mut!((*owned.ptr).sys);
69             if sys::yaml_emitter_initialize(emitter).fail {
70                 panic!("malloc error: {}", libyaml::Error::emit_error(emitter));
71             }
72             sys::yaml_emitter_set_unicode(emitter, true);
73             sys::yaml_emitter_set_width(emitter, -1);
74             addr_of_mut!((*owned.ptr).write).write(write);
75             addr_of_mut!((*owned.ptr).write_error).write(None);
76             sys::yaml_emitter_set_output(emitter, write_handler, owned.ptr.cast());
77             Owned::assume_init(owned)
78         };
79         Emitter { pin }
80     }
81 
emit(&mut self, event: Event) -> Result<(), Error>82     pub fn emit(&mut self, event: Event) -> Result<(), Error> {
83         let mut sys_event = MaybeUninit::<sys::yaml_event_t>::uninit();
84         let sys_event = sys_event.as_mut_ptr();
85         unsafe {
86             let emitter = addr_of_mut!((*self.pin.ptr).sys);
87             let initialize_status = match event {
88                 Event::StreamStart => {
89                     sys::yaml_stream_start_event_initialize(sys_event, sys::YAML_UTF8_ENCODING)
90                 }
91                 Event::StreamEnd => sys::yaml_stream_end_event_initialize(sys_event),
92                 Event::DocumentStart => {
93                     let version_directive = ptr::null_mut();
94                     let tag_directives_start = ptr::null_mut();
95                     let tag_directives_end = ptr::null_mut();
96                     let implicit = true;
97                     sys::yaml_document_start_event_initialize(
98                         sys_event,
99                         version_directive,
100                         tag_directives_start,
101                         tag_directives_end,
102                         implicit,
103                     )
104                 }
105                 Event::DocumentEnd => {
106                     let implicit = true;
107                     sys::yaml_document_end_event_initialize(sys_event, implicit)
108                 }
109                 Event::Scalar(mut scalar) => {
110                     let anchor = ptr::null();
111                     let tag = scalar.tag.as_mut().map_or_else(ptr::null, |tag| {
112                         tag.push('\0');
113                         tag.as_ptr()
114                     });
115                     let value = scalar.value.as_ptr();
116                     let length = scalar.value.len() as i32;
117                     let plain_implicit = tag.is_null();
118                     let quoted_implicit = tag.is_null();
119                     let style = match scalar.style {
120                         ScalarStyle::Any => sys::YAML_ANY_SCALAR_STYLE,
121                         ScalarStyle::Plain => sys::YAML_PLAIN_SCALAR_STYLE,
122                         ScalarStyle::SingleQuoted => sys::YAML_SINGLE_QUOTED_SCALAR_STYLE,
123                         ScalarStyle::Literal => sys::YAML_LITERAL_SCALAR_STYLE,
124                     };
125                     sys::yaml_scalar_event_initialize(
126                         sys_event,
127                         anchor,
128                         tag,
129                         value,
130                         length,
131                         plain_implicit,
132                         quoted_implicit,
133                         style,
134                     )
135                 }
136                 Event::SequenceStart(mut sequence) => {
137                     let anchor = ptr::null();
138                     let tag = sequence.tag.as_mut().map_or_else(ptr::null, |tag| {
139                         tag.push('\0');
140                         tag.as_ptr()
141                     });
142                     let implicit = tag.is_null();
143                     let style = sys::YAML_ANY_SEQUENCE_STYLE;
144                     sys::yaml_sequence_start_event_initialize(
145                         sys_event, anchor, tag, implicit, style,
146                     )
147                 }
148                 Event::SequenceEnd => sys::yaml_sequence_end_event_initialize(sys_event),
149                 Event::MappingStart(mut mapping) => {
150                     let anchor = ptr::null();
151                     let tag = mapping.tag.as_mut().map_or_else(ptr::null, |tag| {
152                         tag.push('\0');
153                         tag.as_ptr()
154                     });
155                     let implicit = tag.is_null();
156                     let style = sys::YAML_ANY_MAPPING_STYLE;
157                     sys::yaml_mapping_start_event_initialize(
158                         sys_event, anchor, tag, implicit, style,
159                     )
160                 }
161                 Event::MappingEnd => sys::yaml_mapping_end_event_initialize(sys_event),
162             };
163             if initialize_status.fail {
164                 return Err(Error::Libyaml(libyaml::Error::emit_error(emitter)));
165             }
166             if sys::yaml_emitter_emit(emitter, sys_event).fail {
167                 return Err(self.error());
168             }
169         }
170         Ok(())
171     }
172 
flush(&mut self) -> Result<(), Error>173     pub fn flush(&mut self) -> Result<(), Error> {
174         unsafe {
175             let emitter = addr_of_mut!((*self.pin.ptr).sys);
176             if sys::yaml_emitter_flush(emitter).fail {
177                 return Err(self.error());
178             }
179         }
180         Ok(())
181     }
182 
into_inner(self) -> Box<dyn io::Write + 'a>183     pub fn into_inner(self) -> Box<dyn io::Write + 'a> {
184         let sink = Box::new(io::sink());
185         unsafe { mem::replace(&mut (*self.pin.ptr).write, sink) }
186     }
187 
error(&mut self) -> Error188     fn error(&mut self) -> Error {
189         let emitter = unsafe { &mut *self.pin.ptr };
190         if let Some(write_error) = emitter.write_error.take() {
191             Error::Io(write_error)
192         } else {
193             Error::Libyaml(unsafe { libyaml::Error::emit_error(&emitter.sys) })
194         }
195     }
196 }
197 
write_handler(data: *mut c_void, buffer: *mut u8, size: u64) -> i32198 unsafe fn write_handler(data: *mut c_void, buffer: *mut u8, size: u64) -> i32 {
199     let data = data.cast::<EmitterPinned>();
200     match io::Write::write_all(unsafe { &mut *(*data).write }, unsafe {
201         slice::from_raw_parts(buffer, size as usize)
202     }) {
203         Ok(()) => 1,
204         Err(err) => {
205             unsafe {
206                 (*data).write_error = Some(err);
207             }
208             0
209         }
210     }
211 }
212 
213 impl<'a> Drop for EmitterPinned<'a> {
drop(&mut self)214     fn drop(&mut self) {
215         unsafe { sys::yaml_emitter_delete(&mut self.sys) }
216     }
217 }
218