serde_yaml/libyaml/
emitter.rs

1use crate::libyaml;
2use crate::libyaml::util::Owned;
3use std::ffi::c_void;
4use std::io;
5use std::mem::{self, MaybeUninit};
6use std::ptr::{self, addr_of_mut};
7use std::slice;
8use unsafe_libyaml as sys;
9
10#[derive(Debug)]
11pub(crate) enum Error {
12    Libyaml(libyaml::error::Error),
13    Io(io::Error),
14}
15
16pub(crate) struct Emitter<'a> {
17    pin: Owned<EmitterPinned<'a>>,
18}
19
20struct 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)]
27pub(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)]
40pub(crate) struct Scalar<'a> {
41    pub tag: Option<String>,
42    pub value: &'a str,
43    pub style: ScalarStyle,
44}
45
46#[derive(Debug)]
47pub(crate) enum ScalarStyle {
48    Any,
49    Plain,
50    SingleQuoted,
51    Literal,
52}
53
54#[derive(Debug)]
55pub(crate) struct Sequence {
56    pub tag: Option<String>,
57}
58
59#[derive(Debug)]
60pub(crate) struct Mapping {
61    pub tag: Option<String>,
62}
63
64impl<'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
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
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
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
188    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
198unsafe 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
213impl<'a> Drop for EmitterPinned<'a> {
214    fn drop(&mut self) {
215        unsafe { sys::yaml_emitter_delete(&mut self.sys) }
216    }
217}