1use crate::progress::{NoProgressCallback, ProgressCallback};
2use binaryninjacore_sys::*;
3use std::ffi::{c_char, c_void, CStr};
4use std::fmt::{Debug, Display, Formatter};
5use std::hash::Hash;
6use std::path::{Path, PathBuf};
7use std::ptr::NonNull;
8
9use crate::data_buffer::DataBuffer;
10use crate::metadata::Metadata;
11use crate::platform::Platform;
12use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable};
13use crate::string::{raw_to_string, BnString, IntoCStr};
14use crate::type_container::TypeContainer;
15use crate::types::{QualifiedName, QualifiedNameAndType, QualifiedNameTypeAndId, Type};
16
17#[repr(transparent)]
18#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
19pub struct TypeArchiveSnapshotId(pub String);
20
21impl TypeArchiveSnapshotId {
22 pub fn unset() -> Self {
23 Self("".to_string())
24 }
25}
26
27impl Display for TypeArchiveSnapshotId {
28 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
29 f.write_fmt(format_args!("{}", self.0))
30 }
31}
32
33impl CoreArrayProvider for TypeArchiveSnapshotId {
34 type Raw = *mut c_char;
35 type Context = ();
36 type Wrapped<'a> = TypeArchiveSnapshotId;
37}
38
39unsafe impl CoreArrayProviderInner for TypeArchiveSnapshotId {
40 unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
41 BNFreeStringList(raw, count)
42 }
43
44 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
45 let str = CStr::from_ptr(*raw).to_str().unwrap().to_string();
46 TypeArchiveSnapshotId(str)
47 }
48}
49
50pub struct TypeArchive {
54 pub(crate) handle: NonNull<BNTypeArchive>,
55}
56
57impl TypeArchive {
58 pub(crate) unsafe fn from_raw(handle: NonNull<BNTypeArchive>) -> Self {
59 Self { handle }
60 }
61
62 pub(crate) unsafe fn ref_from_raw(handle: NonNull<BNTypeArchive>) -> Ref<Self> {
63 Ref::new(Self { handle })
64 }
65
66 pub fn open(path: impl AsRef<Path>) -> Option<Ref<TypeArchive>> {
68 let raw_path = path.as_ref().to_cstr();
69 let handle = unsafe { BNOpenTypeArchive(raw_path.as_ptr()) };
70 NonNull::new(handle).map(|handle| unsafe { TypeArchive::ref_from_raw(handle) })
71 }
72
73 pub fn create(path: impl AsRef<Path>, platform: &Platform) -> Option<Ref<TypeArchive>> {
77 let raw_path = path.as_ref().to_cstr();
78 let handle = unsafe { BNCreateTypeArchive(raw_path.as_ptr(), platform.handle) };
79 NonNull::new(handle).map(|handle| unsafe { TypeArchive::ref_from_raw(handle) })
80 }
81
82 pub fn create_with_id(
86 path: impl AsRef<Path>,
87 id: &str,
88 platform: &Platform,
89 ) -> Option<Ref<TypeArchive>> {
90 let raw_path = path.as_ref().to_cstr();
91 let id = id.to_cstr();
92 let handle =
93 unsafe { BNCreateTypeArchiveWithId(raw_path.as_ptr(), platform.handle, id.as_ptr()) };
94 NonNull::new(handle).map(|handle| unsafe { TypeArchive::ref_from_raw(handle) })
95 }
96
97 pub fn lookup_by_id(id: &str) -> Option<Ref<TypeArchive>> {
99 let id = id.to_cstr();
100 let handle = unsafe { BNLookupTypeArchiveById(id.as_ptr()) };
101 NonNull::new(handle).map(|handle| unsafe { TypeArchive::ref_from_raw(handle) })
102 }
103
104 pub fn path(&self) -> Option<PathBuf> {
106 let result = unsafe { BNGetTypeArchivePath(self.handle.as_ptr()) };
107 assert!(!result.is_null());
108 let path_str = unsafe { BnString::into_string(result) };
109 Some(PathBuf::from(path_str))
110 }
111
112 pub fn id(&self) -> BnString {
114 let result = unsafe { BNGetTypeArchiveId(self.handle.as_ptr()) };
115 assert!(!result.is_null());
116 unsafe { BnString::from_raw(result) }
117 }
118
119 pub fn platform(&self) -> Ref<Platform> {
121 let result = unsafe { BNGetTypeArchivePlatform(self.handle.as_ptr()) };
122 assert!(!result.is_null());
123 unsafe { Platform::ref_from_raw(result) }
124 }
125
126 pub fn current_snapshot_id(&self) -> TypeArchiveSnapshotId {
128 let result = unsafe { BNGetTypeArchiveCurrentSnapshotId(self.handle.as_ptr()) };
129 assert!(!result.is_null());
130 let id = unsafe { BnString::into_string(result) };
131 TypeArchiveSnapshotId(id)
132 }
133
134 pub fn set_current_snapshot_id(&self, id: &TypeArchiveSnapshotId) {
136 let snapshot = id.clone().to_cstr();
137 unsafe { BNSetTypeArchiveCurrentSnapshot(self.handle.as_ptr(), snapshot.as_ptr()) }
138 }
139
140 pub fn all_snapshot_ids(&self) -> Array<TypeArchiveSnapshotId> {
142 let mut count = 0;
143 let result = unsafe { BNGetTypeArchiveAllSnapshotIds(self.handle.as_ptr(), &mut count) };
144 assert!(!result.is_null());
145 unsafe { Array::new(result, count, ()) }
146 }
147
148 pub fn get_snapshot_parent_ids(
150 &self,
151 snapshot: &TypeArchiveSnapshotId,
152 ) -> Option<Array<BnString>> {
153 let mut count = 0;
154 let snapshot = snapshot.clone().to_cstr();
155 let result = unsafe {
156 BNGetTypeArchiveSnapshotParentIds(self.handle.as_ptr(), snapshot.as_ptr(), &mut count)
157 };
158 (!result.is_null()).then(|| unsafe { Array::new(result, count, ()) })
159 }
160
161 pub fn get_snapshot_child_ids(
163 &self,
164 snapshot: &TypeArchiveSnapshotId,
165 ) -> Option<Array<BnString>> {
166 let mut count = 0;
167 let snapshot = snapshot.clone().to_cstr();
168 let result = unsafe {
169 BNGetTypeArchiveSnapshotChildIds(self.handle.as_ptr(), snapshot.as_ptr(), &mut count)
170 };
171 (!result.is_null()).then(|| unsafe { Array::new(result, count, ()) })
172 }
173
174 pub fn add_type(&self, named_type: QualifiedNameAndType) -> bool {
180 self.add_types(vec![named_type])
181 }
182
183 pub fn add_types(&self, named_types: Vec<QualifiedNameAndType>) -> bool {
189 let new_types_raw: Vec<_> = named_types
190 .into_iter()
191 .map(QualifiedNameAndType::into_raw)
192 .collect();
193 let result = unsafe {
194 BNAddTypeArchiveTypes(
195 self.handle.as_ptr(),
196 new_types_raw.as_ptr(),
197 new_types_raw.len(),
198 )
199 };
200 for new_type in new_types_raw {
201 QualifiedNameAndType::free_raw(new_type);
202 }
203 result
204 }
205
206 pub fn rename_type(&self, old_name: QualifiedName, new_name: QualifiedName) -> bool {
211 if let Some(id) = self.get_type_id(old_name) {
212 self.rename_type_by_id(&id, new_name)
213 } else {
214 false
215 }
216 }
217
218 pub fn rename_type_by_id(&self, id: &str, new_name: QualifiedName) -> bool {
223 let id = id.to_cstr();
224 let raw_name = QualifiedName::into_raw(new_name);
225 let result =
226 unsafe { BNRenameTypeArchiveType(self.handle.as_ptr(), id.as_ptr(), &raw_name) };
227 QualifiedName::free_raw(raw_name);
228 result
229 }
230
231 pub fn delete_type(&self, name: QualifiedName) -> bool {
233 if let Some(type_id) = self.get_type_id(name) {
234 self.delete_type_by_id(&type_id)
235 } else {
236 false
237 }
238 }
239
240 pub fn delete_type_by_id(&self, id: &str) -> bool {
242 let id = id.to_cstr();
243 unsafe { BNDeleteTypeArchiveType(self.handle.as_ptr(), id.as_ptr()) }
244 }
245
246 pub fn get_type_by_name(&self, name: QualifiedName) -> Option<Ref<Type>> {
250 self.get_type_by_name_from_snapshot(name, &TypeArchiveSnapshotId::unset())
251 }
252
253 pub fn get_type_by_name_from_snapshot(
258 &self,
259 name: QualifiedName,
260 snapshot: &TypeArchiveSnapshotId,
261 ) -> Option<Ref<Type>> {
262 let raw_name = QualifiedName::into_raw(name);
263 let snapshot = snapshot.clone().to_cstr();
264 let result = unsafe {
265 BNGetTypeArchiveTypeByName(self.handle.as_ptr(), &raw_name, snapshot.as_ptr())
266 };
267 QualifiedName::free_raw(raw_name);
268 (!result.is_null()).then(|| unsafe { Type::ref_from_raw(result) })
269 }
270
271 pub fn get_type_by_id(&self, id: &str) -> Option<Ref<Type>> {
275 self.get_type_by_id_from_snapshot(id, &TypeArchiveSnapshotId::unset())
276 }
277
278 pub fn get_type_by_id_from_snapshot(
283 &self,
284 id: &str,
285 snapshot: &TypeArchiveSnapshotId,
286 ) -> Option<Ref<Type>> {
287 let id = id.to_cstr();
288 let snapshot = snapshot.clone().to_cstr();
289 let result = unsafe {
290 BNGetTypeArchiveTypeById(self.handle.as_ptr(), id.as_ptr(), snapshot.as_ptr())
291 };
292 (!result.is_null()).then(|| unsafe { Type::ref_from_raw(result) })
293 }
294
295 pub fn get_type_name_by_id(&self, id: &str) -> QualifiedName {
299 self.get_type_name_by_id_from_snapshot(id, &TypeArchiveSnapshotId::unset())
300 }
301
302 pub fn get_type_name_by_id_from_snapshot(
307 &self,
308 id: &str,
309 snapshot: &TypeArchiveSnapshotId,
310 ) -> QualifiedName {
311 let id = id.to_cstr();
312 let snapshot = snapshot.clone().to_cstr();
313 let result = unsafe {
314 BNGetTypeArchiveTypeName(self.handle.as_ptr(), id.as_ptr(), snapshot.as_ptr())
315 };
316 QualifiedName::from_owned_raw(result)
317 }
318
319 pub fn get_type_id(&self, name: QualifiedName) -> Option<String> {
323 self.get_type_id_from_snapshot(name, &TypeArchiveSnapshotId::unset())
324 }
325
326 pub fn get_type_id_from_snapshot(
331 &self,
332 name: QualifiedName,
333 snapshot: &TypeArchiveSnapshotId,
334 ) -> Option<String> {
335 let raw_name = QualifiedName::into_raw(name);
336 let snapshot = snapshot.clone().to_cstr();
337 let result =
338 unsafe { BNGetTypeArchiveTypeId(self.handle.as_ptr(), &raw_name, snapshot.as_ptr()) };
339 QualifiedName::free_raw(raw_name);
340 (!result.is_null()).then(|| unsafe { BnString::into_string(result) })
341 }
342
343 pub fn get_types_and_ids(&self) -> Array<QualifiedNameTypeAndId> {
345 self.get_types_and_ids_from_snapshot(&TypeArchiveSnapshotId::unset())
346 }
347
348 pub fn get_types_and_ids_from_snapshot(
352 &self,
353 snapshot: &TypeArchiveSnapshotId,
354 ) -> Array<QualifiedNameTypeAndId> {
355 let mut count = 0;
356 let snapshot = snapshot.clone().to_cstr();
357 let result =
358 unsafe { BNGetTypeArchiveTypes(self.handle.as_ptr(), snapshot.as_ptr(), &mut count) };
359 assert!(!result.is_null());
360 unsafe { Array::new(result, count, ()) }
361 }
362
363 pub fn get_type_ids(&self) -> Array<BnString> {
365 self.get_type_ids_from_snapshot(&TypeArchiveSnapshotId::unset())
366 }
367
368 pub fn get_type_ids_from_snapshot(&self, snapshot: &TypeArchiveSnapshotId) -> Array<BnString> {
372 let mut count = 0;
373 let snapshot = snapshot.clone().to_cstr();
374 let result =
375 unsafe { BNGetTypeArchiveTypeIds(self.handle.as_ptr(), snapshot.as_ptr(), &mut count) };
376 assert!(!result.is_null());
377 unsafe { Array::new(result, count, ()) }
378 }
379
380 pub fn get_type_names(&self) -> Array<QualifiedName> {
382 self.get_type_names_from_snapshot(&TypeArchiveSnapshotId::unset())
383 }
384
385 pub fn get_type_names_from_snapshot(
389 &self,
390 snapshot: &TypeArchiveSnapshotId,
391 ) -> Array<QualifiedName> {
392 let mut count = 0;
393 let snapshot = snapshot.clone().to_cstr();
394 let result = unsafe {
395 BNGetTypeArchiveTypeNames(self.handle.as_ptr(), snapshot.as_ptr(), &mut count)
396 };
397 assert!(!result.is_null());
398 unsafe { Array::new(result, count, ()) }
399 }
400
401 pub fn get_type_names_and_ids(&self) -> (Array<QualifiedName>, Array<BnString>) {
403 self.get_type_names_and_ids_from_snapshot(&TypeArchiveSnapshotId::unset())
404 }
405
406 pub fn get_type_names_and_ids_from_snapshot(
410 &self,
411 snapshot: &TypeArchiveSnapshotId,
412 ) -> (Array<QualifiedName>, Array<BnString>) {
413 let mut count = 0;
414 let snapshot = snapshot.clone().to_cstr();
415 let mut names = std::ptr::null_mut();
416 let mut ids = std::ptr::null_mut();
417 let result = unsafe {
418 BNGetTypeArchiveTypeNamesAndIds(
419 self.handle.as_ptr(),
420 snapshot.as_ptr(),
421 &mut names,
422 &mut ids,
423 &mut count,
424 )
425 };
426 assert!(result);
427 (unsafe { Array::new(names, count, ()) }, unsafe {
428 Array::new(ids, count, ())
429 })
430 }
431
432 pub fn get_outgoing_direct_references(&self, id: &str) -> Array<BnString> {
436 self.get_outgoing_direct_references_from_snapshot(id, &TypeArchiveSnapshotId::unset())
437 }
438
439 pub fn get_outgoing_direct_references_from_snapshot(
444 &self,
445 id: &str,
446 snapshot: &TypeArchiveSnapshotId,
447 ) -> Array<BnString> {
448 let id = id.to_cstr();
449 let snapshot = snapshot.clone().to_cstr();
450 let mut count = 0;
451 let result = unsafe {
452 BNGetTypeArchiveOutgoingDirectTypeReferences(
453 self.handle.as_ptr(),
454 id.as_ptr(),
455 snapshot.as_ptr(),
456 &mut count,
457 )
458 };
459 assert!(!result.is_null());
460 unsafe { Array::new(result, count, ()) }
461 }
462
463 pub fn get_outgoing_recursive_references(&self, id: &str) -> Array<BnString> {
467 self.get_outgoing_recursive_references_from_snapshot(id, &TypeArchiveSnapshotId::unset())
468 }
469
470 pub fn get_outgoing_recursive_references_from_snapshot(
475 &self,
476 id: &str,
477 snapshot: &TypeArchiveSnapshotId,
478 ) -> Array<BnString> {
479 let id = id.to_cstr();
480 let snapshot = snapshot.clone().to_cstr();
481 let mut count = 0;
482 let result = unsafe {
483 BNGetTypeArchiveOutgoingRecursiveTypeReferences(
484 self.handle.as_ptr(),
485 id.as_ptr(),
486 snapshot.as_ptr(),
487 &mut count,
488 )
489 };
490 assert!(!result.is_null());
491 unsafe { Array::new(result, count, ()) }
492 }
493
494 pub fn get_incoming_direct_references(&self, id: &str) -> Array<BnString> {
498 self.get_incoming_direct_references_with_snapshot(id, &TypeArchiveSnapshotId::unset())
499 }
500
501 pub fn get_incoming_direct_references_with_snapshot(
506 &self,
507 id: &str,
508 snapshot: &TypeArchiveSnapshotId,
509 ) -> Array<BnString> {
510 let id = id.to_cstr();
511 let snapshot = snapshot.clone().to_cstr();
512 let mut count = 0;
513 let result = unsafe {
514 BNGetTypeArchiveIncomingDirectTypeReferences(
515 self.handle.as_ptr(),
516 id.as_ptr(),
517 snapshot.as_ptr(),
518 &mut count,
519 )
520 };
521 assert!(!result.is_null());
522 unsafe { Array::new(result, count, ()) }
523 }
524
525 pub fn get_incoming_recursive_references(&self, id: &str) -> Array<BnString> {
529 self.get_incoming_recursive_references_with_snapshot(id, &TypeArchiveSnapshotId::unset())
530 }
531
532 pub fn get_incoming_recursive_references_with_snapshot(
537 &self,
538 id: &str,
539 snapshot: &TypeArchiveSnapshotId,
540 ) -> Array<BnString> {
541 let id = id.to_cstr();
542 let snapshot = snapshot.clone().to_cstr();
543 let mut count = 0;
544 let result = unsafe {
545 BNGetTypeArchiveIncomingRecursiveTypeReferences(
546 self.handle.as_ptr(),
547 id.as_ptr(),
548 snapshot.as_ptr(),
549 &mut count,
550 )
551 };
552 assert!(!result.is_null());
553 unsafe { Array::new(result, count, ()) }
554 }
555
556 pub fn query_metadata(&self, key: &str) -> Option<Ref<Metadata>> {
558 let key = key.to_cstr();
559 let result = unsafe { BNTypeArchiveQueryMetadata(self.handle.as_ptr(), key.as_ptr()) };
560 (!result.is_null()).then(|| unsafe { Metadata::ref_from_raw(result) })
561 }
562
563 pub fn store_metadata(&self, key: &str, md: &Metadata) {
568 let key = key.to_cstr();
569 let result =
570 unsafe { BNTypeArchiveStoreMetadata(self.handle.as_ptr(), key.as_ptr(), md.handle) };
571 assert!(result);
572 }
573
574 pub fn remove_metadata(&self, key: &str) -> bool {
576 let key = key.to_cstr();
577 unsafe { BNTypeArchiveRemoveMetadata(self.handle.as_ptr(), key.as_ptr()) }
578 }
579
580 pub fn serialize_snapshot(&self, snapshot: &TypeArchiveSnapshotId) -> DataBuffer {
582 let snapshot = snapshot.clone().to_cstr();
583 let result =
584 unsafe { BNTypeArchiveSerializeSnapshot(self.handle.as_ptr(), snapshot.as_ptr()) };
585 assert!(!result.is_null());
586 DataBuffer::from_raw(result)
587 }
588
589 pub fn deserialize_snapshot(&self, data: &DataBuffer) -> TypeArchiveSnapshotId {
591 let result =
592 unsafe { BNTypeArchiveDeserializeSnapshot(self.handle.as_ptr(), data.as_raw()) };
593 assert!(!result.is_null());
594 let id = unsafe { BnString::into_string(result) };
595 TypeArchiveSnapshotId(id)
596 }
597
598 pub fn register_notification_callback<T: TypeArchiveNotificationCallback>(
600 &self,
601 callback: T,
602 ) -> TypeArchiveCallbackHandle<T> {
603 let callback = Box::leak(Box::new(callback));
605 let mut notification = BNTypeArchiveNotification {
606 context: callback as *mut T as *mut c_void,
607 typeAdded: Some(cb_type_added::<T>),
608 typeUpdated: Some(cb_type_updated::<T>),
609 typeRenamed: Some(cb_type_renamed::<T>),
610 typeDeleted: Some(cb_type_deleted::<T>),
611 };
612 unsafe { BNRegisterTypeArchiveNotification(self.handle.as_ptr(), &mut notification) }
613 TypeArchiveCallbackHandle {
614 callback,
615 type_archive: self.to_owned(),
616 }
617 }
618
619 #[allow(private_interfaces)]
622 pub fn register_notification_closure<A, U, R, D>(
623 &self,
624 type_added: A,
625 type_updated: U,
626 type_renamed: R,
627 type_deleted: D,
628 ) -> TypeArchiveCallbackHandle<NotificationClosure<A, U, R, D>>
629 where
630 A: FnMut(&TypeArchive, &str, &Type),
631 U: FnMut(&TypeArchive, &str, &Type, &Type),
632 R: FnMut(&TypeArchive, &str, &QualifiedName, &QualifiedName),
633 D: FnMut(&TypeArchive, &str, &Type),
634 {
635 self.register_notification_callback(NotificationClosure {
636 fun_type_added: type_added,
637 fun_type_updated: type_updated,
638 fun_type_renamed: type_renamed,
639 fun_type_deleted: type_deleted,
640 })
641 }
642
643 pub fn close(&self) {
646 unsafe { BNCloseTypeArchive(self.handle.as_ptr()) }
647 }
648
649 pub fn is_type_archive(file: &Path) -> bool {
651 let file = file.to_cstr();
652 unsafe { BNIsTypeArchive(file.as_ptr()) }
653 }
654
655 pub fn type_container(&self) -> TypeContainer {
658 let result = unsafe { BNGetTypeArchiveTypeContainer(self.handle.as_ptr()) };
659 unsafe { TypeContainer::from_raw(NonNull::new(result).unwrap()) }
660 }
661
662 pub fn new_snapshot_transaction<F>(
670 &self,
671 mut function: F,
672 parents: &[TypeArchiveSnapshotId],
673 ) -> TypeArchiveSnapshotId
674 where
675 F: FnMut(&TypeArchiveSnapshotId) -> bool,
676 {
677 unsafe extern "C" fn cb_callback<F: FnMut(&TypeArchiveSnapshotId) -> bool>(
678 ctxt: *mut c_void,
679 id: *const c_char,
680 ) -> bool {
681 let fun: &mut F = &mut *(ctxt as *mut F);
682 let id_str = raw_to_string(id).unwrap();
683 fun(&TypeArchiveSnapshotId(id_str))
684 }
685
686 let parents_cstr: Vec<_> = parents.iter().map(|p| p.clone().to_cstr()).collect();
687 let parents_raw: Vec<_> = parents_cstr.iter().map(|p| p.as_ptr()).collect();
688 let result = unsafe {
689 BNTypeArchiveNewSnapshotTransaction(
690 self.handle.as_ptr(),
691 Some(cb_callback::<F>),
692 &mut function as *mut F as *mut c_void,
693 parents_raw.as_ptr(),
694 parents.len(),
695 )
696 };
697 assert!(!result.is_null());
698 let id_str = unsafe { BnString::into_string(result) };
699 TypeArchiveSnapshotId(id_str)
700 }
701
702 pub fn merge_snapshots<M>(
713 &self,
714 base_snapshot: &str,
715 first_snapshot: &str,
716 second_snapshot: &str,
717 merge_conflicts: M,
718 ) -> Result<BnString, Array<BnString>>
719 where
720 M: IntoIterator<Item = (String, String)>,
721 {
722 self.merge_snapshots_with_progress(
723 base_snapshot,
724 first_snapshot,
725 second_snapshot,
726 merge_conflicts,
727 NoProgressCallback,
728 )
729 }
730
731 pub fn merge_snapshots_with_progress<M, PC>(
742 &self,
743 base_snapshot: &str,
744 first_snapshot: &str,
745 second_snapshot: &str,
746 merge_conflicts: M,
747 mut progress: PC,
748 ) -> Result<BnString, Array<BnString>>
749 where
750 M: IntoIterator<Item = (String, String)>,
751 PC: ProgressCallback,
752 {
753 let base_snapshot = base_snapshot.to_cstr();
754 let first_snapshot = first_snapshot.to_cstr();
755 let second_snapshot = second_snapshot.to_cstr();
756 let (merge_keys, merge_values): (Vec<BnString>, Vec<BnString>) = merge_conflicts
757 .into_iter()
758 .map(|(k, v)| (BnString::new(k), BnString::new(v)))
759 .unzip();
760 let merge_keys_raw = merge_keys.as_ptr() as *const *const c_char;
762 let merge_values_raw = merge_values.as_ptr() as *const *const c_char;
763
764 let mut conflicts_errors = std::ptr::null_mut();
765 let mut conflicts_errors_count = 0;
766
767 let mut result = std::ptr::null_mut();
768
769 let success = unsafe {
770 BNTypeArchiveMergeSnapshots(
771 self.handle.as_ptr(),
772 base_snapshot.as_ptr(),
773 first_snapshot.as_ptr(),
774 second_snapshot.as_ptr(),
775 merge_keys_raw,
776 merge_values_raw,
777 merge_keys.len(),
778 &mut conflicts_errors,
779 &mut conflicts_errors_count,
780 &mut result,
781 Some(PC::cb_progress_callback),
782 &mut progress as *mut PC as *mut c_void,
783 )
784 };
785
786 if success {
787 assert!(!result.is_null());
788 Ok(unsafe { BnString::from_raw(result) })
789 } else {
790 assert!(!conflicts_errors.is_null());
791 Err(unsafe { Array::new(conflicts_errors, conflicts_errors_count, ()) })
792 }
793 }
794}
795
796impl ToOwned for TypeArchive {
797 type Owned = Ref<Self>;
798
799 fn to_owned(&self) -> Self::Owned {
800 unsafe { RefCountable::inc_ref(self) }
801 }
802}
803
804unsafe impl RefCountable for TypeArchive {
805 unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
806 Ref::new(Self {
807 handle: NonNull::new(BNNewTypeArchiveReference(handle.handle.as_ptr())).unwrap(),
808 })
809 }
810
811 unsafe fn dec_ref(handle: &Self) {
812 BNFreeTypeArchiveReference(handle.handle.as_ptr());
813 }
814}
815
816impl PartialEq for TypeArchive {
817 fn eq(&self, other: &Self) -> bool {
818 self.id() == other.id()
819 }
820}
821impl Eq for TypeArchive {}
822
823impl Hash for TypeArchive {
824 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
825 self.id().hash(state);
826 }
827}
828
829impl Debug for TypeArchive {
830 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
831 f.debug_struct("TypeArchive")
832 .field("id", &self.id())
833 .field("path", &self.path())
834 .field("current_snapshot_id", &self.current_snapshot_id())
835 .field("platform", &self.platform())
836 .finish()
837 }
838}
839
840impl CoreArrayProvider for TypeArchive {
841 type Raw = *mut BNTypeArchive;
842 type Context = ();
843 type Wrapped<'a> = Guard<'a, TypeArchive>;
844}
845
846unsafe impl CoreArrayProviderInner for TypeArchive {
847 unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
848 BNFreeTypeArchiveList(raw, count)
849 }
850
851 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
852 let raw_ptr = NonNull::new(*raw).unwrap();
853 Guard::new(Self::from_raw(raw_ptr), context)
854 }
855}
856
857pub struct TypeArchiveCallbackHandle<T: TypeArchiveNotificationCallback> {
858 callback: *mut T,
859 type_archive: Ref<TypeArchive>,
860}
861
862impl<T: TypeArchiveNotificationCallback> Drop for TypeArchiveCallbackHandle<T> {
863 fn drop(&mut self) {
864 let mut notification = BNTypeArchiveNotification {
865 context: self.callback as *mut c_void,
866 typeAdded: Some(cb_type_added::<T>),
867 typeUpdated: Some(cb_type_updated::<T>),
868 typeRenamed: Some(cb_type_renamed::<T>),
869 typeDeleted: Some(cb_type_deleted::<T>),
870 };
871 unsafe {
873 BNUnregisterTypeArchiveNotification(
874 self.type_archive.handle.as_ptr(),
875 &mut notification,
876 )
877 }
878 drop(unsafe { Box::from_raw(self.callback) });
880 }
881}
882
883pub trait TypeArchiveNotificationCallback {
884 fn type_added(&mut self, _archive: &TypeArchive, _id: &str, _definition: &Type) {}
890
891 fn type_updated(
898 &mut self,
899 _archive: &TypeArchive,
900 _id: &str,
901 _old_definition: &Type,
902 _new_definition: &Type,
903 ) {
904 }
905
906 fn type_renamed(
913 &mut self,
914 _archive: &TypeArchive,
915 _id: &str,
916 _old_name: &QualifiedName,
917 _new_name: &QualifiedName,
918 ) {
919 }
920
921 fn type_deleted(&mut self, _archive: &TypeArchive, _id: &str, _definition: &Type) {}
927}
928
929struct NotificationClosure<A, U, R, D>
930where
931 A: FnMut(&TypeArchive, &str, &Type),
932 U: FnMut(&TypeArchive, &str, &Type, &Type),
933 R: FnMut(&TypeArchive, &str, &QualifiedName, &QualifiedName),
934 D: FnMut(&TypeArchive, &str, &Type),
935{
936 fun_type_added: A,
937 fun_type_updated: U,
938 fun_type_renamed: R,
939 fun_type_deleted: D,
940}
941
942impl<A, U, R, D> TypeArchiveNotificationCallback for NotificationClosure<A, U, R, D>
943where
944 A: FnMut(&TypeArchive, &str, &Type),
945 U: FnMut(&TypeArchive, &str, &Type, &Type),
946 R: FnMut(&TypeArchive, &str, &QualifiedName, &QualifiedName),
947 D: FnMut(&TypeArchive, &str, &Type),
948{
949 fn type_added(&mut self, archive: &TypeArchive, id: &str, definition: &Type) {
950 (self.fun_type_added)(archive, id, definition)
951 }
952
953 fn type_updated(
954 &mut self,
955 archive: &TypeArchive,
956 id: &str,
957 old_definition: &Type,
958 new_definition: &Type,
959 ) {
960 (self.fun_type_updated)(archive, id, old_definition, new_definition)
961 }
962
963 fn type_renamed(
964 &mut self,
965 archive: &TypeArchive,
966 id: &str,
967 old_name: &QualifiedName,
968 new_name: &QualifiedName,
969 ) {
970 (self.fun_type_renamed)(archive, id, old_name, new_name)
971 }
972
973 fn type_deleted(&mut self, archive: &TypeArchive, id: &str, definition: &Type) {
974 (self.fun_type_deleted)(archive, id, definition)
975 }
976}
977
978unsafe extern "C" fn cb_type_added<T: TypeArchiveNotificationCallback>(
979 ctxt: *mut ::std::os::raw::c_void,
980 archive: *mut BNTypeArchive,
981 id: *const ::std::os::raw::c_char,
982 definition: *mut BNType,
983) {
984 let ctxt: &mut T = &mut *(ctxt as *mut T);
985 let archive = unsafe { TypeArchive::from_raw(NonNull::new(archive).unwrap()) };
987 ctxt.type_added(
988 &archive,
989 unsafe { CStr::from_ptr(id).to_string_lossy().as_ref() },
990 &Type { handle: definition },
991 )
992}
993unsafe extern "C" fn cb_type_updated<T: TypeArchiveNotificationCallback>(
994 ctxt: *mut ::std::os::raw::c_void,
995 archive: *mut BNTypeArchive,
996 id: *const ::std::os::raw::c_char,
997 old_definition: *mut BNType,
998 new_definition: *mut BNType,
999) {
1000 let ctxt: &mut T = &mut *(ctxt as *mut T);
1001 let archive = unsafe { TypeArchive::from_raw(NonNull::new(archive).unwrap()) };
1003 ctxt.type_updated(
1004 &archive,
1005 unsafe { CStr::from_ptr(id).to_string_lossy().as_ref() },
1006 &Type {
1007 handle: old_definition,
1008 },
1009 &Type {
1010 handle: new_definition,
1011 },
1012 )
1013}
1014unsafe extern "C" fn cb_type_renamed<T: TypeArchiveNotificationCallback>(
1015 ctxt: *mut ::std::os::raw::c_void,
1016 archive: *mut BNTypeArchive,
1017 id: *const ::std::os::raw::c_char,
1018 old_name: *const BNQualifiedName,
1019 new_name: *const BNQualifiedName,
1020) {
1021 let ctxt: &mut T = &mut *(ctxt as *mut T);
1022 let old_name = QualifiedName::from_raw(&*old_name);
1024 let new_name = QualifiedName::from_raw(&*new_name);
1026 let archive = unsafe { TypeArchive::from_raw(NonNull::new(archive).unwrap()) };
1028 ctxt.type_renamed(
1029 &archive,
1030 unsafe { CStr::from_ptr(id).to_string_lossy().as_ref() },
1031 &old_name,
1032 &new_name,
1033 )
1034}
1035unsafe extern "C" fn cb_type_deleted<T: TypeArchiveNotificationCallback>(
1036 ctxt: *mut ::std::os::raw::c_void,
1037 archive: *mut BNTypeArchive,
1038 id: *const ::std::os::raw::c_char,
1039 definition: *mut BNType,
1040) {
1041 let ctxt: &mut T = &mut *(ctxt as *mut T);
1042 let archive = unsafe { TypeArchive::from_raw(NonNull::new(archive).unwrap()) };
1044 ctxt.type_deleted(
1045 &archive,
1046 unsafe { CStr::from_ptr(id).to_string_lossy().as_ref() },
1047 &Type { handle: definition },
1048 )
1049}
1050
1051#[repr(transparent)]
1052pub struct TypeArchiveMergeConflict {
1053 handle: NonNull<BNTypeArchiveMergeConflict>,
1054}
1055
1056impl TypeArchiveMergeConflict {
1057 pub(crate) unsafe fn from_raw(handle: NonNull<BNTypeArchiveMergeConflict>) -> Self {
1058 Self { handle }
1059 }
1060
1061 #[allow(unused)]
1062 pub(crate) unsafe fn ref_from_raw(handle: NonNull<BNTypeArchiveMergeConflict>) -> Ref<Self> {
1063 Ref::new(Self { handle })
1064 }
1065
1066 pub fn get_type_archive(&self) -> Option<Ref<TypeArchive>> {
1067 let value = unsafe { BNTypeArchiveMergeConflictGetTypeArchive(self.handle.as_ptr()) };
1068 NonNull::new(value).map(|handle| unsafe { TypeArchive::ref_from_raw(handle) })
1069 }
1070
1071 pub fn type_id(&self) -> String {
1072 let value = unsafe { BNTypeArchiveMergeConflictGetTypeId(self.handle.as_ptr()) };
1073 assert!(!value.is_null());
1074 unsafe { BnString::into_string(value) }
1075 }
1076
1077 pub fn base_snapshot_id(&self) -> TypeArchiveSnapshotId {
1078 let value = unsafe { BNTypeArchiveMergeConflictGetBaseSnapshotId(self.handle.as_ptr()) };
1079 assert!(!value.is_null());
1080 let id = unsafe { BnString::into_string(value) };
1081 TypeArchiveSnapshotId(id)
1082 }
1083
1084 pub fn first_snapshot_id(&self) -> TypeArchiveSnapshotId {
1085 let value = unsafe { BNTypeArchiveMergeConflictGetFirstSnapshotId(self.handle.as_ptr()) };
1086 assert!(!value.is_null());
1087 let id = unsafe { BnString::into_string(value) };
1088 TypeArchiveSnapshotId(id)
1089 }
1090
1091 pub fn second_snapshot_id(&self) -> TypeArchiveSnapshotId {
1092 let value = unsafe { BNTypeArchiveMergeConflictGetSecondSnapshotId(self.handle.as_ptr()) };
1093 assert!(!value.is_null());
1094 let id = unsafe { BnString::into_string(value) };
1095 TypeArchiveSnapshotId(id)
1096 }
1097
1098 pub fn success(&self, result: &str) -> bool {
1100 let result = result.to_cstr();
1101 unsafe { BNTypeArchiveMergeConflictSuccess(self.handle.as_ptr(), result.as_ptr()) }
1102 }
1103}
1104
1105impl Debug for TypeArchiveMergeConflict {
1106 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1107 f.debug_struct("TypeArchiveMergeConflict")
1108 .field("type_id", &self.type_id())
1109 .field("base_snapshot_id", &self.base_snapshot_id())
1110 .field("first_snapshot_id", &self.first_snapshot_id())
1111 .field("second_snapshot_id", &self.second_snapshot_id())
1112 .finish()
1113 }
1114}
1115
1116impl ToOwned for TypeArchiveMergeConflict {
1117 type Owned = Ref<Self>;
1118
1119 fn to_owned(&self) -> Self::Owned {
1120 unsafe { RefCountable::inc_ref(self) }
1121 }
1122}
1123
1124unsafe impl RefCountable for TypeArchiveMergeConflict {
1125 unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
1126 Ref::new(Self {
1127 handle: NonNull::new(BNNewTypeArchiveMergeConflictReference(
1128 handle.handle.as_ptr(),
1129 ))
1130 .unwrap(),
1131 })
1132 }
1133
1134 unsafe fn dec_ref(handle: &Self) {
1135 BNFreeTypeArchiveMergeConflict(handle.handle.as_ptr());
1136 }
1137}
1138
1139impl CoreArrayProvider for TypeArchiveMergeConflict {
1140 type Raw = *mut BNTypeArchiveMergeConflict;
1141 type Context = ();
1142 type Wrapped<'a> = Guard<'a, Self>;
1143}
1144
1145unsafe impl CoreArrayProviderInner for TypeArchiveMergeConflict {
1146 unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
1147 BNFreeTypeArchiveMergeConflictList(raw, count)
1148 }
1149
1150 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
1151 let raw_ptr = NonNull::new(*raw).unwrap();
1152 Guard::new(Self::from_raw(raw_ptr), context)
1153 }
1154}