1use crate::ffi::write_out;
22use crate::file_ffi::file_document_mut;
23use alloc::ffi::CString;
24use core::ffi::{CStr, c_char, c_int};
25
26use asdf_core::yaml::{NodeData, NodeId, Resolved, ScalarStyle, Schema, resolve};
27
28use crate::file_ffi::{AsdfFile, AsdfValue, value_document, value_file, value_node};
29use crate::panic::guard;
30use crate::types::{
31 AsdfValueErr, AsdfValueType, asdf_container_iter_t, asdf_mapping_iter_t, asdf_sequence_iter_t,
32};
33
34pub type AsdfMapping = AsdfValue;
37
38pub type AsdfSequence = AsdfValue;
40
41fn resolved_of(value: *mut AsdfValue) -> Option<Resolved> {
43 let doc = value_document(value)?;
44 let node = value_node(value)?;
45 let resolved = doc.resolved(node);
46 let NodeData::Scalar { value: text, style } = &resolved.data else {
47 return None;
48 };
49 if let Some(tag) = doc.tag_of(node)
51 && tag.is_yaml_builtin()
52 && let Some(r) = asdf_core::yaml::resolve_tagged(text, tag.suffix(), Schema::Libasdf)
53 {
54 return Some(r);
55 }
56 Some(resolve(text, *style, Schema::Libasdf))
57}
58
59pub(crate) fn make_value(file: *mut AsdfFile, node: NodeId) -> *mut AsdfValue {
61 Box::into_raw(Box::new(AsdfValue::new(file, node)))
62}
63
64#[unsafe(no_mangle)]
74pub unsafe extern "C" fn asdf_value_copy(value: *mut AsdfValue) -> *mut AsdfValue {
75 guard("asdf_value_copy", core::ptr::null_mut(), || {
76 let (Some(file), Some(node)) = (value_file(value), value_node(value)) else {
77 return core::ptr::null_mut();
78 };
79 make_value(file, node)
80 })
81}
82
83#[unsafe(no_mangle)]
88pub unsafe extern "C" fn asdf_value_file(value: *mut AsdfValue) -> *mut AsdfFile {
89 guard("asdf_value_file", core::ptr::null_mut(), || {
90 value_file(value).unwrap_or(core::ptr::null_mut())
91 })
92}
93
94#[unsafe(no_mangle)]
99pub unsafe extern "C" fn asdf_value_is_container(value: *mut AsdfValue) -> bool {
100 guard("asdf_value_is_container", false, || {
101 let (Some(doc), Some(node)) = (value_document(value), value_node(value)) else {
102 return false;
103 };
104 let resolved = doc.resolved(node);
105 resolved.is_mapping() || resolved.is_sequence()
106 })
107}
108
109#[unsafe(no_mangle)]
114pub unsafe extern "C" fn asdf_container_size(container: *mut AsdfValue) -> c_int {
115 guard("asdf_container_size", -1, || container_size(container))
116}
117
118pub(crate) fn container_size(container: *mut AsdfValue) -> c_int {
124 let (Some(doc), Some(node)) = (value_document(container), value_node(container)) else {
125 return -1;
126 };
127 doc.container_len(node).and_then(|n| c_int::try_from(n).ok()).unwrap_or(-1)
128}
129
130#[unsafe(no_mangle)]
135pub unsafe extern "C" fn asdf_value_is_type(value: *mut AsdfValue, value_type: c_int) -> bool {
136 guard("asdf_value_is_type", false, || {
137 let Some(wanted) = AsdfValueType::from_i32(value_type) else {
140 return false;
141 };
142 match wanted {
143 AsdfValueType::Unknown => false,
145 AsdfValueType::Scalar => value_is_scalar(value),
148 AsdfValueType::Mapping => value_is_mapping(value),
149 AsdfValueType::Sequence => value_is_sequence(value),
150 AsdfValueType::Bool => unsafe { asdf_value_is_bool(value) },
151 AsdfValueType::Int8 => unsafe { asdf_value_is_int8(value) },
152 AsdfValueType::Int16 => unsafe { asdf_value_is_int16(value) },
153 AsdfValueType::Int32 => unsafe { asdf_value_is_int32(value) },
154 AsdfValueType::Int64 => unsafe { asdf_value_is_int64(value) },
155 AsdfValueType::Uint8 => unsafe { asdf_value_is_uint8(value) },
156 AsdfValueType::Uint16 => unsafe { asdf_value_is_uint16(value) },
157 AsdfValueType::Uint32 => unsafe { asdf_value_is_uint32(value) },
158 AsdfValueType::Uint64 => unsafe { asdf_value_is_uint64(value) },
159 other => {
160 let actual = unsafe { crate::file_ffi::asdf_value_get_type(value) };
161 actual == other
162 }
163 }
164 })
165}
166
167#[unsafe(no_mangle)]
174pub unsafe extern "C" fn asdf_value_is_mapping(value: *mut AsdfValue) -> bool {
175 guard("asdf_value_is_mapping", false, || value_is_mapping(value))
176}
177
178pub(crate) fn value_is_mapping(value: *mut AsdfValue) -> bool {
184 value_document(value)
185 .zip(value_node(value))
186 .is_some_and(|(doc, node)| doc.resolved(node).is_mapping())
187}
188
189#[unsafe(no_mangle)]
194pub unsafe extern "C" fn asdf_value_as_mapping(
195 value: *mut AsdfValue,
196 out: *mut *mut AsdfMapping,
197) -> AsdfValueErr {
198 guard("asdf_value_as_mapping", AsdfValueErr::Unknown, || {
199 if !value_is_mapping(value) {
200 return AsdfValueErr::TypeMismatch;
201 }
202 if !out.is_null() {
203 unsafe { write_out(out, value) };
204 }
205 AsdfValueErr::Ok
206 })
207}
208
209#[unsafe(no_mangle)]
214pub unsafe extern "C" fn asdf_mapping_size(mapping: *mut AsdfMapping) -> c_int {
215 guard("asdf_mapping_size", -1, || {
216 if !value_is_mapping(mapping) {
217 return -1;
218 }
219 container_size(mapping)
220 })
221}
222
223#[unsafe(no_mangle)]
229pub unsafe extern "C" fn asdf_mapping_get(
230 mapping: *mut AsdfMapping,
231 key: *const c_char,
232) -> *mut AsdfValue {
233 guard("asdf_mapping_get", core::ptr::null_mut(), || {
234 if key.is_null() {
235 return core::ptr::null_mut();
236 }
237 let (Some(doc), Some(node), Some(file)) =
238 (value_document(mapping), value_node(mapping), value_file(mapping))
239 else {
240 return core::ptr::null_mut();
241 };
242 let key = unsafe { CStr::from_ptr(key) }.to_string_lossy().into_owned();
243 match doc.mapping_get(node, &key) {
244 Some(found) => make_value(file, found),
245 None => core::ptr::null_mut(),
246 }
247 })
248}
249
250#[repr(C)]
257struct MappingIter {
258 public: asdf_mapping_iter_t,
260 file: *mut AsdfFile,
261 entries: Vec<(Option<String>, NodeId)>,
262 position: usize,
263 current_key: Option<CString>,
266 current_value: *mut AsdfValue,
269}
270
271fn mapping_iter_init(mapping: *mut AsdfMapping, reverse: bool) -> *mut asdf_mapping_iter_t {
272 let (Some(doc), Some(node), Some(file)) =
273 (value_document(mapping), value_node(mapping), value_file(mapping))
274 else {
275 return core::ptr::null_mut();
276 };
277 let Some(entries) = doc.mapping_entries(node) else {
278 return core::ptr::null_mut();
279 };
280
281 let mut collected: Vec<(Option<String>, NodeId)> = entries
282 .iter()
283 .map(|entry| {
284 let key = doc.resolved(entry.key).as_str().map(str::to_string);
287 (key, entry.value)
288 })
289 .collect();
290 if reverse {
291 collected.reverse();
292 }
293
294 let iter = Box::new(MappingIter {
295 public: asdf_mapping_iter_t { key: core::ptr::null(), value: core::ptr::null_mut() },
296 file,
297 entries: collected,
298 position: 0,
299 current_key: None,
300 current_value: core::ptr::null_mut(),
301 });
302 Box::into_raw(iter).cast::<asdf_mapping_iter_t>()
304}
305
306#[unsafe(no_mangle)]
311pub unsafe extern "C" fn asdf_mapping_iter_init(
312 mapping: *mut AsdfMapping,
313) -> *mut asdf_mapping_iter_t {
314 guard("asdf_mapping_iter_init", core::ptr::null_mut(), || mapping_iter_init(mapping, false))
315}
316
317#[unsafe(no_mangle)]
322pub unsafe extern "C" fn asdf_mapping_reverse_iter_init(
323 mapping: *mut AsdfMapping,
324) -> *mut asdf_mapping_iter_t {
325 guard("asdf_mapping_reverse_iter_init", core::ptr::null_mut(), || {
326 mapping_iter_init(mapping, true)
327 })
328}
329
330#[unsafe(no_mangle)]
340pub unsafe extern "C" fn asdf_mapping_iter_next(iter_ptr: *mut *mut asdf_mapping_iter_t) -> bool {
341 guard("asdf_mapping_iter_next", false, || {
342 if iter_ptr.is_null() {
343 return false;
344 }
345 let raw = unsafe { *iter_ptr };
346 if raw.is_null() {
347 return false;
348 }
349 let iter = unsafe { &mut *raw.cast::<MappingIter>() };
350
351 if !iter.current_value.is_null() {
353 drop(unsafe { Box::from_raw(iter.current_value) });
354 iter.current_value = core::ptr::null_mut();
355 }
356
357 if iter.position >= iter.entries.len() {
358 mapping_iter_destroy(raw);
359 unsafe { write_out(iter_ptr, core::ptr::null_mut()) };
360 return false;
361 }
362
363 let (key, node) = iter.entries[iter.position].clone();
364 iter.position += 1;
365
366 iter.current_key = key.and_then(|k| CString::new(k).ok());
367 iter.public.key = iter.current_key.as_ref().map_or(core::ptr::null(), |k| k.as_ptr());
368
369 iter.current_value = make_value(iter.file, node);
370 iter.public.value = iter.current_value.cast();
371 true
372 })
373}
374
375#[unsafe(no_mangle)]
380pub unsafe extern "C" fn asdf_mapping_iter_destroy(iter: *mut asdf_mapping_iter_t) {
381 guard("asdf_mapping_iter_destroy", (), || mapping_iter_destroy(iter))
382}
383
384pub(crate) fn mapping_iter_destroy(iter: *mut asdf_mapping_iter_t) {
390 if iter.is_null() {
391 return;
392 }
393 let mut boxed = unsafe { Box::from_raw(iter.cast::<MappingIter>()) };
394 if !boxed.current_value.is_null() {
395 drop(unsafe { Box::from_raw(boxed.current_value) });
396 boxed.current_value = core::ptr::null_mut();
397 }
398}
399
400#[unsafe(no_mangle)]
407pub unsafe extern "C" fn asdf_value_is_sequence(value: *mut AsdfValue) -> bool {
408 guard("asdf_value_is_sequence", false, || value_is_sequence(value))
409}
410
411pub(crate) fn value_is_sequence(value: *mut AsdfValue) -> bool {
417 value_document(value)
418 .zip(value_node(value))
419 .is_some_and(|(doc, node)| doc.resolved(node).is_sequence())
420}
421
422#[unsafe(no_mangle)]
427pub unsafe extern "C" fn asdf_value_as_sequence(
428 value: *mut AsdfValue,
429 out: *mut *mut AsdfSequence,
430) -> AsdfValueErr {
431 guard("asdf_value_as_sequence", AsdfValueErr::Unknown, || {
432 if !value_is_sequence(value) {
433 return AsdfValueErr::TypeMismatch;
434 }
435 if !out.is_null() {
436 unsafe { write_out(out, value) };
437 }
438 AsdfValueErr::Ok
439 })
440}
441
442#[unsafe(no_mangle)]
447pub unsafe extern "C" fn asdf_sequence_size(sequence: *mut AsdfSequence) -> c_int {
448 guard("asdf_sequence_size", -1, || {
449 if !value_is_sequence(sequence) {
450 return -1;
451 }
452 container_size(sequence)
453 })
454}
455
456#[unsafe(no_mangle)]
462pub unsafe extern "C" fn asdf_sequence_get(
463 sequence: *mut AsdfSequence,
464 index: c_int,
465) -> *mut AsdfValue {
466 guard("asdf_sequence_get", core::ptr::null_mut(), || {
467 let (Some(doc), Some(node), Some(file)) =
468 (value_document(sequence), value_node(sequence), value_file(sequence))
469 else {
470 return core::ptr::null_mut();
471 };
472 match doc.sequence_get(node, i64::from(index)) {
473 Some(found) => make_value(file, found),
474 None => core::ptr::null_mut(),
475 }
476 })
477}
478
479#[repr(C)]
481struct SequenceIter {
482 public: asdf_sequence_iter_t,
484 file: *mut AsdfFile,
485 items: Vec<NodeId>,
486 position: usize,
487 indices: Vec<c_int>,
490 current_value: *mut AsdfValue,
491}
492
493fn sequence_iter_init(sequence: *mut AsdfSequence, reverse: bool) -> *mut asdf_sequence_iter_t {
494 let (Some(doc), Some(node), Some(file)) =
495 (value_document(sequence), value_node(sequence), value_file(sequence))
496 else {
497 return core::ptr::null_mut();
498 };
499 let Some(items) = doc.sequence_items(node) else {
500 return core::ptr::null_mut();
501 };
502
503 let mut items = items.to_vec();
504 let mut indices: Vec<c_int> =
505 (0..items.len()).map(|i| c_int::try_from(i).unwrap_or(c_int::MAX)).collect();
506 if reverse {
507 items.reverse();
508 indices.reverse();
509 }
510
511 let iter = Box::new(SequenceIter {
512 public: asdf_sequence_iter_t { index: -1, value: core::ptr::null_mut() },
513 file,
514 items,
515 position: 0,
516 indices,
517 current_value: core::ptr::null_mut(),
518 });
519 Box::into_raw(iter).cast::<asdf_sequence_iter_t>()
520}
521
522#[unsafe(no_mangle)]
527pub unsafe extern "C" fn asdf_sequence_iter_init(
528 sequence: *mut AsdfSequence,
529) -> *mut asdf_sequence_iter_t {
530 guard("asdf_sequence_iter_init", core::ptr::null_mut(), || sequence_iter_init(sequence, false))
531}
532
533#[unsafe(no_mangle)]
538pub unsafe extern "C" fn asdf_sequence_reverse_iter_init(
539 sequence: *mut AsdfSequence,
540) -> *mut asdf_sequence_iter_t {
541 guard("asdf_sequence_reverse_iter_init", core::ptr::null_mut(), || {
542 sequence_iter_init(sequence, true)
543 })
544}
545
546#[unsafe(no_mangle)]
553pub unsafe extern "C" fn asdf_sequence_iter_next(iter_ptr: *mut *mut asdf_sequence_iter_t) -> bool {
554 guard("asdf_sequence_iter_next", false, || {
555 if iter_ptr.is_null() {
556 return false;
557 }
558 let raw = unsafe { *iter_ptr };
559 if raw.is_null() {
560 return false;
561 }
562 let iter = unsafe { &mut *raw.cast::<SequenceIter>() };
563
564 if !iter.current_value.is_null() {
565 drop(unsafe { Box::from_raw(iter.current_value) });
566 iter.current_value = core::ptr::null_mut();
567 }
568
569 if iter.position >= iter.items.len() {
570 sequence_iter_destroy(raw);
571 unsafe { write_out(iter_ptr, core::ptr::null_mut()) };
572 return false;
573 }
574
575 let node = iter.items[iter.position];
576 iter.public.index = iter.indices[iter.position];
577 iter.position += 1;
578
579 iter.current_value = make_value(iter.file, node);
580 iter.public.value = iter.current_value.cast();
581 true
582 })
583}
584
585#[unsafe(no_mangle)]
590pub unsafe extern "C" fn asdf_sequence_iter_destroy(iter: *mut asdf_sequence_iter_t) {
591 guard("asdf_sequence_iter_destroy", (), || sequence_iter_destroy(iter))
592}
593
594pub(crate) fn sequence_iter_destroy(iter: *mut asdf_sequence_iter_t) {
600 if iter.is_null() {
601 return;
602 }
603 let mut boxed = unsafe { Box::from_raw(iter.cast::<SequenceIter>()) };
604 if !boxed.current_value.is_null() {
605 drop(unsafe { Box::from_raw(boxed.current_value) });
606 boxed.current_value = core::ptr::null_mut();
607 }
608}
609
610macro_rules! value_int_accessors {
614 ($is:ident, $as:ident, $ty:ty, $variant:ident) => {
615 #[unsafe(no_mangle)]
624 pub unsafe extern "C" fn $is(value: *mut AsdfValue) -> bool {
625 guard(stringify!($is), false, || match resolved_of(value) {
626 Some(Resolved::Uint(v, _)) => <$ty>::try_from(v).is_ok(),
627 Some(Resolved::Int(v, _)) => <$ty>::try_from(v).is_ok(),
628 _ => false,
629 })
630 }
631
632 #[unsafe(no_mangle)]
642 pub unsafe extern "C" fn $as(value: *mut AsdfValue, out: *mut $ty) -> AsdfValueErr {
643 guard(stringify!($as), AsdfValueErr::Unknown, || {
644 let Some(resolved) = resolved_of(value) else {
645 return AsdfValueErr::TypeMismatch;
646 };
647 let (truncated, fits): ($ty, bool) = match resolved {
648 Resolved::Uint(v, _) => (v as $ty, <$ty>::try_from(v).is_ok()),
649 Resolved::Int(v, _) => (v as $ty, <$ty>::try_from(v).is_ok()),
650 Resolved::IntOverflow => return AsdfValueErr::Overflow,
653 _ => return AsdfValueErr::TypeMismatch,
654 };
655 if !out.is_null() {
656 unsafe { write_out(out, truncated) };
657 }
658 if fits { AsdfValueErr::Ok } else { AsdfValueErr::Overflow }
659 })
660 }
661 };
662}
663
664value_int_accessors!(asdf_value_is_int8, asdf_value_as_int8, i8, Int8);
665value_int_accessors!(asdf_value_is_int16, asdf_value_as_int16, i16, Int16);
666value_int_accessors!(asdf_value_is_int32, asdf_value_as_int32, i32, Int32);
667value_int_accessors!(asdf_value_is_int64, asdf_value_as_int64, i64, Int64);
668value_int_accessors!(asdf_value_is_uint8, asdf_value_as_uint8, u8, Uint8);
669value_int_accessors!(asdf_value_is_uint16, asdf_value_as_uint16, u16, Uint16);
670value_int_accessors!(asdf_value_is_uint32, asdf_value_as_uint32, u32, Uint32);
671value_int_accessors!(asdf_value_is_uint64, asdf_value_as_uint64, u64, Uint64);
672
673#[unsafe(no_mangle)]
678pub unsafe extern "C" fn asdf_value_is_int(value: *mut AsdfValue) -> bool {
679 guard("asdf_value_is_int", false, || {
680 matches!(resolved_of(value), Some(Resolved::Int(..) | Resolved::Uint(..)))
681 })
682}
683
684#[unsafe(no_mangle)]
689pub unsafe extern "C" fn asdf_value_as_double(
690 value: *mut AsdfValue,
691 out: *mut f64,
692) -> AsdfValueErr {
693 guard("asdf_value_as_double", AsdfValueErr::Unknown, || value_as_double(value, out))
694}
695
696pub(crate) fn value_as_double(value: *mut AsdfValue, out: *mut f64) -> AsdfValueErr {
702 let converted = match resolved_of(value) {
703 Some(Resolved::Double(d)) => d,
704 Some(Resolved::Uint(v, _)) => v as f64,
705 Some(Resolved::Int(v, _)) => v as f64,
706 _ => return AsdfValueErr::TypeMismatch,
707 };
708 if !out.is_null() {
709 unsafe { write_out(out, converted) };
710 }
711 AsdfValueErr::Ok
712}
713
714#[unsafe(no_mangle)]
719pub unsafe extern "C" fn asdf_value_as_float(value: *mut AsdfValue, out: *mut f32) -> AsdfValueErr {
720 guard("asdf_value_as_float", AsdfValueErr::Unknown, || {
721 let mut wide = 0f64;
722 let err = value_as_double(value, &mut wide);
723 if err != AsdfValueErr::Ok {
724 return err;
725 }
726 let narrow = wide as f32;
727 if !out.is_null() {
728 unsafe { write_out(out, narrow) };
729 }
730 if wide.is_finite() && narrow.is_infinite() {
734 return AsdfValueErr::Overflow;
735 }
736 AsdfValueErr::Ok
737 })
738}
739
740#[unsafe(no_mangle)]
745pub unsafe extern "C" fn asdf_value_is_double(value: *mut AsdfValue) -> bool {
746 guard("asdf_value_is_double", false, || matches!(resolved_of(value), Some(Resolved::Double(_))))
747}
748
749#[unsafe(no_mangle)]
755pub unsafe extern "C" fn asdf_value_is_float(value: *mut AsdfValue) -> bool {
756 guard("asdf_value_is_float", false, || unsafe { asdf_value_is_double(value) })
757}
758
759#[unsafe(no_mangle)]
764pub unsafe extern "C" fn asdf_value_is_bool(value: *mut AsdfValue) -> bool {
765 guard("asdf_value_is_bool", false, || bool_of(value).is_some())
766}
767
768fn bool_of(value: *mut AsdfValue) -> Option<bool> {
775 match resolved_of(value)? {
776 Resolved::Bool(v) => Some(v),
777 Resolved::Uint(0, _) => Some(false),
778 Resolved::Uint(1, _) => Some(true),
779 _ => None,
780 }
781}
782
783#[unsafe(no_mangle)]
791pub unsafe extern "C" fn asdf_value_as_bool(value: *mut AsdfValue, out: *mut bool) -> AsdfValueErr {
792 guard("asdf_value_as_bool", AsdfValueErr::Unknown, || {
793 let Some(converted) = bool_of(value) else {
794 return AsdfValueErr::TypeMismatch;
795 };
796 if !out.is_null() {
797 unsafe { write_out(out, converted) };
798 }
799 AsdfValueErr::Ok
800 })
801}
802
803#[unsafe(no_mangle)]
808pub unsafe extern "C" fn asdf_value_is_null(value: *mut AsdfValue) -> bool {
809 guard("asdf_value_is_null", false, || matches!(resolved_of(value), Some(Resolved::Null)))
810}
811
812#[unsafe(no_mangle)]
817pub unsafe extern "C" fn asdf_value_is_string(value: *mut AsdfValue) -> bool {
818 guard("asdf_value_is_string", false, || matches!(resolved_of(value), Some(Resolved::String)))
819}
820
821#[unsafe(no_mangle)]
827pub unsafe extern "C" fn asdf_value_as_string0(
828 value: *mut AsdfValue,
829 out: *mut *const c_char,
830) -> AsdfValueErr {
831 guard("asdf_value_as_string0", AsdfValueErr::Unknown, || {
832 if !matches!(resolved_of(value), Some(Resolved::String)) {
833 return AsdfValueErr::TypeMismatch;
834 }
835 intern_scalar(value, out)
836 })
837}
838
839#[unsafe(no_mangle)]
844pub unsafe extern "C" fn asdf_value_is_scalar(value: *mut AsdfValue) -> bool {
845 guard("asdf_value_is_scalar", false, || value_is_scalar(value))
846}
847
848pub(crate) fn value_is_scalar(value: *mut AsdfValue) -> bool {
854 value_document(value)
855 .zip(value_node(value))
856 .is_some_and(|(doc, node)| doc.resolved(node).is_scalar())
857}
858
859#[unsafe(no_mangle)]
864pub unsafe extern "C" fn asdf_value_as_scalar0(
865 value: *mut AsdfValue,
866 out: *mut *const c_char,
867) -> AsdfValueErr {
868 guard("asdf_value_as_scalar0", AsdfValueErr::Unknown, || {
869 if value.is_null() {
871 return AsdfValueErr::Unknown;
872 }
873 if !value_is_scalar(value) {
874 return AsdfValueErr::TypeMismatch;
875 }
876 intern_scalar(value, out)
877 })
878}
879
880fn intern_scalar(value: *mut AsdfValue, out: *mut *const c_char) -> AsdfValueErr {
882 let (Some(doc), Some(node), Some(file)) =
883 (value_document(value), value_node(value), value_file(value))
884 else {
885 return AsdfValueErr::Unknown;
886 };
887 let Some(text) = doc.resolved(node).as_str() else {
888 return AsdfValueErr::TypeMismatch;
889 };
890 let ptr = unsafe { &*file }.intern(text);
891 if ptr.is_null() {
892 return AsdfValueErr::Oom;
893 }
894 if !out.is_null() {
895 unsafe { write_out(out, ptr) };
896 }
897 AsdfValueErr::Ok
898}
899
900#[repr(C)]
907struct ContainerIter {
908 public: asdf_container_iter_t,
910 file: *mut AsdfFile,
911 entries: Vec<(Option<String>, NodeId, c_int)>,
915 position: usize,
916 current_key: Option<CString>,
917 current_value: *mut AsdfValue,
918 is_mapping: bool,
919}
920
921fn container_iter_init(container: *mut AsdfValue, reverse: bool) -> *mut asdf_container_iter_t {
922 let (Some(doc), Some(node), Some(file)) =
923 (value_document(container), value_node(container), value_file(container))
924 else {
925 return core::ptr::null_mut();
926 };
927
928 let resolved = doc.resolved(node);
929 let is_mapping = resolved.is_mapping();
930
931 let mut entries: Vec<(Option<String>, NodeId)> = if is_mapping {
932 doc.mapping_entries(node)
933 .unwrap_or(&[])
934 .iter()
935 .map(|e| (doc.resolved(e.key).as_str().map(str::to_string), e.value))
936 .collect()
937 } else if resolved.is_sequence() {
938 doc.sequence_items(node).unwrap_or(&[]).iter().map(|n| (None, *n)).collect()
939 } else {
940 return core::ptr::null_mut();
941 };
942
943 let mut numbered: Vec<(Option<String>, NodeId, c_int)> = entries
944 .drain(..)
945 .enumerate()
946 .map(|(index, (key, node))| (key, node, c_int::try_from(index).unwrap_or(c_int::MAX)))
947 .collect();
948 if reverse {
949 numbered.reverse();
950 }
951
952 let iter = Box::new(ContainerIter {
953 public: asdf_container_iter_t {
954 key: core::ptr::null(),
955 index: -1,
956 value: core::ptr::null_mut(),
957 },
958 file,
959 entries: numbered,
960 position: 0,
961 current_key: None,
962 current_value: core::ptr::null_mut(),
963 is_mapping,
964 });
965 Box::into_raw(iter).cast::<asdf_container_iter_t>()
966}
967
968#[unsafe(no_mangle)]
973pub unsafe extern "C" fn asdf_container_iter_init(
974 container: *mut AsdfValue,
975) -> *mut asdf_container_iter_t {
976 guard("asdf_container_iter_init", core::ptr::null_mut(), || {
977 container_iter_init(container, false)
978 })
979}
980
981#[unsafe(no_mangle)]
986pub unsafe extern "C" fn asdf_container_reverse_iter_init(
987 container: *mut AsdfValue,
988) -> *mut asdf_container_iter_t {
989 guard("asdf_container_reverse_iter_init", core::ptr::null_mut(), || {
990 container_iter_init(container, true)
991 })
992}
993
994#[unsafe(no_mangle)]
1001pub unsafe extern "C" fn asdf_container_iter_next(
1002 iter_ptr: *mut *mut asdf_container_iter_t,
1003) -> bool {
1004 guard("asdf_container_iter_next", false, || {
1005 if iter_ptr.is_null() {
1006 return false;
1007 }
1008 let raw = unsafe { *iter_ptr };
1009 if raw.is_null() {
1010 return false;
1011 }
1012 let iter = unsafe { &mut *raw.cast::<ContainerIter>() };
1013
1014 if !iter.current_value.is_null() {
1015 drop(unsafe { Box::from_raw(iter.current_value) });
1016 iter.current_value = core::ptr::null_mut();
1017 }
1018
1019 if iter.position >= iter.entries.len() {
1020 container_iter_destroy(raw);
1021 unsafe { write_out(iter_ptr, core::ptr::null_mut()) };
1022 return false;
1023 }
1024
1025 let (key, node, index) = iter.entries[iter.position].clone();
1026 iter.position += 1;
1027
1028 if iter.is_mapping {
1032 iter.current_key = key.and_then(|k| CString::new(k).ok());
1033 iter.public.key = iter.current_key.as_ref().map_or(core::ptr::null(), |k| k.as_ptr());
1034 } else {
1035 iter.current_key = None;
1036 iter.public.key = core::ptr::null();
1037 }
1038 iter.public.index = index;
1039
1040 iter.current_value = make_value(iter.file, node);
1041 iter.public.value = iter.current_value.cast();
1042 true
1043 })
1044}
1045
1046#[unsafe(no_mangle)]
1051pub unsafe extern "C" fn asdf_container_iter_destroy(iter: *mut asdf_container_iter_t) {
1052 guard("asdf_container_iter_destroy", (), || container_iter_destroy(iter))
1053}
1054
1055pub(crate) fn container_iter_destroy(iter: *mut asdf_container_iter_t) {
1061 if iter.is_null() {
1062 return;
1063 }
1064 let mut boxed = unsafe { Box::from_raw(iter.cast::<ContainerIter>()) };
1065 if !boxed.current_value.is_null() {
1066 drop(unsafe { Box::from_raw(boxed.current_value) });
1067 boxed.current_value = core::ptr::null_mut();
1068 }
1069}
1070
1071fn add_node(
1075 file: *mut AsdfFile,
1076 make: impl FnOnce(&mut asdf_core::yaml::Document) -> NodeId,
1077) -> *mut AsdfValue {
1078 if file.is_null() {
1079 return core::ptr::null_mut();
1080 }
1081 let Some(doc) = file_document_mut(file) else {
1082 return core::ptr::null_mut();
1083 };
1084 let node = make(doc);
1085 make_value(file, node)
1086}
1087
1088macro_rules! value_of {
1090 ($name:ident, $ty:ty) => {
1091 #[unsafe(no_mangle)]
1097 pub unsafe extern "C" fn $name(file: *mut AsdfFile, value: $ty) -> *mut AsdfValue {
1098 guard(stringify!($name), core::ptr::null_mut(), || {
1099 add_node(file, |doc| doc.add_scalar(value.to_string()))
1100 })
1101 }
1102 };
1103}
1104
1105value_of!(asdf_value_of_int8, i8);
1106value_of!(asdf_value_of_int16, i16);
1107value_of!(asdf_value_of_int32, i32);
1108value_of!(asdf_value_of_int64, i64);
1109value_of!(asdf_value_of_uint8, u8);
1110value_of!(asdf_value_of_uint16, u16);
1111value_of!(asdf_value_of_uint32, u32);
1112value_of!(asdf_value_of_uint64, u64);
1113
1114#[unsafe(no_mangle)]
1119pub unsafe extern "C" fn asdf_value_of_double(file: *mut AsdfFile, value: f64) -> *mut AsdfValue {
1120 guard("asdf_value_of_double", core::ptr::null_mut(), || {
1121 add_node(file, |doc| doc.add_scalar(asdf_core::core::elements::format_float(value)))
1122 })
1123}
1124
1125#[unsafe(no_mangle)]
1130pub unsafe extern "C" fn asdf_value_of_float(file: *mut AsdfFile, value: f32) -> *mut AsdfValue {
1131 guard("asdf_value_of_float", core::ptr::null_mut(), || {
1132 add_node(file, |doc| {
1133 doc.add_scalar(asdf_core::core::elements::format_float(f64::from(value)))
1134 })
1135 })
1136}
1137
1138#[unsafe(no_mangle)]
1143pub unsafe extern "C" fn asdf_value_of_bool(file: *mut AsdfFile, value: bool) -> *mut AsdfValue {
1144 guard("asdf_value_of_bool", core::ptr::null_mut(), || {
1145 add_node(file, |doc| doc.add_scalar(if value { "true" } else { "false" }))
1146 })
1147}
1148
1149#[unsafe(no_mangle)]
1154pub unsafe extern "C" fn asdf_value_of_null(file: *mut AsdfFile) -> *mut AsdfValue {
1155 guard("asdf_value_of_null", core::ptr::null_mut(), || value_of_null(file))
1156}
1157
1158pub(crate) fn value_of_null(file: *mut AsdfFile) -> *mut AsdfValue {
1164 add_node(file, |doc| doc.add_scalar("null"))
1165}
1166
1167#[unsafe(no_mangle)]
1175pub unsafe extern "C" fn asdf_value_of_string0(
1176 file: *mut AsdfFile,
1177 value: *const c_char,
1178) -> *mut AsdfValue {
1179 guard("asdf_value_of_string0", core::ptr::null_mut(), || value_of_string0(file, value))
1180}
1181
1182pub(crate) fn value_of_string0(file: *mut AsdfFile, value: *const c_char) -> *mut AsdfValue {
1188 if value.is_null() {
1189 return core::ptr::null_mut();
1190 }
1191 let text = unsafe { CStr::from_ptr(value) }.to_string_lossy().into_owned();
1192 add_node(file, |doc| {
1193 let style = match resolve(&text, ScalarStyle::Plain, Schema::Libasdf) {
1194 Resolved::String => ScalarStyle::Plain,
1195 _ => ScalarStyle::SingleQuoted,
1196 };
1197 doc.add_scalar_styled(text, style)
1198 })
1199}
1200
1201#[unsafe(no_mangle)]
1206pub unsafe extern "C" fn asdf_value_of_string(
1207 file: *mut AsdfFile,
1208 value: *const c_char,
1209 len: usize,
1210) -> *mut AsdfValue {
1211 guard("asdf_value_of_string", core::ptr::null_mut(), || value_of_string(file, value, len))
1212}
1213
1214pub(crate) fn value_of_string(
1220 file: *mut AsdfFile,
1221 value: *const c_char,
1222 len: usize,
1223) -> *mut AsdfValue {
1224 if value.is_null() {
1225 return core::ptr::null_mut();
1226 }
1227 let bytes = unsafe { core::slice::from_raw_parts(value.cast::<u8>(), len) };
1228 let text = String::from_utf8_lossy(bytes).into_owned();
1229 add_node(file, |doc| {
1230 let style = match resolve(&text, ScalarStyle::Plain, Schema::Libasdf) {
1231 Resolved::String => ScalarStyle::Plain,
1232 _ => ScalarStyle::SingleQuoted,
1233 };
1234 doc.add_scalar_styled(text, style)
1235 })
1236}
1237
1238#[unsafe(no_mangle)]
1244pub unsafe extern "C" fn asdf_mapping_create(file: *mut AsdfFile) -> *mut AsdfMapping {
1245 guard("asdf_mapping_create", core::ptr::null_mut(), || {
1246 add_node(file, |doc| doc.add(asdf_core::yaml::Node::mapping()))
1247 })
1248}
1249
1250#[unsafe(no_mangle)]
1256pub unsafe extern "C" fn asdf_sequence_create(file: *mut AsdfFile) -> *mut AsdfSequence {
1257 guard("asdf_sequence_create", core::ptr::null_mut(), || sequence_create(file))
1258}
1259
1260pub(crate) fn sequence_create(file: *mut AsdfFile) -> *mut AsdfSequence {
1266 add_node(file, |doc| doc.add(asdf_core::yaml::Node::sequence()))
1267}
1268
1269#[unsafe(no_mangle)]
1274pub unsafe extern "C" fn asdf_mapping_destroy(mapping: *mut AsdfMapping) {
1275 unsafe { crate::file_ffi::asdf_value_destroy(mapping) }
1276}
1277
1278#[unsafe(no_mangle)]
1283pub unsafe extern "C" fn asdf_sequence_destroy(sequence: *mut AsdfSequence) {
1284 unsafe { crate::file_ffi::asdf_value_destroy(sequence) }
1285}
1286
1287#[unsafe(no_mangle)]
1292pub unsafe extern "C" fn asdf_mapping_set_style(
1293 mapping: *mut AsdfMapping,
1294 style: crate::types::AsdfYamlNodeStyle,
1295) {
1296 guard("asdf_mapping_set_style", (), || set_collection_style(mapping, style))
1297}
1298
1299#[unsafe(no_mangle)]
1304pub unsafe extern "C" fn asdf_sequence_set_style(
1305 sequence: *mut AsdfSequence,
1306 style: crate::types::AsdfYamlNodeStyle,
1307) {
1308 guard("asdf_sequence_set_style", (), || set_collection_style(sequence, style))
1309}
1310
1311fn set_collection_style(value: *mut AsdfValue, style: crate::types::AsdfYamlNodeStyle) {
1312 use crate::types::AsdfYamlNodeStyle;
1313 use asdf_core::yaml::CollectionStyle;
1314
1315 let Some(file) = value_file(value) else { return };
1316 let Some(node) = value_node(value) else { return };
1317 let Some(doc) = file_document_mut(file) else { return };
1318
1319 let target = doc.resolve(node);
1320 let wanted = match style {
1321 AsdfYamlNodeStyle::Auto => CollectionStyle::Auto,
1322 AsdfYamlNodeStyle::Flow => CollectionStyle::Flow,
1323 AsdfYamlNodeStyle::Block => CollectionStyle::Block,
1324 };
1325 match &mut doc.node_mut(target).data {
1326 NodeData::Mapping { style, .. } | NodeData::Sequence { style, .. } => *style = wanted,
1327 _ => {}
1328 }
1329}
1330
1331fn consume_inserted(err: AsdfValueErr, value: *mut AsdfValue) -> AsdfValueErr {
1344 if err == AsdfValueErr::Ok {
1345 unsafe { crate::file_ffi::asdf_value_destroy(value) };
1346 }
1347 err
1348}
1349
1350#[unsafe(no_mangle)]
1358pub unsafe extern "C" fn asdf_mapping_set(
1359 mapping: *mut AsdfMapping,
1360 key: *const c_char,
1361 value: *mut AsdfValue,
1362) -> AsdfValueErr {
1363 guard("asdf_mapping_set", AsdfValueErr::Unknown, || {
1364 consume_inserted(mapping_set(mapping, key, value), value)
1365 })
1366}
1367
1368pub(crate) fn mapping_set(
1374 mapping: *mut AsdfMapping,
1375 key: *const c_char,
1376 value: *mut AsdfValue,
1377) -> AsdfValueErr {
1378 if key.is_null() {
1379 return AsdfValueErr::Unknown;
1380 }
1381 let (Some(file), Some(target)) = (value_file(mapping), value_node(mapping)) else {
1382 return AsdfValueErr::Unknown;
1383 };
1384 let Some(child) = value_node(value) else {
1385 return AsdfValueErr::Unknown;
1386 };
1387 let key = unsafe { CStr::from_ptr(key) }.to_string_lossy().into_owned();
1388
1389 let Some(doc) = file_document_mut(file) else {
1390 return AsdfValueErr::Unknown;
1391 };
1392 if !doc.resolved(target).is_mapping() {
1393 return AsdfValueErr::TypeMismatch;
1394 }
1395 doc.mapping_set(target, &key, child);
1396 AsdfValueErr::Ok
1397}
1398
1399#[unsafe(no_mangle)]
1405pub unsafe extern "C" fn asdf_mapping_pop(
1406 mapping: *mut AsdfMapping,
1407 key: *const c_char,
1408) -> *mut AsdfValue {
1409 guard("asdf_mapping_pop", core::ptr::null_mut(), || {
1410 if key.is_null() {
1411 return core::ptr::null_mut();
1412 }
1413 let (Some(file), Some(target)) = (value_file(mapping), value_node(mapping)) else {
1414 return core::ptr::null_mut();
1415 };
1416 let key = unsafe { CStr::from_ptr(key) }.to_string_lossy().into_owned();
1417
1418 let Some(doc) = file_document_mut(file) else {
1419 return core::ptr::null_mut();
1420 };
1421 match doc.mapping_remove(target, &key) {
1422 Some(node) => make_value(file, node),
1423 None => core::ptr::null_mut(),
1424 }
1425 })
1426}
1427
1428#[unsafe(no_mangle)]
1433pub unsafe extern "C" fn asdf_sequence_append(
1434 sequence: *mut AsdfSequence,
1435 value: *mut AsdfValue,
1436) -> AsdfValueErr {
1437 guard("asdf_sequence_append", AsdfValueErr::Unknown, || {
1438 consume_inserted(sequence_append(sequence, value), value)
1439 })
1440}
1441
1442pub(crate) fn sequence_append(sequence: *mut AsdfSequence, value: *mut AsdfValue) -> AsdfValueErr {
1448 let (Some(file), Some(target)) = (value_file(sequence), value_node(sequence)) else {
1449 return AsdfValueErr::Unknown;
1450 };
1451 let Some(child) = value_node(value) else {
1452 return AsdfValueErr::Unknown;
1453 };
1454 let Some(doc) = file_document_mut(file) else {
1455 return AsdfValueErr::Unknown;
1456 };
1457
1458 let resolved = doc.resolve(target);
1459 if !doc.node(resolved).is_sequence() {
1460 return AsdfValueErr::TypeMismatch;
1461 }
1462 match &mut doc.node_mut(resolved).data {
1463 NodeData::Sequence { items, .. } => {
1464 items.push(child);
1465 AsdfValueErr::Ok
1466 }
1467 _ => AsdfValueErr::TypeMismatch,
1468 }
1469}
1470
1471#[unsafe(no_mangle)]
1477pub unsafe extern "C" fn asdf_sequence_pop(
1478 sequence: *mut AsdfSequence,
1479 index: c_int,
1480) -> *mut AsdfValue {
1481 guard("asdf_sequence_pop", core::ptr::null_mut(), || {
1482 let (Some(file), Some(target)) = (value_file(sequence), value_node(sequence)) else {
1483 return core::ptr::null_mut();
1484 };
1485 let Some(doc) = file_document_mut(file) else {
1486 return core::ptr::null_mut();
1487 };
1488 match doc.sequence_remove(target, i64::from(index)) {
1489 Some(node) => make_value(file, node),
1490 None => core::ptr::null_mut(),
1491 }
1492 })
1493}
1494
1495macro_rules! container_setters {
1504 ($set:ident, $append:ident, $of:ident, $ctor:ident, $ty:ty) => {
1505 #[unsafe(no_mangle)]
1510 pub unsafe extern "C" fn $set(
1511 mapping: *mut AsdfMapping,
1512 key: *const c_char,
1513 value: $ty,
1514 ) -> AsdfValueErr {
1515 guard(stringify!($set), AsdfValueErr::Unknown, || {
1516 let Some(file) = value_file(mapping) else {
1517 return AsdfValueErr::Unknown;
1518 };
1519 let node = unsafe { $ctor(file, value) };
1520 if node.is_null() {
1521 return AsdfValueErr::Unknown;
1522 }
1523 let result = mapping_set(mapping, key, node);
1524 unsafe { crate::file_ffi::asdf_value_destroy(node) };
1525 result
1526 })
1527 }
1528
1529 #[unsafe(no_mangle)]
1534 pub unsafe extern "C" fn $append(sequence: *mut AsdfSequence, value: $ty) -> AsdfValueErr {
1535 guard(stringify!($append), AsdfValueErr::Unknown, || {
1536 let Some(file) = value_file(sequence) else {
1537 return AsdfValueErr::Unknown;
1538 };
1539 let node = unsafe { $ctor(file, value) };
1540 if node.is_null() {
1541 return AsdfValueErr::Unknown;
1542 }
1543 let result = sequence_append(sequence, node);
1544 unsafe { crate::file_ffi::asdf_value_destroy(node) };
1545 result
1546 })
1547 }
1548
1549 #[unsafe(no_mangle)]
1556 pub unsafe extern "C" fn $of(
1557 file: *mut AsdfFile,
1558 arr: *const $ty,
1559 size: c_int,
1560 ) -> *mut AsdfSequence {
1561 guard(stringify!($of), core::ptr::null_mut(), || {
1562 if arr.is_null() || size < 0 {
1563 return core::ptr::null_mut();
1564 }
1565 let sequence = sequence_create(file);
1566 if sequence.is_null() {
1567 return core::ptr::null_mut();
1568 }
1569 let items = unsafe { core::slice::from_raw_parts(arr, size as usize) };
1570 for value in items {
1571 if unsafe { $append(sequence, *value) } != AsdfValueErr::Ok {
1572 unsafe { asdf_sequence_destroy(sequence) };
1573 return core::ptr::null_mut();
1574 }
1575 }
1576 sequence
1577 })
1578 }
1579 };
1580}
1581
1582container_setters!(
1583 asdf_mapping_set_int8,
1584 asdf_sequence_append_int8,
1585 asdf_sequence_of_int8,
1586 asdf_value_of_int8,
1587 i8
1588);
1589container_setters!(
1590 asdf_mapping_set_int16,
1591 asdf_sequence_append_int16,
1592 asdf_sequence_of_int16,
1593 asdf_value_of_int16,
1594 i16
1595);
1596container_setters!(
1597 asdf_mapping_set_int32,
1598 asdf_sequence_append_int32,
1599 asdf_sequence_of_int32,
1600 asdf_value_of_int32,
1601 i32
1602);
1603container_setters!(
1604 asdf_mapping_set_int64,
1605 asdf_sequence_append_int64,
1606 asdf_sequence_of_int64,
1607 asdf_value_of_int64,
1608 i64
1609);
1610container_setters!(
1611 asdf_mapping_set_uint8,
1612 asdf_sequence_append_uint8,
1613 asdf_sequence_of_uint8,
1614 asdf_value_of_uint8,
1615 u8
1616);
1617container_setters!(
1618 asdf_mapping_set_uint16,
1619 asdf_sequence_append_uint16,
1620 asdf_sequence_of_uint16,
1621 asdf_value_of_uint16,
1622 u16
1623);
1624container_setters!(
1625 asdf_mapping_set_uint32,
1626 asdf_sequence_append_uint32,
1627 asdf_sequence_of_uint32,
1628 asdf_value_of_uint32,
1629 u32
1630);
1631container_setters!(
1632 asdf_mapping_set_uint64,
1633 asdf_sequence_append_uint64,
1634 asdf_sequence_of_uint64,
1635 asdf_value_of_uint64,
1636 u64
1637);
1638container_setters!(
1639 asdf_mapping_set_float,
1640 asdf_sequence_append_float,
1641 asdf_sequence_of_float,
1642 asdf_value_of_float,
1643 f32
1644);
1645container_setters!(
1646 asdf_mapping_set_double,
1647 asdf_sequence_append_double,
1648 asdf_sequence_of_double,
1649 asdf_value_of_double,
1650 f64
1651);
1652container_setters!(
1653 asdf_mapping_set_bool,
1654 asdf_sequence_append_bool,
1655 asdf_sequence_of_bool,
1656 asdf_value_of_bool,
1657 bool
1658);
1659
1660#[unsafe(no_mangle)]
1665pub unsafe extern "C" fn asdf_mapping_set_string0(
1666 mapping: *mut AsdfMapping,
1667 key: *const c_char,
1668 value: *const c_char,
1669) -> AsdfValueErr {
1670 guard("asdf_mapping_set_string0", AsdfValueErr::Unknown, || {
1671 let Some(file) = value_file(mapping) else {
1672 return AsdfValueErr::Unknown;
1673 };
1674 let node = value_of_string0(file, value);
1675 if node.is_null() {
1676 return AsdfValueErr::Unknown;
1677 }
1678 let result = mapping_set(mapping, key, node);
1679 unsafe { crate::file_ffi::asdf_value_destroy(node) };
1680 result
1681 })
1682}
1683
1684#[unsafe(no_mangle)]
1689pub unsafe extern "C" fn asdf_mapping_set_string(
1690 mapping: *mut AsdfMapping,
1691 key: *const c_char,
1692 value: *const c_char,
1693 len: usize,
1694) -> AsdfValueErr {
1695 guard("asdf_mapping_set_string", AsdfValueErr::Unknown, || {
1696 let Some(file) = value_file(mapping) else {
1697 return AsdfValueErr::Unknown;
1698 };
1699 let node = value_of_string(file, value, len);
1700 if node.is_null() {
1701 return AsdfValueErr::Unknown;
1702 }
1703 let result = mapping_set(mapping, key, node);
1704 unsafe { crate::file_ffi::asdf_value_destroy(node) };
1705 result
1706 })
1707}
1708
1709#[unsafe(no_mangle)]
1714pub unsafe extern "C" fn asdf_mapping_set_null(
1715 mapping: *mut AsdfMapping,
1716 key: *const c_char,
1717) -> AsdfValueErr {
1718 guard("asdf_mapping_set_null", AsdfValueErr::Unknown, || {
1719 let Some(file) = value_file(mapping) else {
1720 return AsdfValueErr::Unknown;
1721 };
1722 let node = value_of_null(file);
1723 if node.is_null() {
1724 return AsdfValueErr::Unknown;
1725 }
1726 let result = mapping_set(mapping, key, node);
1727 unsafe { crate::file_ffi::asdf_value_destroy(node) };
1728 result
1729 })
1730}
1731
1732#[unsafe(no_mangle)]
1737pub unsafe extern "C" fn asdf_mapping_set_mapping(
1738 mapping: *mut AsdfMapping,
1739 key: *const c_char,
1740 value: *mut AsdfMapping,
1741) -> AsdfValueErr {
1742 consume_inserted(mapping_set(mapping, key, value), value)
1743}
1744
1745#[unsafe(no_mangle)]
1750pub unsafe extern "C" fn asdf_mapping_set_sequence(
1751 mapping: *mut AsdfMapping,
1752 key: *const c_char,
1753 value: *mut AsdfSequence,
1754) -> AsdfValueErr {
1755 consume_inserted(mapping_set(mapping, key, value), value)
1756}
1757
1758#[unsafe(no_mangle)]
1763pub unsafe extern "C" fn asdf_sequence_append_string0(
1764 sequence: *mut AsdfSequence,
1765 value: *const c_char,
1766) -> AsdfValueErr {
1767 guard("asdf_sequence_append_string0", AsdfValueErr::Unknown, || {
1768 sequence_append_string0(sequence, value)
1769 })
1770}
1771
1772pub(crate) fn sequence_append_string0(
1778 sequence: *mut AsdfSequence,
1779 value: *const c_char,
1780) -> AsdfValueErr {
1781 let Some(file) = value_file(sequence) else {
1782 return AsdfValueErr::Unknown;
1783 };
1784 let node = value_of_string0(file, value);
1785 if node.is_null() {
1786 return AsdfValueErr::Unknown;
1787 }
1788 let result = sequence_append(sequence, node);
1789 unsafe { crate::file_ffi::asdf_value_destroy(node) };
1790 result
1791}
1792
1793#[unsafe(no_mangle)]
1798pub unsafe extern "C" fn asdf_sequence_append_string(
1799 sequence: *mut AsdfSequence,
1800 value: *const c_char,
1801 len: usize,
1802) -> AsdfValueErr {
1803 guard("asdf_sequence_append_string", AsdfValueErr::Unknown, || {
1804 sequence_append_string(sequence, value, len)
1805 })
1806}
1807
1808pub(crate) fn sequence_append_string(
1814 sequence: *mut AsdfSequence,
1815 value: *const c_char,
1816 len: usize,
1817) -> AsdfValueErr {
1818 let Some(file) = value_file(sequence) else {
1819 return AsdfValueErr::Unknown;
1820 };
1821 let node = value_of_string(file, value, len);
1822 if node.is_null() {
1823 return AsdfValueErr::Unknown;
1824 }
1825 let result = sequence_append(sequence, node);
1826 unsafe { crate::file_ffi::asdf_value_destroy(node) };
1827 result
1828}
1829
1830#[unsafe(no_mangle)]
1835pub unsafe extern "C" fn asdf_sequence_append_null(sequence: *mut AsdfSequence) -> AsdfValueErr {
1836 guard("asdf_sequence_append_null", AsdfValueErr::Unknown, || sequence_append_null(sequence))
1837}
1838
1839pub(crate) fn sequence_append_null(sequence: *mut AsdfSequence) -> AsdfValueErr {
1845 let Some(file) = value_file(sequence) else {
1846 return AsdfValueErr::Unknown;
1847 };
1848 let node = value_of_null(file);
1849 if node.is_null() {
1850 return AsdfValueErr::Unknown;
1851 }
1852 let result = sequence_append(sequence, node);
1853 unsafe { crate::file_ffi::asdf_value_destroy(node) };
1854 result
1855}
1856
1857#[unsafe(no_mangle)]
1862pub unsafe extern "C" fn asdf_sequence_append_mapping(
1863 sequence: *mut AsdfSequence,
1864 value: *mut AsdfMapping,
1865) -> AsdfValueErr {
1866 consume_inserted(sequence_append(sequence, value), value)
1867}
1868
1869#[unsafe(no_mangle)]
1874pub unsafe extern "C" fn asdf_sequence_append_sequence(
1875 sequence: *mut AsdfSequence,
1876 value: *mut AsdfSequence,
1877) -> AsdfValueErr {
1878 consume_inserted(sequence_append(sequence, value), value)
1879}
1880
1881#[unsafe(no_mangle)]
1886pub unsafe extern "C" fn asdf_sequence_of_null(
1887 file: *mut AsdfFile,
1888 size: c_int,
1889) -> *mut AsdfSequence {
1890 guard("asdf_sequence_of_null", core::ptr::null_mut(), || {
1891 if size < 0 {
1892 return core::ptr::null_mut();
1893 }
1894 let sequence = sequence_create(file);
1895 if sequence.is_null() {
1896 return core::ptr::null_mut();
1897 }
1898 for _ in 0..size {
1899 if sequence_append_null(sequence) != AsdfValueErr::Ok {
1900 unsafe { asdf_sequence_destroy(sequence) };
1901 return core::ptr::null_mut();
1902 }
1903 }
1904 sequence
1905 })
1906}
1907
1908#[unsafe(no_mangle)]
1913pub unsafe extern "C" fn asdf_sequence_of_string0(
1914 file: *mut AsdfFile,
1915 arr: *const *const c_char,
1916 size: c_int,
1917) -> *mut AsdfSequence {
1918 guard("asdf_sequence_of_string0", core::ptr::null_mut(), || {
1919 if arr.is_null() || size < 0 {
1920 return core::ptr::null_mut();
1921 }
1922 let sequence = sequence_create(file);
1923 if sequence.is_null() {
1924 return core::ptr::null_mut();
1925 }
1926 for index in 0..size as isize {
1927 let text = unsafe { *arr.offset(index) };
1928 if sequence_append_string0(sequence, text) != AsdfValueErr::Ok {
1929 unsafe { asdf_sequence_destroy(sequence) };
1930 return core::ptr::null_mut();
1931 }
1932 }
1933 sequence
1934 })
1935}
1936
1937#[unsafe(no_mangle)]
1942pub unsafe extern "C" fn asdf_sequence_of_string(
1943 file: *mut AsdfFile,
1944 arr: *const *const c_char,
1945 lens: *const usize,
1946 size: c_int,
1947) -> *mut AsdfSequence {
1948 guard("asdf_sequence_of_string", core::ptr::null_mut(), || {
1949 if arr.is_null() || lens.is_null() || size < 0 {
1950 return core::ptr::null_mut();
1951 }
1952 let sequence = sequence_create(file);
1953 if sequence.is_null() {
1954 return core::ptr::null_mut();
1955 }
1956 for index in 0..size as isize {
1957 let text = unsafe { *arr.offset(index) };
1958 let len = unsafe { *lens.offset(index) };
1959 if sequence_append_string(sequence, text, len) != AsdfValueErr::Ok {
1960 unsafe { asdf_sequence_destroy(sequence) };
1961 return core::ptr::null_mut();
1962 }
1963 }
1964 sequence
1965 })
1966}
1967
1968#[unsafe(no_mangle)]
1976pub unsafe extern "C" fn asdf_mapping_copy(mapping: *mut AsdfMapping) -> *mut AsdfMapping {
1977 guard("asdf_mapping_copy", core::ptr::null_mut(), || {
1978 let (Some(file), Some(source)) = (value_file(mapping), value_node(mapping)) else {
1979 return core::ptr::null_mut();
1980 };
1981 let Some(doc) = file_document_mut(file) else {
1982 return core::ptr::null_mut();
1983 };
1984 let Some(entries) = doc.mapping_entries(source).map(<[_]>::to_vec) else {
1985 return core::ptr::null_mut();
1986 };
1987 let pairs: Vec<_> = entries.iter().map(|e| (e.key, e.value)).collect();
1988 let fresh = doc.add_mapping(pairs);
1989 make_value(file, fresh)
1990 })
1991}
1992
1993#[unsafe(no_mangle)]
2000pub unsafe extern "C" fn asdf_mapping_update(
2001 mapping: *mut AsdfMapping,
2002 update: *mut AsdfMapping,
2003) -> AsdfValueErr {
2004 guard("asdf_mapping_update", AsdfValueErr::Unknown, || {
2005 let (Some(file), Some(target)) = (value_file(mapping), value_node(mapping)) else {
2006 return AsdfValueErr::Unknown;
2007 };
2008 let Some(source) = value_node(update) else {
2009 return AsdfValueErr::Unknown;
2010 };
2011 let Some(doc) = file_document_mut(file) else {
2012 return AsdfValueErr::Unknown;
2013 };
2014 if !doc.resolved(target).is_mapping() || !doc.resolved(source).is_mapping() {
2015 return AsdfValueErr::TypeMismatch;
2016 }
2017
2018 let entries = doc.mapping_entries(source).map(<[_]>::to_vec).unwrap_or_default();
2019 for entry in entries {
2020 let Some(key) = doc.resolved(entry.key).as_str().map(str::to_string) else {
2021 continue;
2022 };
2023 doc.mapping_set(target, &key, entry.value);
2024 }
2025 AsdfValueErr::Ok
2026 })
2027}
2028
2029fn scalar_with_len(
2033 value: *mut AsdfValue,
2034 out: *mut *const c_char,
2035 out_len: *mut usize,
2036) -> AsdfValueErr {
2037 let (Some(doc), Some(node), Some(file)) =
2038 (value_document(value), value_node(value), value_file(value))
2039 else {
2040 return AsdfValueErr::Unknown;
2041 };
2042 let Some(text) = doc.resolved(node).as_str() else {
2043 return AsdfValueErr::TypeMismatch;
2044 };
2045 let ptr = unsafe { &*file }.intern(text);
2046 if ptr.is_null() {
2047 return AsdfValueErr::Oom;
2048 }
2049 if !out.is_null() {
2050 unsafe { write_out(out, ptr) };
2051 }
2052 if !out_len.is_null() {
2053 unsafe { write_out(out_len, text.len()) };
2054 }
2055 AsdfValueErr::Ok
2056}
2057
2058#[unsafe(no_mangle)]
2067pub unsafe extern "C" fn asdf_value_as_string(
2068 value: *mut AsdfValue,
2069 out: *mut *const c_char,
2070 out_len: *mut usize,
2071) -> AsdfValueErr {
2072 guard("asdf_value_as_string", AsdfValueErr::Unknown, || {
2073 if !matches!(resolved_of(value), Some(Resolved::String)) {
2074 return AsdfValueErr::TypeMismatch;
2075 }
2076 scalar_with_len(value, out, out_len)
2077 })
2078}
2079
2080#[unsafe(no_mangle)]
2085pub unsafe extern "C" fn asdf_value_as_scalar(
2086 value: *mut AsdfValue,
2087 out: *mut *const c_char,
2088 out_len: *mut usize,
2089) -> AsdfValueErr {
2090 guard("asdf_value_as_scalar", AsdfValueErr::Unknown, || {
2091 if value.is_null() {
2093 return AsdfValueErr::Unknown;
2094 }
2095 if !value_is_scalar(value) {
2096 return AsdfValueErr::TypeMismatch;
2097 }
2098 scalar_with_len(value, out, out_len)
2099 })
2100}
2101
2102#[unsafe(no_mangle)]
2112pub unsafe extern "C" fn asdf_value_as_type(
2113 value: *mut AsdfValue,
2114 value_type: c_int,
2115 out: *mut core::ffi::c_void,
2116) -> AsdfValueErr {
2117 guard("asdf_value_as_type", AsdfValueErr::Unknown, || unsafe {
2118 let Some(value_type) = AsdfValueType::from_i32(value_type) else {
2120 return AsdfValueErr::TypeMismatch;
2121 };
2122 if value_type == AsdfValueType::Unknown {
2125 if value.is_null() {
2126 return AsdfValueErr::Unknown;
2127 }
2128 let copy = asdf_value_copy(value);
2129 if copy.is_null() {
2130 return AsdfValueErr::Oom;
2131 }
2132 if out.is_null() {
2133 crate::file_ffi::asdf_value_destroy(copy);
2134 } else {
2135 *out.cast::<*mut AsdfValue>() = copy;
2136 }
2137 return AsdfValueErr::Ok;
2138 }
2139 match value_type {
2140 AsdfValueType::Int8 => asdf_value_as_int8(value, out.cast()),
2141 AsdfValueType::Int16 => asdf_value_as_int16(value, out.cast()),
2142 AsdfValueType::Int32 => asdf_value_as_int32(value, out.cast()),
2143 AsdfValueType::Int64 => asdf_value_as_int64(value, out.cast()),
2144 AsdfValueType::Uint8 => asdf_value_as_uint8(value, out.cast()),
2145 AsdfValueType::Uint16 => asdf_value_as_uint16(value, out.cast()),
2146 AsdfValueType::Uint32 => asdf_value_as_uint32(value, out.cast()),
2147 AsdfValueType::Uint64 => asdf_value_as_uint64(value, out.cast()),
2148 AsdfValueType::Float => asdf_value_as_float(value, out.cast()),
2149 AsdfValueType::Double => asdf_value_as_double(value, out.cast()),
2150 AsdfValueType::Bool => asdf_value_as_bool(value, out.cast()),
2151 AsdfValueType::String => asdf_value_as_string0(value, out.cast()),
2152 AsdfValueType::Scalar => asdf_value_as_scalar0(value, out.cast()),
2153 AsdfValueType::Mapping => asdf_value_as_mapping(value, out.cast()),
2154 AsdfValueType::Sequence => asdf_value_as_sequence(value, out.cast()),
2155 AsdfValueType::Null => {
2157 if asdf_value_is_null(value) {
2158 AsdfValueErr::Ok
2159 } else {
2160 AsdfValueErr::TypeMismatch
2161 }
2162 }
2163 AsdfValueType::Unknown | AsdfValueType::Extension => AsdfValueErr::TypeMismatch,
2164 }
2165 })
2166}
2167
2168#[unsafe(no_mangle)]
2176pub unsafe extern "C" fn asdf_value_of_mapping(mapping: *mut AsdfMapping) -> *mut AsdfValue {
2177 mapping
2178}
2179
2180#[unsafe(no_mangle)]
2185pub unsafe extern "C" fn asdf_value_of_sequence(sequence: *mut AsdfSequence) -> *mut AsdfValue {
2186 sequence
2187}
2188
2189#[unsafe(no_mangle)]
2198pub unsafe extern "C" fn asdf_value_path(value: *mut AsdfValue) -> *const c_char {
2199 guard("asdf_value_path", core::ptr::null(), || {
2200 let (Some(doc), Some(node), Some(file)) =
2201 (value_document(value), value_node(value), value_file(value))
2202 else {
2203 return core::ptr::null();
2204 };
2205 match doc.path_of(node) {
2206 Some(path) => unsafe { &*file }.intern(&path),
2207 None => core::ptr::null(),
2208 }
2209 })
2210}
2211
2212#[unsafe(no_mangle)]
2218pub unsafe extern "C" fn asdf_value_parent(value: *mut AsdfValue) -> *mut AsdfValue {
2219 guard("asdf_value_parent", core::ptr::null_mut(), || {
2220 let (Some(doc), Some(node), Some(file)) =
2221 (value_document(value), value_node(value), value_file(value))
2222 else {
2223 return core::ptr::null_mut();
2224 };
2225 match doc.parent_of(node) {
2226 Some(parent) => make_value(file, parent),
2227 None => core::ptr::null_mut(),
2228 }
2229 })
2230}
2231
2232pub type AsdfValuePred = Option<unsafe extern "C" fn(*mut AsdfValue) -> bool>;
2236
2237#[repr(C)]
2239struct FindIter {
2240 public: crate::types::asdf_find_iter_t,
2242 file: *mut AsdfFile,
2243 queue: alloc::collections::VecDeque<(NodeId, i64)>,
2245 pred: AsdfValuePred,
2246 descend_pred: AsdfValuePred,
2247 depth_first: bool,
2248 max_depth: i64,
2249 seen: Vec<NodeId>,
2251}
2252
2253impl FindIter {
2254 fn enqueue_children(&mut self, doc: &asdf_core::yaml::Document, node: NodeId, depth: i64) {
2256 if self.max_depth >= 0 && depth > self.max_depth {
2261 return;
2262 }
2263 let resolved = doc.resolve(node);
2264 let mut children: Vec<NodeId> = Vec::new();
2265 match &doc.node(resolved).data {
2266 NodeData::Mapping { entries, .. } => {
2267 children.extend(entries.iter().map(|e| e.value));
2268 }
2269 NodeData::Sequence { items, .. } => children.extend(items.iter().copied()),
2270 _ => return,
2271 }
2272 if self.depth_first {
2273 for child in children.into_iter().rev() {
2275 self.queue.push_front((child, depth + 1));
2276 }
2277 } else {
2278 for child in children {
2279 self.queue.push_back((child, depth + 1));
2280 }
2281 }
2282 }
2283
2284 fn should_descend(&self, node: NodeId, is_root: bool) -> bool {
2291 if is_root {
2292 return true;
2293 }
2294 let Some(pred) = self.descend_pred else {
2295 return true;
2296 };
2297 let handle = make_value(self.file, node);
2300 let verdict = unsafe { pred(handle) };
2301 unsafe { crate::file_ffi::asdf_value_destroy(handle) };
2302 verdict
2303 }
2304
2305 fn clear_current(&mut self) {
2307 if !self.public.value.is_null() {
2308 unsafe { crate::file_ffi::asdf_value_destroy(self.public.value.cast::<AsdfValue>()) };
2309 self.public.value = core::ptr::null_mut();
2310 }
2311 }
2312
2313 fn step(&mut self) -> bool {
2315 self.clear_current();
2316 let Some(doc) = crate::file_ffi::file_document(self.file) else {
2317 return false;
2318 };
2319 while let Some((node, depth)) = self.queue.pop_front() {
2320 let resolved = doc.resolve(node);
2321 if self.seen.contains(&resolved) {
2322 continue;
2323 }
2324 self.seen.push(resolved);
2325
2326 let is_container = doc.node(resolved).is_mapping() || doc.node(resolved).is_sequence();
2327 if is_container && self.should_descend(node, depth == 0) {
2328 self.enqueue_children(doc, node, depth);
2329 }
2330
2331 let matched = match self.pred {
2332 Some(pred) => {
2333 let handle = make_value(self.file, node);
2334 let verdict = unsafe { pred(handle) };
2335 if verdict {
2336 self.public.value = handle.cast();
2337 return true;
2338 }
2339 unsafe { crate::file_ffi::asdf_value_destroy(handle) };
2340 false
2341 }
2342 None => {
2345 self.public.value = make_value(self.file, node).cast();
2346 return true;
2347 }
2348 };
2349 let _ = matched;
2350 }
2351 false
2352 }
2353}
2354
2355fn find_iter_new(
2357 root: *mut AsdfValue,
2358 pred: AsdfValuePred,
2359 depth_first: bool,
2360 descend_pred: AsdfValuePred,
2361 max_depth: i64,
2362) -> *mut FindIter {
2363 let (Some(file), Some(node)) = (value_file(root), value_node(root)) else {
2364 return core::ptr::null_mut();
2365 };
2366 let mut queue = alloc::collections::VecDeque::new();
2367 queue.push_back((node, 0i64));
2368 Box::into_raw(Box::new(FindIter {
2369 public: crate::types::asdf_find_iter_t { value: core::ptr::null_mut() },
2370 file,
2371 queue,
2372 pred,
2373 descend_pred,
2374 depth_first,
2375 max_depth,
2376 seen: Vec::new(),
2377 }))
2378}
2379
2380#[unsafe(no_mangle)]
2386pub unsafe extern "C" fn asdf_value_find(
2387 root: *mut AsdfValue,
2388 pred: AsdfValuePred,
2389) -> *mut AsdfValue {
2390 value_find_ex(root, pred, false, None, -1)
2391}
2392
2393#[unsafe(no_mangle)]
2401pub unsafe extern "C" fn asdf_value_find_ex(
2402 root: *mut AsdfValue,
2403 pred: AsdfValuePred,
2404 depth_first: bool,
2405 descend_pred: AsdfValuePred,
2406 max_depth: i64,
2407) -> *mut AsdfValue {
2408 guard("asdf_value_find_ex", core::ptr::null_mut(), || {
2409 value_find_ex(root, pred, depth_first, descend_pred, max_depth)
2410 })
2411}
2412
2413pub(crate) fn value_find_ex(
2419 root: *mut AsdfValue,
2420 pred: AsdfValuePred,
2421 depth_first: bool,
2422 descend_pred: AsdfValuePred,
2423 max_depth: i64,
2424) -> *mut AsdfValue {
2425 let iter = find_iter_new(root, pred, depth_first, descend_pred, max_depth);
2426 if iter.is_null() {
2427 return core::ptr::null_mut();
2428 }
2429 let mut boxed = unsafe { Box::from_raw(iter) };
2430 if !boxed.step() {
2431 return core::ptr::null_mut();
2432 }
2433 let found = boxed.public.value.cast::<AsdfValue>();
2435 boxed.public.value = core::ptr::null_mut();
2436 found
2437}
2438
2439#[unsafe(no_mangle)]
2445pub unsafe extern "C" fn asdf_find_iter_init(
2446 root: *mut AsdfValue,
2447 pred: AsdfValuePred,
2448) -> *mut crate::types::asdf_find_iter_t {
2449 find_iter_init_ex(root, pred, false, None, -1)
2450}
2451
2452#[unsafe(no_mangle)]
2457pub unsafe extern "C" fn asdf_find_iter_init_ex(
2458 root: *mut AsdfValue,
2459 pred: AsdfValuePred,
2460 depth_first: bool,
2461 descend_pred: AsdfValuePred,
2462 max_depth: i64,
2463) -> *mut crate::types::asdf_find_iter_t {
2464 guard("asdf_find_iter_init_ex", core::ptr::null_mut(), || {
2465 find_iter_init_ex(root, pred, depth_first, descend_pred, max_depth)
2466 })
2467}
2468
2469pub(crate) fn find_iter_init_ex(
2475 root: *mut AsdfValue,
2476 pred: AsdfValuePred,
2477 depth_first: bool,
2478 descend_pred: AsdfValuePred,
2479 max_depth: i64,
2480) -> *mut crate::types::asdf_find_iter_t {
2481 find_iter_new(root, pred, depth_first, descend_pred, max_depth)
2482 .cast::<crate::types::asdf_find_iter_t>()
2483}
2484
2485#[unsafe(no_mangle)]
2493pub unsafe extern "C" fn asdf_value_find_iter_next(
2494 iter: *mut *mut crate::types::asdf_find_iter_t,
2495) -> bool {
2496 guard("asdf_value_find_iter_next", false, || {
2497 if iter.is_null() {
2498 return false;
2499 }
2500 let current = unsafe { *iter };
2501 if current.is_null() {
2502 return false;
2503 }
2504 let state = unsafe { &mut *current.cast::<FindIter>() };
2505 if state.step() {
2506 return true;
2507 }
2508 find_iter_destroy(current);
2509 unsafe { write_out(iter, core::ptr::null_mut()) };
2510 false
2511 })
2512}
2513
2514#[unsafe(no_mangle)]
2520pub unsafe extern "C" fn asdf_find_iter_destroy(iter: *mut crate::types::asdf_find_iter_t) {
2521 guard("asdf_find_iter_destroy", (), || find_iter_destroy(iter))
2522}
2523
2524pub(crate) fn find_iter_destroy(iter: *mut crate::types::asdf_find_iter_t) {
2530 if iter.is_null() {
2531 return;
2532 }
2533 let mut boxed = unsafe { Box::from_raw(iter.cast::<FindIter>()) };
2534 boxed.clear_current();
2535}
2536
2537#[cfg(test)]
2538mod tests {
2539 use super::*;
2540 use crate::file_ffi::{asdf_close, asdf_get_value, asdf_open_mem_ex, asdf_value_destroy};
2541
2542 fn sample() -> Vec<u8> {
2543 let mut buf = Vec::new();
2544 buf.extend_from_slice(b"#ASDF 1.0.0\n#ASDF_STANDARD 1.6.0\n");
2545 buf.extend_from_slice(b"%YAML 1.1\n%TAG ! tag:stsci.edu:asdf/\n--- !core/asdf-1.1.0\n");
2546 buf.extend_from_slice(
2547 b"a: 1\nb: two\nc: 3.5\nflag: true\nnothing: null\n\
2548 list: [10, 20, 30]\nnested:\n inner: deep\n",
2549 );
2550 buf.extend_from_slice(b"...\n");
2551 buf
2552 }
2553
2554 struct Handle(*mut AsdfFile);
2555 impl Drop for Handle {
2556 fn drop(&mut self) {
2557 unsafe { asdf_close(self.0) };
2558 }
2559 }
2560
2561 fn open() -> Handle {
2562 let bytes = sample();
2563 let f =
2564 unsafe { asdf_open_mem_ex(bytes.as_ptr().cast(), bytes.len(), core::ptr::null_mut()) };
2565 assert!(!f.is_null());
2566 Handle(f)
2567 }
2568
2569 fn value_at(h: &Handle, path: &str) -> *mut AsdfValue {
2570 let c = CString::new(path).unwrap();
2571 let v = unsafe { asdf_get_value(h.0, c.as_ptr()) };
2572 assert!(!v.is_null(), "no value at {path}");
2573 v
2574 }
2575
2576 unsafe extern "C" fn is_a_string(value: *mut AsdfValue) -> bool {
2578 unsafe { asdf_value_is_string(value) }
2579 }
2580
2581 unsafe extern "C" fn is_deep(value: *mut AsdfValue) -> bool {
2583 let mut out = core::ptr::null();
2584 if unsafe { asdf_value_as_string0(value, &mut out) } != AsdfValueErr::Ok {
2585 return false;
2586 }
2587 let text = unsafe { CStr::from_ptr(out) };
2588 text == c"deep"
2589 }
2590
2591 #[test]
2592 fn find_walks_breadth_first_by_default() {
2593 let h = open();
2594 let root = value_at(&h, "");
2595 let found = unsafe { asdf_value_find(root, Some(is_a_string)) };
2598 assert!(!found.is_null());
2599 let mut text = core::ptr::null();
2600 assert_eq!(unsafe { asdf_value_as_string0(found, &mut text) }, AsdfValueErr::Ok);
2601 assert_eq!(unsafe { CStr::from_ptr(text) }, c"two");
2602 unsafe { asdf_value_destroy(found) };
2603 unsafe { asdf_value_destroy(root) };
2604 }
2605
2606 #[test]
2609 fn find_respects_max_depth() {
2610 let h = open();
2611 let root = value_at(&h, "");
2612
2613 let shallow = unsafe { asdf_value_find_ex(root, Some(is_deep), false, None, 0) };
2616 assert!(shallow.is_null());
2617
2618 let found = unsafe { asdf_value_find_ex(root, Some(is_deep), false, None, 1) };
2620 assert!(!found.is_null());
2621 unsafe { asdf_value_destroy(found) };
2622
2623 let deep = unsafe { asdf_value_find_ex(root, Some(is_deep), false, None, -1) };
2624 assert!(!deep.is_null());
2625 unsafe { asdf_value_destroy(deep) };
2626 unsafe { asdf_value_destroy(root) };
2627 }
2628
2629 #[test]
2630 fn find_iterates_every_match() {
2631 let h = open();
2632 let root = value_at(&h, "");
2633
2634 let mut iter = unsafe { asdf_find_iter_init(root, Some(is_a_string)) };
2635 let mut seen = Vec::new();
2636 while unsafe { asdf_value_find_iter_next(&mut iter) } {
2637 let current = unsafe { &*iter }.value.cast::<AsdfValue>();
2638 let mut text = core::ptr::null();
2639 assert_eq!(unsafe { asdf_value_as_string0(current, &mut text) }, AsdfValueErr::Ok);
2640 seen.push(unsafe { CStr::from_ptr(text) }.to_string_lossy().into_owned());
2641 }
2642 assert!(iter.is_null());
2644
2645 assert_eq!(seen, vec!["two".to_string(), "deep".to_string()]);
2647 unsafe { asdf_value_destroy(root) };
2648 }
2649
2650 #[test]
2651 fn abandoning_a_find_iterator_is_safe() {
2652 let h = open();
2653 let root = value_at(&h, "");
2654 let mut iter = unsafe { asdf_find_iter_init(root, None) };
2655 assert!(unsafe { asdf_value_find_iter_next(&mut iter) });
2656 unsafe { asdf_find_iter_destroy(iter) };
2658 unsafe { asdf_value_destroy(root) };
2659 }
2660
2661 #[test]
2662 fn values_report_their_path_and_parent() {
2663 let h = open();
2664 let inner = value_at(&h, "nested/inner");
2665 let path = unsafe { asdf_value_path(inner) };
2667 assert!(!path.is_null());
2668 assert_eq!(unsafe { CStr::from_ptr(path) }, c"/nested/inner");
2669
2670 let parent = unsafe { asdf_value_parent(inner) };
2671 assert!(!parent.is_null());
2672 let parent_path = unsafe { asdf_value_path(parent) };
2673 assert_eq!(unsafe { CStr::from_ptr(parent_path) }, c"/nested");
2674
2675 let root = value_at(&h, "");
2677 assert!(unsafe { asdf_value_parent(root) }.is_null());
2678 assert_eq!(unsafe { CStr::from_ptr(asdf_value_path(root)) }, c"/");
2679
2680 for v in [inner, parent, root] {
2681 unsafe { asdf_value_destroy(v) };
2682 }
2683 }
2684
2685 #[test]
2689 fn sequence_elements_report_plain_indices() {
2690 let h = open();
2691 let item = value_at(&h, "list/1");
2692 assert_eq!(unsafe { CStr::from_ptr(asdf_value_path(item)) }, c"/list/1");
2693
2694 let again = value_at(&h, "/list/1");
2696 assert_eq!(value_node(again), value_node(item));
2697
2698 unsafe { asdf_value_destroy(again) };
2699 unsafe { asdf_value_destroy(item) };
2700 }
2701
2702 #[test]
2703 fn counted_string_accessors_report_lengths() {
2704 let h = open();
2705 let b = value_at(&h, "b");
2706 let mut text = core::ptr::null();
2707 let mut len = 0usize;
2708 assert_eq!(unsafe { asdf_value_as_string(b, &mut text, &mut len) }, AsdfValueErr::Ok);
2709 assert_eq!(len, 3);
2710 assert_eq!(unsafe { CStr::from_ptr(text) }, c"two");
2711
2712 let a = value_at(&h, "a");
2715 assert_eq!(
2716 unsafe { asdf_value_as_string(a, &mut text, &mut len) },
2717 AsdfValueErr::TypeMismatch
2718 );
2719 assert_eq!(unsafe { asdf_value_as_scalar(a, &mut text, &mut len) }, AsdfValueErr::Ok);
2720 assert_eq!(len, 1);
2721 assert_eq!(unsafe { CStr::from_ptr(text) }, c"1");
2722
2723 for v in [a, b] {
2724 unsafe { asdf_value_destroy(v) };
2725 }
2726 }
2727
2728 #[test]
2729 fn as_type_dispatches_on_the_requested_type() {
2730 let h = open();
2731 let a = value_at(&h, "a");
2732 let mut narrow: i32 = 0;
2733 assert_eq!(
2734 unsafe {
2735 asdf_value_as_type(
2736 a,
2737 AsdfValueType::Int32 as c_int,
2738 core::ptr::from_mut(&mut narrow).cast(),
2739 )
2740 },
2741 AsdfValueErr::Ok
2742 );
2743 assert_eq!(narrow, 1);
2744
2745 let mut text = core::ptr::null::<c_char>();
2747 assert_eq!(
2748 unsafe {
2749 asdf_value_as_type(
2750 a,
2751 AsdfValueType::String as c_int,
2752 core::ptr::from_mut(&mut text).cast(),
2753 )
2754 },
2755 AsdfValueErr::TypeMismatch
2756 );
2757
2758 let nothing = value_at(&h, "nothing");
2759 assert_eq!(
2760 unsafe {
2761 asdf_value_as_type(nothing, AsdfValueType::Null as c_int, core::ptr::null_mut())
2762 },
2763 AsdfValueErr::Ok
2764 );
2765
2766 for v in [a, nothing] {
2767 unsafe { asdf_value_destroy(v) };
2768 }
2769 }
2770
2771 #[test]
2772 fn typed_container_setters_build_a_tree() {
2773 use crate::file_ffi::asdf_value_destroy as destroy;
2774
2775 let file = unsafe { asdf_open_mem_ex(core::ptr::null(), 0, core::ptr::null_mut()) };
2777 assert!(!file.is_null());
2778 let handle = Handle(file);
2779
2780 let mapping = unsafe { asdf_mapping_create(handle.0) };
2781 assert!(!mapping.is_null());
2782 let key = CString::new("count").unwrap();
2783 assert_eq!(unsafe { asdf_mapping_set_int32(mapping, key.as_ptr(), -7) }, AsdfValueErr::Ok);
2784 let name = CString::new("name").unwrap();
2785 let value = CString::new("probe").unwrap();
2786 assert_eq!(
2787 unsafe { asdf_mapping_set_string0(mapping, name.as_ptr(), value.as_ptr()) },
2788 AsdfValueErr::Ok
2789 );
2790 let missing = CString::new("missing").unwrap();
2791 assert_eq!(unsafe { asdf_mapping_set_null(mapping, missing.as_ptr()) }, AsdfValueErr::Ok);
2792 assert_eq!(unsafe { asdf_mapping_size(mapping) }, 3);
2793
2794 let read_back = unsafe { asdf_mapping_get(mapping, key.as_ptr()) };
2795 assert!(!read_back.is_null());
2796 let mut got: i32 = 0;
2797 assert_eq!(unsafe { asdf_value_as_int32(read_back, &mut got) }, AsdfValueErr::Ok);
2798 assert_eq!(got, -7);
2799 unsafe { destroy(read_back) };
2800
2801 let numbers: [f64; 3] = [1.5, 2.5, 3.5];
2802 let sequence = unsafe { asdf_sequence_of_double(handle.0, numbers.as_ptr(), 3) };
2803 assert!(!sequence.is_null());
2804 assert_eq!(unsafe { asdf_sequence_size(sequence) }, 3);
2805 let second = unsafe { asdf_sequence_get(sequence, 1) };
2806 let mut d = 0.0f64;
2807 assert_eq!(unsafe { asdf_value_as_double(second, &mut d) }, AsdfValueErr::Ok);
2808 assert!((d - 2.5).abs() < f64::EPSILON);
2809 unsafe { destroy(second) };
2810
2811 assert_eq!(unsafe { asdf_sequence_append_bool(sequence, true) }, AsdfValueErr::Ok);
2812 assert_eq!(unsafe { asdf_sequence_size(sequence) }, 4);
2813
2814 unsafe { destroy(sequence) };
2815 unsafe { destroy(mapping) };
2816 }
2817
2818 #[test]
2819 fn mapping_update_merges_and_replaces() {
2820 use crate::file_ffi::asdf_value_destroy as destroy;
2821
2822 let file = unsafe { asdf_open_mem_ex(core::ptr::null(), 0, core::ptr::null_mut()) };
2823 let handle = Handle(file);
2824
2825 let target = unsafe { asdf_mapping_create(handle.0) };
2826 let update = unsafe { asdf_mapping_create(handle.0) };
2827 let shared = CString::new("shared").unwrap();
2828 let only_target = CString::new("target-only").unwrap();
2829 let only_update = CString::new("update-only").unwrap();
2830
2831 unsafe { asdf_mapping_set_int32(target, shared.as_ptr(), 1) };
2832 unsafe { asdf_mapping_set_int32(target, only_target.as_ptr(), 2) };
2833 unsafe { asdf_mapping_set_int32(update, shared.as_ptr(), 99) };
2834 unsafe { asdf_mapping_set_int32(update, only_update.as_ptr(), 3) };
2835
2836 assert_eq!(unsafe { asdf_mapping_update(target, update) }, AsdfValueErr::Ok);
2837 assert_eq!(unsafe { asdf_mapping_size(target) }, 3);
2838
2839 let merged = unsafe { asdf_mapping_get(target, shared.as_ptr()) };
2840 let mut got: i32 = 0;
2841 assert_eq!(unsafe { asdf_value_as_int32(merged, &mut got) }, AsdfValueErr::Ok);
2842 assert_eq!(got, 99, "the update's value should replace the target's");
2843 unsafe { destroy(merged) };
2844
2845 let copy = unsafe { asdf_mapping_copy(target) };
2847 assert!(!copy.is_null());
2848 assert_eq!(unsafe { asdf_mapping_size(copy) }, 3);
2849
2850 for v in [copy, update, target] {
2851 unsafe { destroy(v) };
2852 }
2853 }
2854
2855 #[test]
2856 fn recognises_containers() {
2857 let h = open();
2858 let root = value_at(&h, "");
2859 assert!(unsafe { asdf_value_is_mapping(root) });
2860 assert!(unsafe { asdf_value_is_container(root) });
2861 assert_eq!(unsafe { asdf_mapping_size(root) }, 7);
2862
2863 let list = value_at(&h, "list");
2864 assert!(unsafe { asdf_value_is_sequence(list) });
2865 assert_eq!(unsafe { asdf_sequence_size(list) }, 3);
2866
2867 let scalar = value_at(&h, "a");
2868 assert!(!unsafe { asdf_value_is_container(scalar) });
2869 assert_eq!(unsafe { asdf_mapping_size(scalar) }, -1);
2870 assert_eq!(unsafe { asdf_sequence_size(scalar) }, -1);
2871
2872 for v in [root, list, scalar] {
2873 unsafe { asdf_value_destroy(v) };
2874 }
2875 }
2876
2877 #[test]
2878 fn mapping_lookup_and_typed_reads() {
2879 let h = open();
2880 let root = value_at(&h, "");
2881
2882 let key = CString::new("a").unwrap();
2883 let a = unsafe { asdf_mapping_get(root, key.as_ptr()) };
2884 assert!(!a.is_null());
2885 let mut n: i64 = 0;
2886 assert_eq!(unsafe { asdf_value_as_int64(a, &mut n) }, AsdfValueErr::Ok);
2887 assert_eq!(n, 1);
2888 assert!(unsafe { asdf_value_is_int(a) });
2889
2890 let missing = CString::new("nope").unwrap();
2891 assert!(unsafe { asdf_mapping_get(root, missing.as_ptr()) }.is_null());
2892
2893 unsafe { asdf_value_destroy(a) };
2894 unsafe { asdf_value_destroy(root) };
2895 }
2896
2897 #[test]
2898 fn iterates_a_mapping_in_order() {
2899 let h = open();
2900 let root = value_at(&h, "");
2901
2902 let mut iter = unsafe { asdf_mapping_iter_init(root) };
2903 assert!(!iter.is_null());
2904
2905 let mut keys = Vec::new();
2906 while unsafe { asdf_mapping_iter_next(&mut iter) } {
2907 let head = unsafe { &*iter };
2908 assert!(!head.key.is_null());
2909 keys.push(unsafe { CStr::from_ptr(head.key) }.to_str().unwrap().to_string());
2910 assert!(!head.value.is_null());
2911 }
2912 assert!(iter.is_null(), "the iterator must null itself at the end");
2914 unsafe { asdf_mapping_iter_destroy(iter) };
2915
2916 assert_eq!(keys, ["a", "b", "c", "flag", "nothing", "list", "nested"]);
2917 unsafe { asdf_value_destroy(root) };
2918 }
2919
2920 #[test]
2921 fn iterates_a_mapping_in_reverse() {
2922 let h = open();
2923 let root = value_at(&h, "");
2924
2925 let mut iter = unsafe { asdf_mapping_reverse_iter_init(root) };
2926 let mut keys = Vec::new();
2927 while unsafe { asdf_mapping_iter_next(&mut iter) } {
2928 let head = unsafe { &*iter };
2929 keys.push(unsafe { CStr::from_ptr(head.key) }.to_str().unwrap().to_string());
2930 }
2931 assert_eq!(keys, ["nested", "list", "nothing", "flag", "c", "b", "a"]);
2932 unsafe { asdf_value_destroy(root) };
2933 }
2934
2935 #[test]
2936 fn iterates_a_sequence_with_indices() {
2937 let h = open();
2938 let list = value_at(&h, "list");
2939
2940 let mut iter = unsafe { asdf_sequence_iter_init(list) };
2941 let mut seen = Vec::new();
2942 while unsafe { asdf_sequence_iter_next(&mut iter) } {
2943 let head = unsafe { &*iter };
2944 let mut n: i64 = 0;
2945 unsafe { asdf_value_as_int64(head.value.cast(), &mut n) };
2946 seen.push((head.index, n));
2947 }
2948 assert_eq!(seen, [(0, 10), (1, 20), (2, 30)]);
2949 assert!(iter.is_null());
2950 unsafe { asdf_value_destroy(list) };
2951 }
2952
2953 #[test]
2954 fn a_reversed_sequence_keeps_original_indices() {
2955 let h = open();
2956 let list = value_at(&h, "list");
2957
2958 let mut iter = unsafe { asdf_sequence_reverse_iter_init(list) };
2959 let mut seen = Vec::new();
2960 while unsafe { asdf_sequence_iter_next(&mut iter) } {
2961 let head = unsafe { &*iter };
2962 seen.push(head.index);
2963 }
2964 assert_eq!(seen, [2, 1, 0]);
2965 unsafe { asdf_value_destroy(list) };
2966 }
2967
2968 #[test]
2969 fn breaking_out_of_a_loop_leaves_the_iterator_to_destroy() {
2970 let h = open();
2971 let root = value_at(&h, "");
2972
2973 let mut iter = unsafe { asdf_mapping_iter_init(root) };
2974 let mut count = 0;
2975 while unsafe { asdf_mapping_iter_next(&mut iter) } {
2976 count += 1;
2977 if count == 2 {
2978 break;
2979 }
2980 }
2981 assert!(!iter.is_null());
2984 unsafe { asdf_mapping_iter_destroy(iter) };
2985 unsafe { asdf_value_destroy(root) };
2986 }
2987
2988 #[test]
2989 fn sequence_indexing_accepts_negatives() {
2990 let h = open();
2991 let list = value_at(&h, "list");
2992
2993 let last = unsafe { asdf_sequence_get(list, -1) };
2994 assert!(!last.is_null());
2995 let mut n: i64 = 0;
2996 unsafe { asdf_value_as_int64(last, &mut n) };
2997 assert_eq!(n, 30);
2998
2999 assert!(unsafe { asdf_sequence_get(list, 3) }.is_null());
3000 unsafe { asdf_value_destroy(last) };
3001 unsafe { asdf_value_destroy(list) };
3002 }
3003
3004 #[test]
3005 fn typed_predicates_and_reads() {
3006 let h = open();
3007
3008 let b = value_at(&h, "b");
3009 assert!(unsafe { asdf_value_is_string(b) });
3010 let mut s: *const c_char = core::ptr::null();
3011 assert_eq!(unsafe { asdf_value_as_string0(b, &mut s) }, AsdfValueErr::Ok);
3012 assert_eq!(unsafe { CStr::from_ptr(s) }.to_str().unwrap(), "two");
3013
3014 let c = value_at(&h, "c");
3015 assert!(unsafe { asdf_value_is_double(c) });
3016 let mut d = 0f64;
3017 assert_eq!(unsafe { asdf_value_as_double(c, &mut d) }, AsdfValueErr::Ok);
3018 assert_eq!(d, 3.5);
3019
3020 let flag = value_at(&h, "flag");
3021 assert!(unsafe { asdf_value_is_bool(flag) });
3022 let mut bl = false;
3023 assert_eq!(unsafe { asdf_value_as_bool(flag, &mut bl) }, AsdfValueErr::Ok);
3024 assert!(bl);
3025
3026 let nothing = value_at(&h, "nothing");
3027 assert!(unsafe { asdf_value_is_null(nothing) });
3028
3029 for v in [b, c, flag, nothing] {
3030 unsafe { asdf_value_destroy(v) };
3031 }
3032 }
3033
3034 #[test]
3035 fn reading_the_wrong_type_is_a_mismatch_not_a_guess() {
3036 let h = open();
3037 let b = value_at(&h, "b");
3038 let mut n: i64 = 0;
3039 assert_eq!(unsafe { asdf_value_as_int64(b, &mut n) }, AsdfValueErr::TypeMismatch);
3040 unsafe { asdf_value_destroy(b) };
3041 }
3042
3043 #[test]
3044 fn as_mapping_and_as_sequence_check_the_type() {
3045 let h = open();
3046 let root = value_at(&h, "");
3047 let list = value_at(&h, "list");
3048
3049 let mut out: *mut AsdfMapping = core::ptr::null_mut();
3050 assert_eq!(unsafe { asdf_value_as_mapping(root, &mut out) }, AsdfValueErr::Ok);
3051 assert_eq!(out, root);
3052 assert_eq!(unsafe { asdf_value_as_mapping(list, &mut out) }, AsdfValueErr::TypeMismatch);
3053
3054 let mut seq: *mut AsdfSequence = core::ptr::null_mut();
3055 assert_eq!(unsafe { asdf_value_as_sequence(list, &mut seq) }, AsdfValueErr::Ok);
3056 assert_eq!(unsafe { asdf_value_as_sequence(root, &mut seq) }, AsdfValueErr::TypeMismatch);
3057
3058 unsafe { asdf_value_destroy(root) };
3059 unsafe { asdf_value_destroy(list) };
3060 }
3061
3062 #[test]
3063 fn copies_are_independent_handles_to_the_same_node() {
3064 let h = open();
3065 let a = value_at(&h, "a");
3066 let copy = unsafe { asdf_value_copy(a) };
3067 assert!(!copy.is_null());
3068 assert_ne!(copy, a);
3069
3070 unsafe { asdf_value_destroy(a) };
3072 let mut n: i64 = 0;
3073 assert_eq!(unsafe { asdf_value_as_int64(copy, &mut n) }, AsdfValueErr::Ok);
3074 assert_eq!(n, 1);
3075 unsafe { asdf_value_destroy(copy) };
3076 }
3077
3078 #[test]
3079 fn null_handles_are_tolerated_everywhere() {
3080 let null = core::ptr::null_mut();
3081 assert!(!unsafe { asdf_value_is_mapping(null) });
3082 assert!(!unsafe { asdf_value_is_sequence(null) });
3083 assert!(!unsafe { asdf_value_is_container(null) });
3084 assert_eq!(unsafe { asdf_container_size(null) }, -1);
3085 assert_eq!(unsafe { asdf_mapping_size(null) }, -1);
3086 assert_eq!(unsafe { asdf_sequence_size(null) }, -1);
3087 assert!(unsafe { asdf_mapping_iter_init(null) }.is_null());
3088 assert!(unsafe { asdf_sequence_iter_init(null) }.is_null());
3089 assert!(!unsafe { asdf_mapping_iter_next(core::ptr::null_mut()) });
3090 assert!(!unsafe { asdf_sequence_iter_next(core::ptr::null_mut()) });
3091 unsafe { asdf_mapping_iter_destroy(core::ptr::null_mut()) };
3092 unsafe { asdf_sequence_iter_destroy(core::ptr::null_mut()) };
3093 assert!(unsafe { asdf_value_copy(null) }.is_null());
3094 assert!(unsafe { asdf_value_file(null) }.is_null());
3095 }
3096
3097 #[test]
3101 fn iterator_public_heads_sit_at_offset_zero() {
3102 use std::mem::offset_of;
3103 assert_eq!(offset_of!(MappingIter, public), 0);
3104 assert_eq!(offset_of!(SequenceIter, public), 0);
3105 }
3106}
3107#[cfg(test)]
3108mod build_tests {
3109 use super::*;
3110 use crate::file_ffi::{asdf_close, asdf_open_mem_ex, asdf_value_destroy, asdf_write_to_mem};
3111 use crate::types::AsdfYamlNodeStyle;
3112 use core::ffi::c_void;
3113
3114 struct Handle(*mut AsdfFile);
3115 impl Drop for Handle {
3116 fn drop(&mut self) {
3117 unsafe { asdf_close(self.0) };
3118 }
3119 }
3120
3121 fn writable() -> Handle {
3122 let f = unsafe { asdf_open_mem_ex(core::ptr::null(), 0, core::ptr::null_mut()) };
3123 assert!(!f.is_null());
3124 Handle(f)
3125 }
3126
3127 fn cstr(s: &str) -> CString {
3128 CString::new(s).unwrap()
3129 }
3130
3131 #[test]
3132 fn builds_a_mapping_from_values() {
3133 let h = writable();
3134
3135 let mapping = unsafe { asdf_mapping_create(h.0) };
3136 assert!(!mapping.is_null());
3137 assert!(unsafe { asdf_value_is_mapping(mapping) });
3138 assert_eq!(unsafe { asdf_mapping_size(mapping) }, 0);
3139
3140 let n = unsafe { asdf_value_of_int64(h.0, 42) };
3141 let key = cstr("answer");
3142 assert_eq!(unsafe { asdf_mapping_set(mapping, key.as_ptr(), n) }, AsdfValueErr::Ok);
3143 assert_eq!(unsafe { asdf_mapping_size(mapping) }, 1);
3144
3145 let found = unsafe { asdf_mapping_get(mapping, key.as_ptr()) };
3146 let mut value: i64 = 0;
3147 assert_eq!(unsafe { asdf_value_as_int64(found, &mut value) }, AsdfValueErr::Ok);
3148 assert_eq!(value, 42);
3149
3150 unsafe { asdf_value_destroy(found) };
3151 unsafe { asdf_mapping_destroy(mapping) };
3154 }
3155
3156 #[test]
3157 fn builds_a_sequence_by_appending() {
3158 let h = writable();
3159 let sequence = unsafe { asdf_sequence_create(h.0) };
3160 assert!(unsafe { asdf_value_is_sequence(sequence) });
3161
3162 for value in [10i64, 20, 30] {
3163 let item = unsafe { asdf_value_of_int64(h.0, value) };
3164 assert_eq!(unsafe { asdf_sequence_append(sequence, item) }, AsdfValueErr::Ok);
3166 }
3167 assert_eq!(unsafe { asdf_sequence_size(sequence) }, 3);
3168
3169 let second = unsafe { asdf_sequence_get(sequence, 1) };
3170 let mut value: i64 = 0;
3171 unsafe { asdf_value_as_int64(second, &mut value) };
3172 assert_eq!(value, 20);
3173
3174 unsafe { asdf_value_destroy(second) };
3175 unsafe { asdf_sequence_destroy(sequence) };
3176 }
3177
3178 #[test]
3179 fn popping_removes_and_returns() {
3180 let h = writable();
3181
3182 let mapping = unsafe { asdf_mapping_create(h.0) };
3183 let n = unsafe { asdf_value_of_int64(h.0, 7) };
3184 let key = cstr("gone");
3185 unsafe { asdf_mapping_set(mapping, key.as_ptr(), n) };
3186
3187 let popped = unsafe { asdf_mapping_pop(mapping, key.as_ptr()) };
3188 assert!(!popped.is_null());
3189 let mut value: i64 = 0;
3190 unsafe { asdf_value_as_int64(popped, &mut value) };
3191 assert_eq!(value, 7);
3192 assert_eq!(unsafe { asdf_mapping_size(mapping) }, 0);
3193 assert!(unsafe { asdf_mapping_pop(mapping, key.as_ptr()) }.is_null());
3195
3196 let sequence = unsafe { asdf_sequence_create(h.0) };
3197 for value in [1i64, 2] {
3198 let item = unsafe { asdf_value_of_int64(h.0, value) };
3199 unsafe { asdf_sequence_append(sequence, item) };
3200 }
3201 let first = unsafe { asdf_sequence_pop(sequence, 0) };
3202 assert!(!first.is_null());
3203 assert_eq!(unsafe { asdf_sequence_size(sequence) }, 1);
3204
3205 for v in [popped, first, mapping, sequence] {
3208 unsafe { asdf_value_destroy(v) };
3209 }
3210 }
3211
3212 #[test]
3213 fn a_built_tree_writes_and_reads_back() {
3214 let h = writable();
3215
3216 let meta = unsafe { asdf_mapping_create(h.0) };
3219 let name = unsafe { asdf_value_of_string0(h.0, cstr("obs").as_ptr()) };
3220 let name_key = cstr("name");
3221 unsafe { asdf_mapping_set(meta, name_key.as_ptr(), name) };
3222
3223 let frames = unsafe { asdf_sequence_create(h.0) };
3224 for value in [1i64, 2, 3] {
3225 let item = unsafe { asdf_value_of_int64(h.0, value) };
3226 unsafe { asdf_sequence_append(frames, item) };
3227 }
3228 let frames_key = cstr("frames");
3229 unsafe { asdf_mapping_set(meta, frames_key.as_ptr(), frames) };
3230
3231 let path = cstr("meta");
3232 assert_eq!(
3233 unsafe { crate::file_ffi::set_value_at(h.0, path.as_ptr(), meta) },
3234 AsdfValueErr::Ok
3235 );
3236
3237 let mut buf: *mut c_void = core::ptr::null_mut();
3238 let mut size = 0usize;
3239 assert_eq!(unsafe { asdf_write_to_mem(h.0, &mut buf, &mut size) }, 0);
3240
3241 let reopened = unsafe { asdf_open_mem_ex(buf, size, core::ptr::null_mut()) };
3242 let r = Handle(reopened);
3243
3244 let inner = cstr("meta/name");
3245 let mut text: *const c_char = core::ptr::null();
3246 assert_eq!(
3247 unsafe { crate::file_ffi::asdf_get_string0(r.0, inner.as_ptr(), &mut text) },
3248 AsdfValueErr::Ok
3249 );
3250 assert_eq!(unsafe { CStr::from_ptr(text) }.to_str().unwrap(), "obs");
3251
3252 let third = cstr("meta/frames/2");
3253 let mut value: i64 = 0;
3254 assert_eq!(
3255 unsafe { crate::file_ffi::asdf_get_int64(r.0, third.as_ptr(), &mut value) },
3256 AsdfValueErr::Ok
3257 );
3258 assert_eq!(value, 3);
3259
3260 unsafe { libc::free(buf) };
3261 let _ = (meta, name, frames);
3264 }
3265
3266 #[test]
3267 fn a_numeric_string_value_stays_a_string() {
3268 let h = writable();
3269 let value = unsafe { asdf_value_of_string0(h.0, cstr("42").as_ptr()) };
3270 assert!(unsafe { asdf_value_is_string(value) });
3271 let mut n: i64 = 0;
3272 assert_eq!(unsafe { asdf_value_as_int64(value, &mut n) }, AsdfValueErr::TypeMismatch);
3273 unsafe { asdf_value_destroy(value) };
3274 }
3275
3276 #[test]
3277 fn scalar_constructors_produce_the_right_types() {
3278 let h = writable();
3279
3280 let cases: Vec<(*mut AsdfValue, AsdfValueType)> = vec![
3281 (unsafe { asdf_value_of_bool(h.0, true) }, AsdfValueType::Bool),
3282 (unsafe { asdf_value_of_null(h.0) }, AsdfValueType::Null),
3283 (unsafe { asdf_value_of_double(h.0, 1.5) }, AsdfValueType::Double),
3284 (unsafe { asdf_value_of_int64(h.0, 7) }, AsdfValueType::Uint8),
3286 (unsafe { asdf_value_of_int64(h.0, -7) }, AsdfValueType::Int8),
3287 ];
3288 for (value, expected) in cases {
3289 assert!(!value.is_null());
3290 assert_eq!(unsafe { crate::file_ffi::asdf_value_get_type(value) }, expected);
3291 unsafe { asdf_value_destroy(value) };
3292 }
3293 }
3294
3295 #[test]
3296 fn iterates_either_container_kind() {
3297 let h = writable();
3298
3299 let mapping = unsafe { asdf_mapping_create(h.0) };
3300 for (key, value) in [("a", 1i64), ("b", 2)] {
3301 let item = unsafe { asdf_value_of_int64(h.0, value) };
3302 unsafe { asdf_mapping_set(mapping, cstr(key).as_ptr(), item) };
3303 }
3304
3305 let mut iter = unsafe { asdf_container_iter_init(mapping) };
3306 let mut seen = Vec::new();
3307 while unsafe { asdf_container_iter_next(&mut iter) } {
3308 let head = unsafe { &*iter };
3309 assert!(!head.key.is_null(), "a mapping must report keys");
3310 assert_eq!(head.index, seen.len() as c_int);
3313 seen.push(unsafe { CStr::from_ptr(head.key) }.to_str().unwrap().to_string());
3314 }
3315 assert_eq!(seen, ["a", "b"]);
3316 assert!(iter.is_null());
3317
3318 let sequence = unsafe { asdf_sequence_create(h.0) };
3319 for value in [10i64, 20] {
3320 let item = unsafe { asdf_value_of_int64(h.0, value) };
3321 unsafe { asdf_sequence_append(sequence, item) };
3322 }
3323 let mut iter = unsafe { asdf_container_iter_init(sequence) };
3324 let mut indices = Vec::new();
3325 while unsafe { asdf_container_iter_next(&mut iter) } {
3326 let head = unsafe { &*iter };
3327 assert!(head.key.is_null(), "a sequence reports no key");
3328 indices.push(head.index);
3329 }
3330 assert_eq!(indices, [0, 1]);
3331
3332 unsafe { asdf_mapping_destroy(mapping) };
3333 unsafe { asdf_sequence_destroy(sequence) };
3334 }
3335
3336 #[test]
3337 fn container_iteration_can_be_reversed() {
3338 let h = writable();
3339 let sequence = unsafe { asdf_sequence_create(h.0) };
3340 for value in [1i64, 2, 3] {
3341 let item = unsafe { asdf_value_of_int64(h.0, value) };
3342 unsafe { asdf_sequence_append(sequence, item) };
3343 }
3344
3345 let mut iter = unsafe { asdf_container_reverse_iter_init(sequence) };
3346 let mut values = Vec::new();
3347 while unsafe { asdf_container_iter_next(&mut iter) } {
3348 let head = unsafe { &*iter };
3349 let mut n: i64 = 0;
3350 unsafe { asdf_value_as_int64(head.value.cast(), &mut n) };
3351 values.push(n);
3352 }
3353 assert_eq!(values, [3, 2, 1]);
3354 unsafe { asdf_sequence_destroy(sequence) };
3355 }
3356
3357 #[test]
3358 fn styles_can_be_set() {
3359 let h = writable();
3360 let sequence = unsafe { asdf_sequence_create(h.0) };
3361 unsafe { asdf_sequence_set_style(sequence, AsdfYamlNodeStyle::Flow) };
3363 unsafe { asdf_sequence_set_style(sequence, AsdfYamlNodeStyle::Block) };
3364 assert_eq!(unsafe { asdf_sequence_size(sequence) }, 0);
3365
3366 let mapping = unsafe { asdf_mapping_create(h.0) };
3367 unsafe { asdf_mapping_set_style(mapping, AsdfYamlNodeStyle::Flow) };
3368 assert_eq!(unsafe { asdf_mapping_size(mapping) }, 0);
3369
3370 unsafe { asdf_sequence_destroy(sequence) };
3371 unsafe { asdf_mapping_destroy(mapping) };
3372 }
3373
3374 #[test]
3375 fn setting_the_wrong_kind_is_a_mismatch() {
3376 let h = writable();
3377 let sequence = unsafe { asdf_sequence_create(h.0) };
3378 let item = unsafe { asdf_value_of_int64(h.0, 1) };
3379
3380 assert_eq!(
3382 unsafe { asdf_mapping_set(sequence, cstr("k").as_ptr(), item) },
3383 AsdfValueErr::TypeMismatch
3384 );
3385
3386 let mapping = unsafe { asdf_mapping_create(h.0) };
3387 assert_eq!(unsafe { asdf_sequence_append(mapping, item) }, AsdfValueErr::TypeMismatch);
3388
3389 unsafe { asdf_value_destroy(item) };
3390 unsafe { asdf_sequence_destroy(sequence) };
3391 unsafe { asdf_mapping_destroy(mapping) };
3392 }
3393
3394 #[test]
3395 fn null_handles_are_tolerated() {
3396 assert!(unsafe { asdf_mapping_create(core::ptr::null_mut()) }.is_null());
3397 assert!(unsafe { asdf_sequence_create(core::ptr::null_mut()) }.is_null());
3398 assert!(unsafe { asdf_value_of_int64(core::ptr::null_mut(), 0) }.is_null());
3399 assert!(unsafe { asdf_value_of_null(core::ptr::null_mut()) }.is_null());
3400 assert!(
3401 unsafe { asdf_value_of_string0(core::ptr::null_mut(), core::ptr::null()) }.is_null()
3402 );
3403 assert!(unsafe { asdf_container_iter_init(core::ptr::null_mut()) }.is_null());
3404 assert!(!unsafe { asdf_container_iter_next(core::ptr::null_mut()) });
3405 unsafe { asdf_container_iter_destroy(core::ptr::null_mut()) };
3406 }
3407}