1use crate::progress::{NoProgressCallback, ProgressCallback};
2use binaryninjacore_sys::*;
3use std::ffi::{c_char, c_void, CStr, CString};
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::types::{
15 QualifiedName, QualifiedNameAndType, QualifiedNameTypeAndId, Type, TypeContainer,
16};
17
18#[repr(transparent)]
19#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
20pub struct TypeArchiveId(pub String);
21
22impl Display for TypeArchiveId {
23 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
24 f.write_fmt(format_args!("{}", self.0))
25 }
26}
27
28#[repr(transparent)]
29#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
30pub struct TypeArchiveSnapshotId(pub String);
31
32impl TypeArchiveSnapshotId {
33 pub fn unset() -> Self {
34 Self("".to_string())
35 }
36}
37
38impl Display for TypeArchiveSnapshotId {
39 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
40 f.write_fmt(format_args!("{}", self.0))
41 }
42}
43
44impl CoreArrayProvider for TypeArchiveSnapshotId {
45 type Raw = *mut c_char;
46 type Context = ();
47 type Wrapped<'a> = TypeArchiveSnapshotId;
48}
49
50unsafe impl CoreArrayProviderInner for TypeArchiveSnapshotId {
51 unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
52 BNFreeStringList(raw, count)
53 }
54
55 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
56 let str = CStr::from_ptr(*raw).to_str().unwrap().to_string();
57 TypeArchiveSnapshotId(str)
58 }
59}
60
61impl IntoCStr for TypeArchiveSnapshotId {
62 type Result = CString;
63
64 fn to_cstr(self) -> Self::Result {
65 self.to_string().to_cstr()
66 }
67}
68
69pub struct TypeArchive {
73 pub(crate) handle: NonNull<BNTypeArchive>,
74}
75
76impl TypeArchive {
77 pub(crate) unsafe fn from_raw(handle: NonNull<BNTypeArchive>) -> Self {
78 Self { handle }
79 }
80
81 pub(crate) unsafe fn ref_from_raw(handle: NonNull<BNTypeArchive>) -> Ref<Self> {
82 Ref::new(Self { handle })
83 }
84
85 pub fn open(path: impl AsRef<Path>) -> Option<Ref<TypeArchive>> {
87 let raw_path = path.as_ref().to_cstr();
88 let handle = unsafe { BNOpenTypeArchive(raw_path.as_ptr()) };
89 NonNull::new(handle).map(|handle| unsafe { TypeArchive::ref_from_raw(handle) })
90 }
91
92 pub fn create(path: impl AsRef<Path>, platform: &Platform) -> Option<Ref<TypeArchive>> {
96 let raw_path = path.as_ref().to_cstr();
97 let handle = unsafe { BNCreateTypeArchive(raw_path.as_ptr(), platform.handle) };
98 NonNull::new(handle).map(|handle| unsafe { TypeArchive::ref_from_raw(handle) })
99 }
100
101 pub fn create_with_id(
105 path: impl AsRef<Path>,
106 id: &TypeArchiveId,
107 platform: &Platform,
108 ) -> Option<Ref<TypeArchive>> {
109 let raw_path = path.as_ref().to_cstr();
110 let id = id.0.as_str().to_cstr();
111 let handle =
112 unsafe { BNCreateTypeArchiveWithId(raw_path.as_ptr(), platform.handle, id.as_ptr()) };
113 NonNull::new(handle).map(|handle| unsafe { TypeArchive::ref_from_raw(handle) })
114 }
115
116 pub fn lookup_by_id(id: &TypeArchiveId) -> Option<Ref<TypeArchive>> {
118 let id = id.0.as_str().to_cstr();
119 let handle = unsafe { BNLookupTypeArchiveById(id.as_ptr()) };
120 NonNull::new(handle).map(|handle| unsafe { TypeArchive::ref_from_raw(handle) })
121 }
122
123 pub fn path(&self) -> Option<PathBuf> {
125 let result = unsafe { BNGetTypeArchivePath(self.handle.as_ptr()) };
126 assert!(!result.is_null());
127 let path_str = unsafe { BnString::into_string(result) };
128 Some(PathBuf::from(path_str))
129 }
130
131 pub fn id(&self) -> TypeArchiveId {
133 let result = unsafe { BNGetTypeArchiveId(self.handle.as_ptr()) };
134 assert!(!result.is_null());
135 let result_str = unsafe { BnString::from_raw(result) };
136 TypeArchiveId(result_str.to_string_lossy().to_string())
137 }
138
139 pub fn platform(&self) -> Ref<Platform> {
141 let result = unsafe { BNGetTypeArchivePlatform(self.handle.as_ptr()) };
142 assert!(!result.is_null());
143 unsafe { Platform::ref_from_raw(result) }
144 }
145
146 pub fn current_snapshot_id(&self) -> TypeArchiveSnapshotId {
148 let result = unsafe { BNGetTypeArchiveCurrentSnapshotId(self.handle.as_ptr()) };
149 assert!(!result.is_null());
150 let id = unsafe { BnString::into_string(result) };
151 TypeArchiveSnapshotId(id)
152 }
153
154 pub fn set_current_snapshot_id(&self, id: &TypeArchiveSnapshotId) {
156 let snapshot = id.clone().to_cstr();
157 unsafe { BNSetTypeArchiveCurrentSnapshot(self.handle.as_ptr(), snapshot.as_ptr()) }
158 }
159
160 pub fn all_snapshot_ids(&self) -> Array<TypeArchiveSnapshotId> {
162 let mut count = 0;
163 let result = unsafe { BNGetTypeArchiveAllSnapshotIds(self.handle.as_ptr(), &mut count) };
164 assert!(!result.is_null());
165 unsafe { Array::new(result, count, ()) }
166 }
167
168 pub fn get_snapshot_parent_ids(
170 &self,
171 snapshot: &TypeArchiveSnapshotId,
172 ) -> Option<Array<BnString>> {
173 let mut count = 0;
174 let snapshot = snapshot.clone().to_cstr();
175 let result = unsafe {
176 BNGetTypeArchiveSnapshotParentIds(self.handle.as_ptr(), snapshot.as_ptr(), &mut count)
177 };
178 (!result.is_null()).then(|| unsafe { Array::new(result, count, ()) })
179 }
180
181 pub fn get_snapshot_child_ids(
183 &self,
184 snapshot: &TypeArchiveSnapshotId,
185 ) -> Option<Array<BnString>> {
186 let mut count = 0;
187 let snapshot = snapshot.clone().to_cstr();
188 let result = unsafe {
189 BNGetTypeArchiveSnapshotChildIds(self.handle.as_ptr(), snapshot.as_ptr(), &mut count)
190 };
191 (!result.is_null()).then(|| unsafe { Array::new(result, count, ()) })
192 }
193
194 pub fn add_type(&self, named_type: QualifiedNameAndType) -> bool {
200 self.add_types(vec![named_type])
201 }
202
203 pub fn add_types(&self, named_types: Vec<QualifiedNameAndType>) -> bool {
209 let new_types_raw: Vec<_> = named_types
210 .into_iter()
211 .map(QualifiedNameAndType::into_raw)
212 .collect();
213 let result = unsafe {
214 BNAddTypeArchiveTypes(
215 self.handle.as_ptr(),
216 new_types_raw.as_ptr(),
217 new_types_raw.len(),
218 )
219 };
220 for new_type in new_types_raw {
221 QualifiedNameAndType::free_raw(new_type);
222 }
223 result
224 }
225
226 pub fn rename_type(&self, old_name: QualifiedName, new_name: QualifiedName) -> bool {
231 if let Some(id) = self.get_type_id(old_name) {
232 self.rename_type_by_id(&id, new_name)
233 } else {
234 false
235 }
236 }
237
238 pub fn rename_type_by_id(&self, id: &str, new_name: QualifiedName) -> bool {
243 let id = id.to_cstr();
244 let raw_name = QualifiedName::into_raw(new_name);
245 let result =
246 unsafe { BNRenameTypeArchiveType(self.handle.as_ptr(), id.as_ptr(), &raw_name) };
247 QualifiedName::free_raw(raw_name);
248 result
249 }
250
251 pub fn delete_type(&self, name: QualifiedName) -> bool {
253 if let Some(type_id) = self.get_type_id(name) {
254 self.delete_type_by_id(&type_id)
255 } else {
256 false
257 }
258 }
259
260 pub fn delete_type_by_id(&self, id: &str) -> bool {
262 let id = id.to_cstr();
263 unsafe { BNDeleteTypeArchiveType(self.handle.as_ptr(), id.as_ptr()) }
264 }
265
266 pub fn get_type_by_name(&self, name: QualifiedName) -> Option<Ref<Type>> {
270 self.get_type_by_name_from_snapshot(name, &TypeArchiveSnapshotId::unset())
271 }
272
273 pub fn get_type_by_name_from_snapshot(
278 &self,
279 name: QualifiedName,
280 snapshot: &TypeArchiveSnapshotId,
281 ) -> Option<Ref<Type>> {
282 let raw_name = QualifiedName::into_raw(name);
283 let snapshot = snapshot.clone().to_cstr();
284 let result = unsafe {
285 BNGetTypeArchiveTypeByName(self.handle.as_ptr(), &raw_name, snapshot.as_ptr())
286 };
287 QualifiedName::free_raw(raw_name);
288 (!result.is_null()).then(|| unsafe { Type::ref_from_raw(result) })
289 }
290
291 pub fn get_type_by_id(&self, id: &str) -> Option<Ref<Type>> {
295 self.get_type_by_id_from_snapshot(id, &TypeArchiveSnapshotId::unset())
296 }
297
298 pub fn get_type_by_id_from_snapshot(
303 &self,
304 id: &str,
305 snapshot: &TypeArchiveSnapshotId,
306 ) -> Option<Ref<Type>> {
307 let id = id.to_cstr();
308 let snapshot = snapshot.clone().to_cstr();
309 let result = unsafe {
310 BNGetTypeArchiveTypeById(self.handle.as_ptr(), id.as_ptr(), snapshot.as_ptr())
311 };
312 (!result.is_null()).then(|| unsafe { Type::ref_from_raw(result) })
313 }
314
315 pub fn get_type_name_by_id(&self, id: &str) -> QualifiedName {
319 self.get_type_name_by_id_from_snapshot(id, &TypeArchiveSnapshotId::unset())
320 }
321
322 pub fn get_type_name_by_id_from_snapshot(
327 &self,
328 id: &str,
329 snapshot: &TypeArchiveSnapshotId,
330 ) -> QualifiedName {
331 let id = id.to_cstr();
332 let snapshot = snapshot.clone().to_cstr();
333 let result = unsafe {
334 BNGetTypeArchiveTypeName(self.handle.as_ptr(), id.as_ptr(), snapshot.as_ptr())
335 };
336 QualifiedName::from_owned_raw(result)
337 }
338
339 pub fn get_type_id(&self, name: QualifiedName) -> Option<String> {
343 self.get_type_id_from_snapshot(name, &TypeArchiveSnapshotId::unset())
344 }
345
346 pub fn get_type_id_from_snapshot(
351 &self,
352 name: QualifiedName,
353 snapshot: &TypeArchiveSnapshotId,
354 ) -> Option<String> {
355 let raw_name = QualifiedName::into_raw(name);
356 let snapshot = snapshot.clone().to_cstr();
357 let result =
358 unsafe { BNGetTypeArchiveTypeId(self.handle.as_ptr(), &raw_name, snapshot.as_ptr()) };
359 QualifiedName::free_raw(raw_name);
360 (!result.is_null()).then(|| unsafe { BnString::into_string(result) })
361 }
362
363 pub fn get_types_and_ids(&self) -> Array<QualifiedNameTypeAndId> {
365 self.get_types_and_ids_from_snapshot(&TypeArchiveSnapshotId::unset())
366 }
367
368 pub fn get_types_and_ids_from_snapshot(
372 &self,
373 snapshot: &TypeArchiveSnapshotId,
374 ) -> Array<QualifiedNameTypeAndId> {
375 let mut count = 0;
376 let snapshot = snapshot.clone().to_cstr();
377 let result =
378 unsafe { BNGetTypeArchiveTypes(self.handle.as_ptr(), snapshot.as_ptr(), &mut count) };
379 assert!(!result.is_null());
380 unsafe { Array::new(result, count, ()) }
381 }
382
383 pub fn get_type_ids(&self) -> Array<BnString> {
385 self.get_type_ids_from_snapshot(&TypeArchiveSnapshotId::unset())
386 }
387
388 pub fn get_type_ids_from_snapshot(&self, snapshot: &TypeArchiveSnapshotId) -> Array<BnString> {
392 let mut count = 0;
393 let snapshot = snapshot.clone().to_cstr();
394 let result =
395 unsafe { BNGetTypeArchiveTypeIds(self.handle.as_ptr(), snapshot.as_ptr(), &mut count) };
396 assert!(!result.is_null());
397 unsafe { Array::new(result, count, ()) }
398 }
399
400 pub fn get_type_names(&self) -> Array<QualifiedName> {
402 self.get_type_names_from_snapshot(&TypeArchiveSnapshotId::unset())
403 }
404
405 pub fn get_type_names_from_snapshot(
409 &self,
410 snapshot: &TypeArchiveSnapshotId,
411 ) -> Array<QualifiedName> {
412 let mut count = 0;
413 let snapshot = snapshot.clone().to_cstr();
414 let result = unsafe {
415 BNGetTypeArchiveTypeNames(self.handle.as_ptr(), snapshot.as_ptr(), &mut count)
416 };
417 assert!(!result.is_null());
418 unsafe { Array::new(result, count, ()) }
419 }
420
421 pub fn get_type_names_and_ids(&self) -> (Array<QualifiedName>, Array<BnString>) {
423 self.get_type_names_and_ids_from_snapshot(&TypeArchiveSnapshotId::unset())
424 }
425
426 pub fn get_type_names_and_ids_from_snapshot(
430 &self,
431 snapshot: &TypeArchiveSnapshotId,
432 ) -> (Array<QualifiedName>, Array<BnString>) {
433 let mut count = 0;
434 let snapshot = snapshot.clone().to_cstr();
435 let mut names = std::ptr::null_mut();
436 let mut ids = std::ptr::null_mut();
437 let result = unsafe {
438 BNGetTypeArchiveTypeNamesAndIds(
439 self.handle.as_ptr(),
440 snapshot.as_ptr(),
441 &mut names,
442 &mut ids,
443 &mut count,
444 )
445 };
446 assert!(result);
447 (unsafe { Array::new(names, count, ()) }, unsafe {
448 Array::new(ids, count, ())
449 })
450 }
451
452 pub fn get_outgoing_direct_references(&self, id: &str) -> Array<BnString> {
456 self.get_outgoing_direct_references_from_snapshot(id, &TypeArchiveSnapshotId::unset())
457 }
458
459 pub fn get_outgoing_direct_references_from_snapshot(
464 &self,
465 id: &str,
466 snapshot: &TypeArchiveSnapshotId,
467 ) -> Array<BnString> {
468 let id = id.to_cstr();
469 let snapshot = snapshot.clone().to_cstr();
470 let mut count = 0;
471 let result = unsafe {
472 BNGetTypeArchiveOutgoingDirectTypeReferences(
473 self.handle.as_ptr(),
474 id.as_ptr(),
475 snapshot.as_ptr(),
476 &mut count,
477 )
478 };
479 assert!(!result.is_null());
480 unsafe { Array::new(result, count, ()) }
481 }
482
483 pub fn get_outgoing_recursive_references(&self, id: &str) -> Array<BnString> {
487 self.get_outgoing_recursive_references_from_snapshot(id, &TypeArchiveSnapshotId::unset())
488 }
489
490 pub fn get_outgoing_recursive_references_from_snapshot(
495 &self,
496 id: &str,
497 snapshot: &TypeArchiveSnapshotId,
498 ) -> Array<BnString> {
499 let id = id.to_cstr();
500 let snapshot = snapshot.clone().to_cstr();
501 let mut count = 0;
502 let result = unsafe {
503 BNGetTypeArchiveOutgoingRecursiveTypeReferences(
504 self.handle.as_ptr(),
505 id.as_ptr(),
506 snapshot.as_ptr(),
507 &mut count,
508 )
509 };
510 assert!(!result.is_null());
511 unsafe { Array::new(result, count, ()) }
512 }
513
514 pub fn get_incoming_direct_references(&self, id: &str) -> Array<BnString> {
518 self.get_incoming_direct_references_with_snapshot(id, &TypeArchiveSnapshotId::unset())
519 }
520
521 pub fn get_incoming_direct_references_with_snapshot(
526 &self,
527 id: &str,
528 snapshot: &TypeArchiveSnapshotId,
529 ) -> Array<BnString> {
530 let id = id.to_cstr();
531 let snapshot = snapshot.clone().to_cstr();
532 let mut count = 0;
533 let result = unsafe {
534 BNGetTypeArchiveIncomingDirectTypeReferences(
535 self.handle.as_ptr(),
536 id.as_ptr(),
537 snapshot.as_ptr(),
538 &mut count,
539 )
540 };
541 assert!(!result.is_null());
542 unsafe { Array::new(result, count, ()) }
543 }
544
545 pub fn get_incoming_recursive_references(&self, id: &str) -> Array<BnString> {
549 self.get_incoming_recursive_references_with_snapshot(id, &TypeArchiveSnapshotId::unset())
550 }
551
552 pub fn get_incoming_recursive_references_with_snapshot(
557 &self,
558 id: &str,
559 snapshot: &TypeArchiveSnapshotId,
560 ) -> Array<BnString> {
561 let id = id.to_cstr();
562 let snapshot = snapshot.clone().to_cstr();
563 let mut count = 0;
564 let result = unsafe {
565 BNGetTypeArchiveIncomingRecursiveTypeReferences(
566 self.handle.as_ptr(),
567 id.as_ptr(),
568 snapshot.as_ptr(),
569 &mut count,
570 )
571 };
572 assert!(!result.is_null());
573 unsafe { Array::new(result, count, ()) }
574 }
575
576 pub fn query_metadata(&self, key: &str) -> Option<Ref<Metadata>> {
578 let key = key.to_cstr();
579 let result = unsafe { BNTypeArchiveQueryMetadata(self.handle.as_ptr(), key.as_ptr()) };
580 (!result.is_null()).then(|| unsafe { Metadata::ref_from_raw(result) })
581 }
582
583 pub fn store_metadata(&self, key: &str, md: &Metadata) {
588 let key = key.to_cstr();
589 let result =
590 unsafe { BNTypeArchiveStoreMetadata(self.handle.as_ptr(), key.as_ptr(), md.handle) };
591 assert!(result);
592 }
593
594 pub fn remove_metadata(&self, key: &str) -> bool {
596 let key = key.to_cstr();
597 unsafe { BNTypeArchiveRemoveMetadata(self.handle.as_ptr(), key.as_ptr()) }
598 }
599
600 pub fn serialize_snapshot(&self, snapshot: &TypeArchiveSnapshotId) -> DataBuffer {
602 let snapshot = snapshot.clone().to_cstr();
603 let result =
604 unsafe { BNTypeArchiveSerializeSnapshot(self.handle.as_ptr(), snapshot.as_ptr()) };
605 assert!(!result.is_null());
606 DataBuffer::from_raw(result)
607 }
608
609 pub fn deserialize_snapshot(&self, data: &DataBuffer) -> TypeArchiveSnapshotId {
611 let result =
612 unsafe { BNTypeArchiveDeserializeSnapshot(self.handle.as_ptr(), data.as_raw()) };
613 assert!(!result.is_null());
614 let id = unsafe { BnString::into_string(result) };
615 TypeArchiveSnapshotId(id)
616 }
617
618 pub fn register_notification_callback<T: TypeArchiveNotificationCallback>(
620 &self,
621 callback: T,
622 ) -> TypeArchiveCallbackHandle<T> {
623 let callback = Box::leak(Box::new(callback));
625 let mut notification = BNTypeArchiveNotification {
626 context: callback as *mut T as *mut c_void,
627 typeAdded: Some(cb_type_added::<T>),
628 typeUpdated: Some(cb_type_updated::<T>),
629 typeRenamed: Some(cb_type_renamed::<T>),
630 typeDeleted: Some(cb_type_deleted::<T>),
631 };
632 unsafe { BNRegisterTypeArchiveNotification(self.handle.as_ptr(), &mut notification) }
633 TypeArchiveCallbackHandle {
634 callback,
635 type_archive: self.to_owned(),
636 }
637 }
638
639 #[allow(private_interfaces)]
642 pub fn register_notification_closure<A, U, R, D>(
643 &self,
644 type_added: A,
645 type_updated: U,
646 type_renamed: R,
647 type_deleted: D,
648 ) -> TypeArchiveCallbackHandle<NotificationClosure<A, U, R, D>>
649 where
650 A: FnMut(&TypeArchive, &str, &Type),
651 U: FnMut(&TypeArchive, &str, &Type, &Type),
652 R: FnMut(&TypeArchive, &str, &QualifiedName, &QualifiedName),
653 D: FnMut(&TypeArchive, &str, &Type),
654 {
655 self.register_notification_callback(NotificationClosure {
656 fun_type_added: type_added,
657 fun_type_updated: type_updated,
658 fun_type_renamed: type_renamed,
659 fun_type_deleted: type_deleted,
660 })
661 }
662
663 pub fn close(&self) {
666 unsafe { BNCloseTypeArchive(self.handle.as_ptr()) }
667 }
668
669 pub fn is_type_archive(file: &Path) -> bool {
671 let file = file.to_cstr();
672 unsafe { BNIsTypeArchive(file.as_ptr()) }
673 }
674
675 pub fn type_container(&self) -> TypeContainer {
678 let result = unsafe { BNGetTypeArchiveTypeContainer(self.handle.as_ptr()) };
679 unsafe { TypeContainer::from_raw(NonNull::new(result).unwrap()) }
680 }
681
682 pub fn new_snapshot_transaction<F>(
690 &self,
691 mut function: F,
692 parents: &[TypeArchiveSnapshotId],
693 ) -> TypeArchiveSnapshotId
694 where
695 F: FnMut(&TypeArchiveSnapshotId) -> bool,
696 {
697 unsafe extern "C" fn cb_callback<F: FnMut(&TypeArchiveSnapshotId) -> bool>(
698 ctxt: *mut c_void,
699 id: *const c_char,
700 ) -> bool {
701 let fun: &mut F = &mut *(ctxt as *mut F);
702 let id_str = raw_to_string(id).unwrap();
703 fun(&TypeArchiveSnapshotId(id_str))
704 }
705
706 let parents_cstr: Vec<_> = parents.iter().map(|p| p.clone().to_cstr()).collect();
707 let parents_raw: Vec<_> = parents_cstr.iter().map(|p| p.as_ptr()).collect();
708 let result = unsafe {
709 BNTypeArchiveNewSnapshotTransaction(
710 self.handle.as_ptr(),
711 Some(cb_callback::<F>),
712 &mut function as *mut F as *mut c_void,
713 parents_raw.as_ptr(),
714 parents.len(),
715 )
716 };
717 assert!(!result.is_null());
718 let id_str = unsafe { BnString::into_string(result) };
719 TypeArchiveSnapshotId(id_str)
720 }
721
722 pub fn merge_snapshots<M>(
733 &self,
734 base_snapshot: &TypeArchiveSnapshotId,
735 first_snapshot: &TypeArchiveSnapshotId,
736 second_snapshot: &TypeArchiveSnapshotId,
737 merge_conflicts: M,
738 ) -> Result<BnString, Array<BnString>>
739 where
740 M: IntoIterator<Item = (String, String)>,
741 {
742 self.merge_snapshots_with_progress(
743 base_snapshot,
744 first_snapshot,
745 second_snapshot,
746 merge_conflicts,
747 NoProgressCallback,
748 )
749 }
750
751 pub fn merge_snapshots_with_progress<M, PC>(
762 &self,
763 base_snapshot: &TypeArchiveSnapshotId,
764 first_snapshot: &TypeArchiveSnapshotId,
765 second_snapshot: &TypeArchiveSnapshotId,
766 merge_conflicts: M,
767 mut progress: PC,
768 ) -> Result<BnString, Array<BnString>>
769 where
770 M: IntoIterator<Item = (String, String)>,
771 PC: ProgressCallback,
772 {
773 let base_snapshot = base_snapshot.0.as_str().to_cstr();
774 let first_snapshot = first_snapshot.0.as_str().to_cstr();
775 let second_snapshot = second_snapshot.0.as_str().to_cstr();
776 let (merge_keys, merge_values): (Vec<BnString>, Vec<BnString>) = merge_conflicts
777 .into_iter()
778 .map(|(k, v)| (BnString::new(k), BnString::new(v)))
779 .unzip();
780 let merge_keys_raw = merge_keys.as_ptr() as *const *const c_char;
782 let merge_values_raw = merge_values.as_ptr() as *const *const c_char;
783
784 let mut conflicts_errors = std::ptr::null_mut();
785 let mut conflicts_errors_count = 0;
786
787 let mut result = std::ptr::null_mut();
788
789 let success = unsafe {
790 BNTypeArchiveMergeSnapshots(
791 self.handle.as_ptr(),
792 base_snapshot.as_ptr(),
793 first_snapshot.as_ptr(),
794 second_snapshot.as_ptr(),
795 merge_keys_raw,
796 merge_values_raw,
797 merge_keys.len(),
798 &mut conflicts_errors,
799 &mut conflicts_errors_count,
800 &mut result,
801 Some(PC::cb_progress_callback),
802 &mut progress as *mut PC as *mut c_void,
803 )
804 };
805
806 if success {
807 assert!(!result.is_null());
808 Ok(unsafe { BnString::from_raw(result) })
809 } else {
810 assert!(!conflicts_errors.is_null());
811 Err(unsafe { Array::new(conflicts_errors, conflicts_errors_count, ()) })
812 }
813 }
814}
815
816impl ToOwned for TypeArchive {
817 type Owned = Ref<Self>;
818
819 fn to_owned(&self) -> Self::Owned {
820 unsafe { RefCountable::inc_ref(self) }
821 }
822}
823
824unsafe impl RefCountable for TypeArchive {
825 unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
826 Ref::new(Self {
827 handle: NonNull::new(BNNewTypeArchiveReference(handle.handle.as_ptr())).unwrap(),
828 })
829 }
830
831 unsafe fn dec_ref(handle: &Self) {
832 BNFreeTypeArchiveReference(handle.handle.as_ptr());
833 }
834}
835
836impl PartialEq for TypeArchive {
837 fn eq(&self, other: &Self) -> bool {
838 self.id() == other.id()
839 }
840}
841impl Eq for TypeArchive {}
842
843impl Hash for TypeArchive {
844 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
845 self.id().hash(state);
846 }
847}
848
849impl Debug for TypeArchive {
850 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
851 f.debug_struct("TypeArchive")
852 .field("id", &self.id())
853 .field("path", &self.path())
854 .field("current_snapshot_id", &self.current_snapshot_id())
855 .field("platform", &self.platform())
856 .finish()
857 }
858}
859
860impl CoreArrayProvider for TypeArchive {
861 type Raw = *mut BNTypeArchive;
862 type Context = ();
863 type Wrapped<'a> = Guard<'a, TypeArchive>;
864}
865
866unsafe impl CoreArrayProviderInner for TypeArchive {
867 unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
868 BNFreeTypeArchiveList(raw, count)
869 }
870
871 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
872 let raw_ptr = NonNull::new(*raw).unwrap();
873 Guard::new(Self::from_raw(raw_ptr), context)
874 }
875}
876
877pub struct TypeArchiveCallbackHandle<T: TypeArchiveNotificationCallback> {
878 callback: *mut T,
879 type_archive: Ref<TypeArchive>,
880}
881
882impl<T: TypeArchiveNotificationCallback> Drop for TypeArchiveCallbackHandle<T> {
883 fn drop(&mut self) {
884 let mut notification = BNTypeArchiveNotification {
885 context: self.callback as *mut c_void,
886 typeAdded: Some(cb_type_added::<T>),
887 typeUpdated: Some(cb_type_updated::<T>),
888 typeRenamed: Some(cb_type_renamed::<T>),
889 typeDeleted: Some(cb_type_deleted::<T>),
890 };
891 unsafe {
893 BNUnregisterTypeArchiveNotification(
894 self.type_archive.handle.as_ptr(),
895 &mut notification,
896 )
897 }
898 drop(unsafe { Box::from_raw(self.callback) });
900 }
901}
902
903pub trait TypeArchiveNotificationCallback {
904 fn type_added(&mut self, _archive: &TypeArchive, _id: &str, _definition: &Type) {}
910
911 fn type_updated(
918 &mut self,
919 _archive: &TypeArchive,
920 _id: &str,
921 _old_definition: &Type,
922 _new_definition: &Type,
923 ) {
924 }
925
926 fn type_renamed(
933 &mut self,
934 _archive: &TypeArchive,
935 _id: &str,
936 _old_name: &QualifiedName,
937 _new_name: &QualifiedName,
938 ) {
939 }
940
941 fn type_deleted(&mut self, _archive: &TypeArchive, _id: &str, _definition: &Type) {}
947}
948
949struct NotificationClosure<A, U, R, D>
950where
951 A: FnMut(&TypeArchive, &str, &Type),
952 U: FnMut(&TypeArchive, &str, &Type, &Type),
953 R: FnMut(&TypeArchive, &str, &QualifiedName, &QualifiedName),
954 D: FnMut(&TypeArchive, &str, &Type),
955{
956 fun_type_added: A,
957 fun_type_updated: U,
958 fun_type_renamed: R,
959 fun_type_deleted: D,
960}
961
962impl<A, U, R, D> TypeArchiveNotificationCallback for NotificationClosure<A, U, R, D>
963where
964 A: FnMut(&TypeArchive, &str, &Type),
965 U: FnMut(&TypeArchive, &str, &Type, &Type),
966 R: FnMut(&TypeArchive, &str, &QualifiedName, &QualifiedName),
967 D: FnMut(&TypeArchive, &str, &Type),
968{
969 fn type_added(&mut self, archive: &TypeArchive, id: &str, definition: &Type) {
970 (self.fun_type_added)(archive, id, definition)
971 }
972
973 fn type_updated(
974 &mut self,
975 archive: &TypeArchive,
976 id: &str,
977 old_definition: &Type,
978 new_definition: &Type,
979 ) {
980 (self.fun_type_updated)(archive, id, old_definition, new_definition)
981 }
982
983 fn type_renamed(
984 &mut self,
985 archive: &TypeArchive,
986 id: &str,
987 old_name: &QualifiedName,
988 new_name: &QualifiedName,
989 ) {
990 (self.fun_type_renamed)(archive, id, old_name, new_name)
991 }
992
993 fn type_deleted(&mut self, archive: &TypeArchive, id: &str, definition: &Type) {
994 (self.fun_type_deleted)(archive, id, definition)
995 }
996}
997
998unsafe extern "C" fn cb_type_added<T: TypeArchiveNotificationCallback>(
999 ctxt: *mut ::std::os::raw::c_void,
1000 archive: *mut BNTypeArchive,
1001 id: *const ::std::os::raw::c_char,
1002 definition: *mut BNType,
1003) {
1004 let ctxt: &mut T = &mut *(ctxt as *mut T);
1005 let archive = unsafe { TypeArchive::from_raw(NonNull::new(archive).unwrap()) };
1007 ctxt.type_added(
1008 &archive,
1009 unsafe { CStr::from_ptr(id).to_string_lossy().as_ref() },
1010 &Type { handle: definition },
1011 )
1012}
1013unsafe extern "C" fn cb_type_updated<T: TypeArchiveNotificationCallback>(
1014 ctxt: *mut ::std::os::raw::c_void,
1015 archive: *mut BNTypeArchive,
1016 id: *const ::std::os::raw::c_char,
1017 old_definition: *mut BNType,
1018 new_definition: *mut BNType,
1019) {
1020 let ctxt: &mut T = &mut *(ctxt as *mut T);
1021 let archive = unsafe { TypeArchive::from_raw(NonNull::new(archive).unwrap()) };
1023 ctxt.type_updated(
1024 &archive,
1025 unsafe { CStr::from_ptr(id).to_string_lossy().as_ref() },
1026 &Type {
1027 handle: old_definition,
1028 },
1029 &Type {
1030 handle: new_definition,
1031 },
1032 )
1033}
1034unsafe extern "C" fn cb_type_renamed<T: TypeArchiveNotificationCallback>(
1035 ctxt: *mut ::std::os::raw::c_void,
1036 archive: *mut BNTypeArchive,
1037 id: *const ::std::os::raw::c_char,
1038 old_name: *const BNQualifiedName,
1039 new_name: *const BNQualifiedName,
1040) {
1041 let ctxt: &mut T = &mut *(ctxt as *mut T);
1042 let old_name = QualifiedName::from_raw(&*old_name);
1044 let new_name = QualifiedName::from_raw(&*new_name);
1046 let archive = unsafe { TypeArchive::from_raw(NonNull::new(archive).unwrap()) };
1048 ctxt.type_renamed(
1049 &archive,
1050 unsafe { CStr::from_ptr(id).to_string_lossy().as_ref() },
1051 &old_name,
1052 &new_name,
1053 )
1054}
1055unsafe extern "C" fn cb_type_deleted<T: TypeArchiveNotificationCallback>(
1056 ctxt: *mut ::std::os::raw::c_void,
1057 archive: *mut BNTypeArchive,
1058 id: *const ::std::os::raw::c_char,
1059 definition: *mut BNType,
1060) {
1061 let ctxt: &mut T = &mut *(ctxt as *mut T);
1062 let archive = unsafe { TypeArchive::from_raw(NonNull::new(archive).unwrap()) };
1064 ctxt.type_deleted(
1065 &archive,
1066 unsafe { CStr::from_ptr(id).to_string_lossy().as_ref() },
1067 &Type { handle: definition },
1068 )
1069}
1070
1071#[repr(transparent)]
1072pub struct TypeArchiveMergeConflict {
1073 handle: NonNull<BNTypeArchiveMergeConflict>,
1074}
1075
1076impl TypeArchiveMergeConflict {
1077 pub(crate) unsafe fn from_raw(handle: NonNull<BNTypeArchiveMergeConflict>) -> Self {
1078 Self { handle }
1079 }
1080
1081 #[allow(unused)]
1082 pub(crate) unsafe fn ref_from_raw(handle: NonNull<BNTypeArchiveMergeConflict>) -> Ref<Self> {
1083 Ref::new(Self { handle })
1084 }
1085
1086 pub fn get_type_archive(&self) -> Option<Ref<TypeArchive>> {
1087 let value = unsafe { BNTypeArchiveMergeConflictGetTypeArchive(self.handle.as_ptr()) };
1088 NonNull::new(value).map(|handle| unsafe { TypeArchive::ref_from_raw(handle) })
1089 }
1090
1091 pub fn type_id(&self) -> String {
1092 let value = unsafe { BNTypeArchiveMergeConflictGetTypeId(self.handle.as_ptr()) };
1093 assert!(!value.is_null());
1094 unsafe { BnString::into_string(value) }
1095 }
1096
1097 pub fn base_snapshot_id(&self) -> TypeArchiveSnapshotId {
1098 let value = unsafe { BNTypeArchiveMergeConflictGetBaseSnapshotId(self.handle.as_ptr()) };
1099 assert!(!value.is_null());
1100 let id = unsafe { BnString::into_string(value) };
1101 TypeArchiveSnapshotId(id)
1102 }
1103
1104 pub fn first_snapshot_id(&self) -> TypeArchiveSnapshotId {
1105 let value = unsafe { BNTypeArchiveMergeConflictGetFirstSnapshotId(self.handle.as_ptr()) };
1106 assert!(!value.is_null());
1107 let id = unsafe { BnString::into_string(value) };
1108 TypeArchiveSnapshotId(id)
1109 }
1110
1111 pub fn second_snapshot_id(&self) -> TypeArchiveSnapshotId {
1112 let value = unsafe { BNTypeArchiveMergeConflictGetSecondSnapshotId(self.handle.as_ptr()) };
1113 assert!(!value.is_null());
1114 let id = unsafe { BnString::into_string(value) };
1115 TypeArchiveSnapshotId(id)
1116 }
1117
1118 pub fn success(&self, result: &str) -> bool {
1120 let result = result.to_cstr();
1121 unsafe { BNTypeArchiveMergeConflictSuccess(self.handle.as_ptr(), result.as_ptr()) }
1122 }
1123}
1124
1125impl Debug for TypeArchiveMergeConflict {
1126 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1127 f.debug_struct("TypeArchiveMergeConflict")
1128 .field("type_id", &self.type_id())
1129 .field("base_snapshot_id", &self.base_snapshot_id())
1130 .field("first_snapshot_id", &self.first_snapshot_id())
1131 .field("second_snapshot_id", &self.second_snapshot_id())
1132 .finish()
1133 }
1134}
1135
1136impl ToOwned for TypeArchiveMergeConflict {
1137 type Owned = Ref<Self>;
1138
1139 fn to_owned(&self) -> Self::Owned {
1140 unsafe { RefCountable::inc_ref(self) }
1141 }
1142}
1143
1144unsafe impl RefCountable for TypeArchiveMergeConflict {
1145 unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
1146 Ref::new(Self {
1147 handle: NonNull::new(BNNewTypeArchiveMergeConflictReference(
1148 handle.handle.as_ptr(),
1149 ))
1150 .unwrap(),
1151 })
1152 }
1153
1154 unsafe fn dec_ref(handle: &Self) {
1155 BNFreeTypeArchiveMergeConflict(handle.handle.as_ptr());
1156 }
1157}
1158
1159impl CoreArrayProvider for TypeArchiveMergeConflict {
1160 type Raw = *mut BNTypeArchiveMergeConflict;
1161 type Context = ();
1162 type Wrapped<'a> = Guard<'a, Self>;
1163}
1164
1165unsafe impl CoreArrayProviderInner for TypeArchiveMergeConflict {
1166 unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
1167 BNFreeTypeArchiveMergeConflictList(raw, count)
1168 }
1169
1170 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
1171 let raw_ptr = NonNull::new(*raw).unwrap();
1172 Guard::new(Self::from_raw(raw_ptr), context)
1173 }
1174}