1use crate::ffi::write_out;
24use alloc::ffi::CString;
25use core::ffi::{CStr, c_char, c_int, c_void};
26
27use asdf_core::events::{Event as CoreEvent, EventOptions, events, render_event};
28use asdf_core::yaml::{YamlEvent, YamlEventKind};
29
30use asdf_core::ErrorCode;
31
32use crate::error_ffi::ErrorState;
33use crate::panic::guard;
34use crate::types::{
35 AsdfEventType, AsdfParserOptFlags, AsdfYamlEventType, asdf_block_header_t, asdf_block_info_t,
36 asdf_parser_cfg_t, asdf_tree_info_t, parser_opt,
37};
38
39#[derive(Debug)]
45enum Payload {
46 None,
48 Comment(CString),
50 Tree {
52 info: Box<asdf_tree_info_t>,
53 #[allow(dead_code)]
56 text: Option<CString>,
57 },
58 Yaml(YamlSub),
60 Block(Box<asdf_block_info_t>),
62}
63
64#[derive(Debug)]
66struct YamlSub {
67 kind: AsdfYamlEventType,
68 tag: Option<CString>,
69 value: Option<CString>,
70}
71
72#[repr(C)]
78#[derive(Debug)]
79pub struct AsdfEvent {
80 event_type: AsdfEventType,
81 payload: Payload,
82 source: CoreEvent,
86}
87
88#[derive(Debug)]
90pub struct AsdfParser {
91 flags: AsdfParserOptFlags,
92 error: ErrorState,
93 buffer: Vec<u8>,
95 filename: Option<CString>,
97 steps: alloc::collections::VecDeque<CoreEvent>,
99 live: Vec<*mut AsdfEvent>,
101 iterated: *mut AsdfEvent,
104 finished: bool,
106}
107
108impl AsdfParser {
109 fn new(flags: AsdfParserOptFlags) -> Self {
110 Self {
111 flags,
112 error: ErrorState::default(),
113 buffer: Vec::new(),
114 filename: None,
115 steps: alloc::collections::VecDeque::new(),
116 live: Vec::new(),
117 iterated: core::ptr::null_mut(),
118 finished: false,
119 }
120 }
121
122 fn emits_yaml(&self) -> bool {
123 self.flags & parser_opt::EMIT_YAML_EVENTS != 0
124 }
125
126 fn buffers_tree(&self) -> bool {
127 self.flags & parser_opt::BUFFER_TREE != 0
128 }
129
130 fn ingest(&mut self, buffer: Vec<u8>) -> c_int {
135 self.buffer = buffer;
136 self.steps.clear();
137 self.finished = false;
138
139 let options = EventOptions { yaml: self.emits_yaml(), buffer_tree: self.buffers_tree() };
140 match events(&self.buffer, options) {
141 Ok(stream) => {
142 self.steps.extend(stream);
143 self.error.clear();
144 0
145 }
146 Err(e) => {
147 self.error.set_error(&e);
148 -1
149 }
150 }
151 }
152
153 fn next_event(&mut self) -> *mut AsdfEvent {
155 let Some(step) = self.steps.pop_front() else {
156 self.finished = true;
157 return core::ptr::null_mut();
158 };
159
160 let built = match step.clone() {
161 CoreEvent::AsdfVersion(_) => Some((AsdfEventType::AsdfVersion, Payload::None)),
162 CoreEvent::StandardVersion(_) => Some((AsdfEventType::StandardVersion, Payload::None)),
163 CoreEvent::Comment(text) => CString::new(text)
164 .ok()
165 .map(|owned| (AsdfEventType::Comment, Payload::Comment(owned))),
166 CoreEvent::BlockIndex(_) => Some((AsdfEventType::BlockIndex, Payload::None)),
167 CoreEvent::TreeStart { start } => {
168 let info = Box::new(asdf_tree_info_t { start, end: 0, buf: core::ptr::null() });
169 Some((AsdfEventType::TreeStart, Payload::Tree { info, text: None }))
170 }
171 CoreEvent::TreeEnd { start, end, text } => {
172 let text = text.and_then(|text| CString::new(text).ok());
175 let info = Box::new(asdf_tree_info_t { start, end, buf: core::ptr::null() });
179 Some((AsdfEventType::TreeEnd, Payload::Tree { info, text }))
180 }
181 CoreEvent::Yaml(event) => Some((AsdfEventType::Yaml, Payload::Yaml(yaml_sub(&event)))),
182 CoreEvent::Block(location) => {
183 let header = &location.header;
184 let info = Box::new(asdf_block_info_t {
185 index: location.index,
186 header_pos: i64::try_from(location.header_pos).unwrap_or(i64::MAX),
187 data_pos: i64::try_from(location.data_pos).unwrap_or(i64::MAX),
188 header: asdf_block_header_t {
189 header_size: header.header_size,
190 flags: header.flags,
191 compression: header.compression,
192 allocated_size: header.allocated_size,
193 used_size: header.used_size,
194 data_size: header.data_size,
195 checksum: header.checksum,
196 },
197 });
198 Some((AsdfEventType::Block, Payload::Block(info)))
199 }
200 CoreEvent::End => Some((AsdfEventType::End, Payload::None)),
201 }
202 .map(|(event_type, payload)| AsdfEvent { event_type, payload, source: step });
203
204 let Some(event) = built else {
205 return core::ptr::null_mut();
206 };
207 let mut boxed = Box::new(event);
208
209 if let Payload::Tree { info, text: Some(text) } = &mut boxed.payload {
217 let buf = text.as_ptr();
218 info.buf = buf;
219 }
220
221 let handle = Box::into_raw(boxed);
222 self.live.push(handle);
223 handle
224 }
225
226 fn release(&mut self, event: *mut AsdfEvent) {
228 let Some(position) = self.live.iter().position(|e| *e == event) else {
229 return;
230 };
231 self.live.remove(position);
232 if self.iterated == event {
233 self.iterated = core::ptr::null_mut();
234 }
235 drop(unsafe { Box::from_raw(event) });
236 }
237}
238
239impl Drop for AsdfParser {
240 fn drop(&mut self) {
241 for event in core::mem::take(&mut self.live) {
242 drop(unsafe { Box::from_raw(event) });
243 }
244 }
245}
246
247fn yaml_sub(event: &YamlEvent) -> YamlSub {
249 let kind = match event.kind {
250 YamlEventKind::StreamStart => AsdfYamlEventType::StreamStart,
251 YamlEventKind::StreamEnd => AsdfYamlEventType::StreamEnd,
252 YamlEventKind::DocumentStart => AsdfYamlEventType::DocumentStart,
253 YamlEventKind::DocumentEnd => AsdfYamlEventType::DocumentEnd,
254 YamlEventKind::MappingStart => AsdfYamlEventType::MappingStart,
255 YamlEventKind::MappingEnd => AsdfYamlEventType::MappingEnd,
256 YamlEventKind::SequenceStart => AsdfYamlEventType::SequenceStart,
257 YamlEventKind::SequenceEnd => AsdfYamlEventType::SequenceEnd,
258 YamlEventKind::Scalar => AsdfYamlEventType::Scalar,
259 YamlEventKind::Alias => AsdfYamlEventType::Alias,
260 };
261 YamlSub {
262 kind,
263 tag: event.tag.as_ref().and_then(|t| CString::new(t.as_str()).ok()),
264 value: event.value.as_ref().and_then(|v| CString::new(v.as_str()).ok()),
265 }
266}
267
268fn parser_ref<'a>(parser: *const AsdfParser) -> Option<&'a AsdfParser> {
269 unsafe { crate::ffi::as_ref(parser) }
270}
271
272fn parser_mut<'a>(parser: *mut AsdfParser) -> Option<&'a mut AsdfParser> {
273 unsafe { crate::ffi::as_mut(parser) }
274}
275
276fn event_ref<'a>(event: *const AsdfEvent) -> Option<&'a AsdfEvent> {
277 unsafe { crate::ffi::as_ref(event) }
278}
279
280#[unsafe(no_mangle)]
291pub unsafe extern "C" fn asdf_parser_create(config: *const asdf_parser_cfg_t) -> *mut AsdfParser {
292 guard("asdf_parser_create", core::ptr::null_mut(), || {
293 let flags = if config.is_null() { 0 } else { unsafe { &*config }.flags };
294 Box::into_raw(Box::new(AsdfParser::new(flags)))
295 })
296}
297
298#[unsafe(no_mangle)]
304pub unsafe extern "C" fn asdf_parser_destroy(parser: *mut AsdfParser) {
305 guard("asdf_parser_destroy", (), || {
306 if parser.is_null() {
307 return;
308 }
309 drop(unsafe { Box::from_raw(parser) });
310 })
311}
312
313#[unsafe(no_mangle)]
318pub unsafe extern "C" fn asdf_parser_set_input_file(
319 parser: *mut AsdfParser,
320 filename: *const c_char,
321) -> c_int {
322 guard("asdf_parser_set_input_file", -1, || {
323 let Some(state) = parser_mut(parser) else {
324 return -1;
325 };
326 if filename.is_null() {
327 state.error.set(ErrorCode::InvalidArgument as i32, "no filename given");
328 return -1;
329 }
330 let name = unsafe { CStr::from_ptr(filename) };
331 let path = std::path::PathBuf::from(name.to_string_lossy().into_owned());
332 match std::fs::read(&path) {
333 Ok(bytes) => {
334 state.filename = Some(name.to_owned());
335 state.ingest(bytes)
336 }
337 Err(e) => {
338 state.error.set_system(e.raw_os_error().unwrap_or(0));
339 -1
340 }
341 }
342 })
343}
344
345#[unsafe(no_mangle)]
354pub unsafe extern "C" fn asdf_parser_set_input_fp(
355 parser: *mut AsdfParser,
356 fp: *mut c_void,
357 filename: *const c_char,
358) -> c_int {
359 guard("asdf_parser_set_input_fp", -1, || {
360 let Some(state) = parser_mut(parser) else {
361 return -1;
362 };
363 if fp.is_null() {
364 state.error.set(ErrorCode::InvalidArgument as i32, "no stream given");
365 return -1;
366 }
367 if !filename.is_null() {
368 state.filename = Some(unsafe { CStr::from_ptr(filename) }.to_owned());
369 }
370 match read_stream(fp) {
371 Some(bytes) => state.ingest(bytes),
372 None => {
373 state.error.set(ErrorCode::System as i32, "could not read the stream");
374 -1
375 }
376 }
377 })
378}
379
380#[unsafe(no_mangle)]
387pub unsafe extern "C" fn asdf_parser_set_input_mem(
388 parser: *mut AsdfParser,
389 buf: *const c_void,
390 size: usize,
391) -> c_int {
392 guard("asdf_parser_set_input_mem", -1, || {
393 let Some(state) = parser_mut(parser) else {
394 return -1;
395 };
396 if buf.is_null() {
397 state.error.set(ErrorCode::InvalidArgument as i32, "no buffer given");
398 return -1;
399 }
400 let bytes = unsafe { core::slice::from_raw_parts(buf.cast::<u8>(), size) }.to_vec();
401 state.ingest(bytes)
402 })
403}
404
405fn read_stream(fp: *mut c_void) -> Option<Vec<u8>> {
407 let mut out = Vec::new();
408 let mut chunk = [0u8; 64 * 1024];
409 loop {
410 let read =
411 unsafe { libc::fread(chunk.as_mut_ptr().cast::<c_void>(), 1, chunk.len(), fp.cast()) };
412 if read > 0 {
413 out.extend_from_slice(&chunk[..read]);
414 }
415 if read < chunk.len() {
416 if unsafe { libc::ferror(fp.cast()) } != 0 {
418 return None;
419 }
420 return Some(out);
421 }
422 }
423}
424
425#[unsafe(no_mangle)]
432pub unsafe extern "C" fn asdf_parser_parse(parser: *mut AsdfParser) -> *mut AsdfEvent {
433 guard("asdf_parser_parse", core::ptr::null_mut(), || match parser_mut(parser) {
434 Some(state) => state.next_event(),
435 None => core::ptr::null_mut(),
436 })
437}
438
439#[unsafe(no_mangle)]
446pub unsafe extern "C" fn asdf_parser_has_error(parser: *const AsdfParser) -> bool {
447 guard("asdf_parser_has_error", false, || {
448 parser_ref(parser).is_some_and(|p| p.error.code() != 0)
449 })
450}
451
452#[unsafe(no_mangle)]
458pub unsafe extern "C" fn asdf_parser_get_error(parser: *const AsdfParser) -> *const c_char {
459 guard("asdf_parser_get_error", core::ptr::null(), || match parser_ref(parser) {
460 Some(p) => p.error.message_ptr(),
461 None => core::ptr::null(),
462 })
463}
464
465#[unsafe(no_mangle)]
470pub unsafe extern "C" fn asdf_parser_error_code(parser: *const AsdfParser) -> c_int {
471 guard("asdf_parser_error_code", 0, || parser_ref(parser).map_or(0, |p| p.error.code()))
472}
473
474#[unsafe(no_mangle)]
479pub unsafe extern "C" fn asdf_parser_error_errno(parser: *const AsdfParser) -> c_int {
480 guard("asdf_parser_error_errno", 0, || parser_ref(parser).map_or(0, |p| p.error.errno()))
481}
482
483#[unsafe(no_mangle)]
490pub unsafe extern "C" fn asdf_event_type(event: *mut AsdfEvent) -> AsdfEventType {
491 guard("asdf_event_type", AsdfEventType::None, || match event_ref(event) {
492 Some(e) => e.event_type,
493 None => AsdfEventType::None,
494 })
495}
496
497#[unsafe(no_mangle)]
502pub extern "C" fn asdf_event_type_name(event_type: c_int) -> *const c_char {
503 match AsdfEventType::from_i32(event_type) {
506 Some(known) => known.name().as_ptr(),
507 None => c"ASDF_UNKNOWN_EVENT".as_ptr(),
508 }
509}
510
511#[unsafe(no_mangle)]
517pub unsafe extern "C" fn asdf_event_comment(event: *const AsdfEvent) -> *const c_char {
518 guard("asdf_event_comment", core::ptr::null(), || match event_ref(event).map(|e| &e.payload) {
519 Some(Payload::Comment(text)) => text.as_ptr(),
520 _ => core::ptr::null(),
521 })
522}
523
524#[unsafe(no_mangle)]
530pub unsafe extern "C" fn asdf_event_tree_info(event: *const AsdfEvent) -> *const asdf_tree_info_t {
531 guard("asdf_event_tree_info", core::ptr::null(), || {
532 match event_ref(event).map(|e| &e.payload) {
533 Some(Payload::Tree { info, .. }) => core::ptr::from_ref::<asdf_tree_info_t>(info),
534 _ => core::ptr::null(),
535 }
536 })
537}
538
539#[unsafe(no_mangle)]
545pub unsafe extern "C" fn asdf_event_block_info(
546 event: *const AsdfEvent,
547) -> *const asdf_block_info_t {
548 guard("asdf_event_block_info", core::ptr::null(), || {
549 match event_ref(event).map(|e| &e.payload) {
550 Some(Payload::Block(info)) => core::ptr::from_ref::<asdf_block_info_t>(info),
551 _ => core::ptr::null(),
552 }
553 })
554}
555
556#[unsafe(no_mangle)]
563pub unsafe extern "C" fn asdf_event_iterate(parser: *mut AsdfParser) -> *mut AsdfEvent {
564 guard("asdf_event_iterate", core::ptr::null_mut(), || {
565 let Some(state) = parser_mut(parser) else {
566 return core::ptr::null_mut();
567 };
568 if !state.iterated.is_null() {
569 let previous = state.iterated;
570 state.release(previous);
571 }
572 let event = state.next_event();
573 state.iterated = event;
574 event
575 })
576}
577
578#[unsafe(no_mangle)]
584pub unsafe extern "C" fn asdf_event_free(parser: *mut AsdfParser, event: *mut AsdfEvent) {
585 guard("asdf_event_free", (), || {
586 if let Some(state) = parser_mut(parser) {
587 state.release(event);
588 }
589 })
590}
591
592#[unsafe(no_mangle)]
598pub unsafe extern "C" fn asdf_event_print(
599 event: *const AsdfEvent,
600 file: *mut c_void,
601 verbose: bool,
602) {
603 guard("asdf_event_print", (), || {
604 let Some(state) = event_ref(event) else {
605 return;
606 };
607 write_c_stream(file, &render_event(&state.source, verbose));
608 })
609}
610
611fn write_c_stream(file: *mut c_void, text: &str) {
613 let stream = if file.is_null() { unsafe { stdout_stream() } } else { file.cast() };
614 if stream.is_null() {
615 return;
616 }
617 unsafe {
618 libc::fwrite(text.as_ptr().cast::<c_void>(), 1, text.len(), stream);
619 }
620}
621
622unsafe fn stdout_stream() -> *mut libc::FILE {
624 unsafe { libc::fdopen(1, c"w".as_ptr()) }
627}
628
629#[unsafe(no_mangle)]
636pub unsafe extern "C" fn asdf_yaml_event_type(event: *const AsdfEvent) -> AsdfYamlEventType {
637 guard("asdf_yaml_event_type", AsdfYamlEventType::None, || {
638 match event_ref(event).map(|e| &e.payload) {
639 Some(Payload::Yaml(sub)) => sub.kind,
640 _ => AsdfYamlEventType::None,
641 }
642 })
643}
644
645#[unsafe(no_mangle)]
652pub unsafe extern "C" fn asdf_yaml_event_type_text(event: *const AsdfEvent) -> *const c_char {
653 guard("asdf_yaml_event_type_text", c"".as_ptr(), || {
654 match event_ref(event).map(|e| &e.payload) {
655 Some(Payload::Yaml(sub)) => sub.kind.text().as_ptr(),
656 _ => c"".as_ptr(),
657 }
658 })
659}
660
661#[unsafe(no_mangle)]
667pub unsafe extern "C" fn asdf_yaml_event_scalar_value(
668 event: *const AsdfEvent,
669 lenp: *mut usize,
670) -> *const c_char {
671 guard("asdf_yaml_event_scalar_value", core::ptr::null(), || {
672 let text = match event_ref(event).map(|e| &e.payload) {
673 Some(Payload::Yaml(sub)) => sub.value.as_ref(),
674 _ => None,
675 };
676 match text {
677 Some(value) => {
678 if !lenp.is_null() {
679 unsafe { write_out(lenp, value.as_bytes().len()) };
680 }
681 value.as_ptr()
682 }
683 None => {
684 if !lenp.is_null() {
685 unsafe { write_out(lenp, 0) };
686 }
687 core::ptr::null()
688 }
689 }
690 })
691}
692
693#[unsafe(no_mangle)]
698pub unsafe extern "C" fn asdf_yaml_event_tag(
699 event: *const AsdfEvent,
700 lenp: *mut usize,
701) -> *const c_char {
702 guard("asdf_yaml_event_tag", core::ptr::null(), || {
703 let tag = match event_ref(event).map(|e| &e.payload) {
704 Some(Payload::Yaml(sub)) => sub.tag.as_ref(),
705 _ => None,
706 };
707 match tag {
708 Some(value) => {
709 if !lenp.is_null() {
710 unsafe { write_out(lenp, value.as_bytes().len()) };
711 }
712 value.as_ptr()
713 }
714 None => {
715 if !lenp.is_null() {
716 unsafe { write_out(lenp, 0) };
717 }
718 core::ptr::null()
719 }
720 }
721 })
722}
723
724#[cfg(test)]
725mod tests {
726 use super::*;
727 use crate::types::parser_opt;
728
729 fn sample() -> Vec<u8> {
731 let mut buf = Vec::new();
732 buf.extend_from_slice(b"#ASDF 1.0.0\n#ASDF_STANDARD 1.6.0\n#a note\n");
733 buf.extend_from_slice(b"%YAML 1.1\n%TAG ! tag:stsci.edu:asdf/\n--- !core/asdf-1.1.0\n");
734 buf.extend_from_slice(b"n: 1\nname: probe\n");
735 buf.extend_from_slice(b"...\n");
736 buf
737 }
738
739 struct Parser(*mut AsdfParser);
740 impl Drop for Parser {
741 fn drop(&mut self) {
742 unsafe { asdf_parser_destroy(self.0) };
743 }
744 }
745
746 fn parse(bytes: &[u8], flags: AsdfParserOptFlags) -> Parser {
747 let cfg = asdf_parser_cfg_t { flags, log: core::ptr::null_mut() };
748 let parser = unsafe { asdf_parser_create(&cfg) };
749 assert!(!parser.is_null());
750 assert_eq!(
751 unsafe { asdf_parser_set_input_mem(parser, bytes.as_ptr().cast(), bytes.len()) },
752 0
753 );
754 Parser(parser)
755 }
756
757 fn event_types(parser: &Parser) -> Vec<AsdfEventType> {
759 let mut out = Vec::new();
760 loop {
761 let event = unsafe { asdf_event_iterate(parser.0) };
762 if event.is_null() {
763 return out;
764 }
765 out.push(unsafe { asdf_event_type(event) });
766 }
767 }
768
769 #[test]
770 fn reports_the_expected_event_sequence() {
771 let bytes = sample();
772 let parser = parse(&bytes, 0);
773 assert_eq!(
774 event_types(&parser),
775 vec![
776 AsdfEventType::AsdfVersion,
777 AsdfEventType::StandardVersion,
778 AsdfEventType::Comment,
779 AsdfEventType::TreeStart,
780 AsdfEventType::TreeEnd,
781 AsdfEventType::End,
782 ]
783 );
784 }
785
786 #[test]
787 fn yaml_events_appear_only_when_asked_for() {
788 let bytes = sample();
789 let quiet = parse(&bytes, 0);
790 assert!(!event_types(&quiet).contains(&AsdfEventType::Yaml));
791
792 let loud = parse(&bytes, parser_opt::EMIT_YAML_EVENTS);
793 let types = event_types(&loud);
794 assert!(types.contains(&AsdfEventType::Yaml));
795 assert_eq!(types.iter().filter(|t| **t == AsdfEventType::Yaml).count(), 10);
798 }
799
800 #[test]
801 fn comment_text_drops_its_leading_hash() {
802 let bytes = sample();
803 let parser = parse(&bytes, 0);
804 loop {
805 let event = unsafe { asdf_event_iterate(parser.0) };
806 assert!(!event.is_null(), "no comment event in the stream");
807 if unsafe { asdf_event_type(event) } == AsdfEventType::Comment {
808 let text = unsafe { asdf_event_comment(event) };
809 assert_eq!(unsafe { CStr::from_ptr(text) }, c"a note");
810 return;
811 }
812 }
813 }
814
815 #[test]
816 fn tree_info_brackets_the_yaml() {
817 let bytes = sample();
818 let parser = parse(&bytes, 0);
819 let mut start = None;
820 let mut end = None;
821 loop {
822 let event = unsafe { asdf_event_iterate(parser.0) };
823 if event.is_null() {
824 break;
825 }
826 match unsafe { asdf_event_type(event) } {
827 AsdfEventType::TreeStart => {
828 let info = unsafe { &*asdf_event_tree_info(event) };
829 start = Some(info.start);
830 }
831 AsdfEventType::TreeEnd => {
832 let info = unsafe { &*asdf_event_tree_info(event) };
833 end = Some(info.end);
834 }
835 _ => {}
836 }
837 }
838 let (start, end) = (start.expect("tree start"), end.expect("tree end"));
839 assert_eq!(&bytes[start..start + 5], b"%YAML");
842 assert!(end > start && end <= bytes.len());
843 }
844
845 #[test]
846 fn buffered_tree_hands_back_its_text() {
847 let bytes = sample();
848 let parser = parse(&bytes, parser_opt::BUFFER_TREE);
849 loop {
850 let event = unsafe { asdf_event_iterate(parser.0) };
851 assert!(!event.is_null());
852 if unsafe { asdf_event_type(event) } == AsdfEventType::TreeEnd {
853 let info = unsafe { &*asdf_event_tree_info(event) };
854 assert!(!info.buf.is_null());
855 let text = unsafe { CStr::from_ptr(info.buf) }.to_string_lossy().into_owned();
856 assert!(text.starts_with("%YAML 1.1"), "unexpected tree text: {text}");
857 assert!(text.contains("name: probe"));
858 return;
859 }
860 }
861 }
862
863 #[test]
864 fn accessors_reject_events_of_the_wrong_type() {
865 let bytes = sample();
866 let parser = parse(&bytes, 0);
867 let event = unsafe { asdf_event_iterate(parser.0) };
868 assert_eq!(unsafe { asdf_event_type(event) }, AsdfEventType::AsdfVersion);
869 assert!(unsafe { asdf_event_comment(event) }.is_null());
870 assert!(unsafe { asdf_event_tree_info(event) }.is_null());
871 assert!(unsafe { asdf_event_block_info(event) }.is_null());
872 assert_eq!(unsafe { asdf_yaml_event_type(event) }, AsdfYamlEventType::None);
873 }
874
875 #[test]
876 fn parse_hands_out_events_the_caller_frees() {
877 let bytes = sample();
878 let parser = parse(&bytes, 0);
879 let first = unsafe { asdf_parser_parse(parser.0) };
882 let second = unsafe { asdf_parser_parse(parser.0) };
883 assert!(!first.is_null() && !second.is_null());
884 assert_eq!(unsafe { asdf_event_type(first) }, AsdfEventType::AsdfVersion);
885 assert_eq!(unsafe { asdf_event_type(second) }, AsdfEventType::StandardVersion);
886 unsafe { asdf_event_free(parser.0, first) };
887 unsafe { asdf_event_free(parser.0, second) };
888 let _ = unsafe { asdf_parser_parse(parser.0) };
890 }
891
892 #[test]
893 fn event_type_names_match_the_enum_spelling() {
894 let name = asdf_event_type_name(AsdfEventType::BlockIndex as c_int);
895 assert_eq!(unsafe { CStr::from_ptr(name) }, c"ASDF_BLOCK_INDEX_EVENT");
896 assert_eq!(unsafe { CStr::from_ptr(asdf_event_type_name(99)) }, c"ASDF_UNKNOWN_EVENT");
899 assert_eq!(unsafe { CStr::from_ptr(asdf_event_type_name(-1)) }, c"ASDF_UNKNOWN_EVENT");
900 }
901
902 #[test]
903 fn a_bad_buffer_is_reported_not_fatal() {
904 let cfg = asdf_parser_cfg_t { flags: 0, log: core::ptr::null_mut() };
905 let parser = Parser(unsafe { asdf_parser_create(&cfg) });
906 let junk = b"not an asdf file at all\n";
907 assert_eq!(
908 unsafe { asdf_parser_set_input_mem(parser.0, junk.as_ptr().cast(), junk.len()) },
909 -1
910 );
911 assert!(unsafe { asdf_parser_has_error(parser.0) });
912 assert!(!unsafe { asdf_parser_get_error(parser.0) }.is_null());
913 assert_ne!(unsafe { asdf_parser_error_code(parser.0) }, 0);
914 }
915
916 #[test]
917 fn null_handles_are_tolerated() {
918 assert!(unsafe { asdf_parser_parse(core::ptr::null_mut()) }.is_null());
919 assert!(unsafe { asdf_event_iterate(core::ptr::null_mut()) }.is_null());
920 assert!(!unsafe { asdf_parser_has_error(core::ptr::null()) });
921 assert_eq!(unsafe { asdf_event_type(core::ptr::null_mut()) }, AsdfEventType::None);
922 assert!(unsafe { asdf_event_comment(core::ptr::null()) }.is_null());
923 unsafe { asdf_parser_destroy(core::ptr::null_mut()) };
924 unsafe { asdf_event_free(core::ptr::null_mut(), core::ptr::null_mut()) };
925 let mut len = 7usize;
926 assert!(unsafe { asdf_yaml_event_tag(core::ptr::null(), &mut len) }.is_null());
927 assert_eq!(len, 0, "the length must be cleared even when there is no tag");
928 }
929
930 #[test]
931 fn missing_input_files_are_reported() {
932 let cfg = asdf_parser_cfg_t { flags: 0, log: core::ptr::null_mut() };
933 let parser = Parser(unsafe { asdf_parser_create(&cfg) });
934 let path = CString::new("/nonexistent/definitely-not-here.asdf").unwrap();
935 assert_eq!(unsafe { asdf_parser_set_input_file(parser.0, path.as_ptr()) }, -1);
936 assert!(unsafe { asdf_parser_has_error(parser.0) });
937 assert_ne!(unsafe { asdf_parser_error_errno(parser.0) }, 0);
938 }
939}