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