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}