summaryrefslogtreecommitdiff
path: root/rust/src/typearchive.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rust/src/typearchive.rs')
-rw-r--r--rust/src/typearchive.rs947
1 files changed, 0 insertions, 947 deletions
diff --git a/rust/src/typearchive.rs b/rust/src/typearchive.rs
deleted file mode 100644
index 71a7058e..00000000
--- a/rust/src/typearchive.rs
+++ /dev/null
@@ -1,947 +0,0 @@
-use core::{ffi, mem, ptr};
-
-use binaryninjacore_sys::*;
-
-use crate::databuffer::DataBuffer;
-use crate::metadata::Metadata;
-use crate::platform::Platform;
-use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref};
-use crate::string::{BnStrCompatible, BnString};
-use crate::types::{QualifiedName, QualifiedNameAndType, QualifiedNameTypeAndId, Type};
-
-/// Type Archives are a collection of types which can be shared between different analysis
-/// sessions and are backed by a database file on disk. Their types can be modified, and
-/// a history of previous versions of types is stored in snapshots in the archive.
-#[repr(transparent)]
-pub struct TypeArchive {
- handle: ptr::NonNull<BNTypeArchive>,
-}
-
-impl Drop for TypeArchive {
- fn drop(&mut self) {
- unsafe { BNFreeTypeArchiveReference(self.as_raw()) }
- }
-}
-
-impl Clone for TypeArchive {
- fn clone(&self) -> Self {
- unsafe {
- Self::from_raw(ptr::NonNull::new(BNNewTypeArchiveReference(self.as_raw())).unwrap())
- }
- }
-}
-
-impl PartialEq for TypeArchive {
- fn eq(&self, other: &Self) -> bool {
- self.id() == other.id()
- }
-}
-impl Eq for TypeArchive {}
-
-impl core::hash::Hash for TypeArchive {
- fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
- (self.handle.as_ptr() as usize).hash(state);
- }
-}
-
-impl core::fmt::Debug for TypeArchive {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- let path = self.path().map(|x| x.to_string());
- f.debug_struct("TypeArchive").field("path", &path).finish()
- }
-}
-
-impl TypeArchive {
- pub(crate) unsafe fn from_raw(handle: ptr::NonNull<BNTypeArchive>) -> Self {
- Self { handle }
- }
-
- pub(crate) unsafe fn ref_from_raw(handle: &*mut BNTypeArchive) -> &Self {
- assert!(!handle.is_null());
- mem::transmute(handle)
- }
-
- #[allow(clippy::mut_from_ref)]
- pub(crate) unsafe fn as_raw(&self) -> &mut BNTypeArchive {
- &mut *self.handle.as_ptr()
- }
-
- /// Open the Type Archive at the given path, if it exists.
- pub fn open<S: BnStrCompatible>(path: S) -> Option<TypeArchive> {
- let path = path.into_bytes_with_nul();
- let handle = unsafe { BNOpenTypeArchive(path.as_ref().as_ptr() as *const ffi::c_char) };
- ptr::NonNull::new(handle).map(|handle| unsafe { TypeArchive::from_raw(handle) })
- }
-
- /// Create a Type Archive at the given path, returning None if it could not be created.
- pub fn create<S: BnStrCompatible>(path: S, platform: &Platform) -> Option<TypeArchive> {
- let path = path.into_bytes_with_nul();
- let handle = unsafe {
- BNCreateTypeArchive(
- path.as_ref().as_ptr() as *const ffi::c_char,
- platform.handle,
- )
- };
- ptr::NonNull::new(handle).map(|handle| unsafe { TypeArchive::from_raw(handle) })
- }
-
- /// Create a Type Archive at the given path and id, returning None if it could not be created.
- pub fn create_with_id<P: BnStrCompatible, I: BnStrCompatible>(
- path: P,
- id: I,
- platform: &Platform,
- ) -> Option<TypeArchive> {
- let path = path.into_bytes_with_nul();
- let id = id.into_bytes_with_nul();
- let handle = unsafe {
- BNCreateTypeArchiveWithId(
- path.as_ref().as_ptr() as *const ffi::c_char,
- platform.handle,
- id.as_ref().as_ptr() as *const ffi::c_char,
- )
- };
- ptr::NonNull::new(handle).map(|handle| unsafe { TypeArchive::from_raw(handle) })
- }
-
- /// Get a reference to the Type Archive with the known id, if one exists.
- pub fn lookup_by_id<S: BnStrCompatible>(id: S) -> Option<TypeArchive> {
- let id = id.into_bytes_with_nul();
- let handle = unsafe { BNLookupTypeArchiveById(id.as_ref().as_ptr() as *const ffi::c_char) };
- ptr::NonNull::new(handle).map(|handle| unsafe { TypeArchive::from_raw(handle) })
- }
-
- /// Get the path to the Type Archive's file
- pub fn path(&self) -> Option<BnString> {
- let result = unsafe { BNGetTypeArchivePath(self.as_raw()) };
- (!result.is_null()).then(|| unsafe { BnString::from_raw(result) })
- }
-
- /// Get the guid for a Type Archive
- pub fn id(&self) -> Option<BnString> {
- let result = unsafe { BNGetTypeArchiveId(self.as_raw()) };
- (!result.is_null()).then(|| unsafe { BnString::from_raw(result) })
- }
-
- /// Get the associated Platform for a Type Archive
- pub fn platform(&self) -> Ref<Platform> {
- let result = unsafe { BNGetTypeArchivePlatform(self.as_raw()) };
- assert!(!result.is_null());
- unsafe { Platform::ref_from_raw(result) }
- }
-
- /// Get the id of the current snapshot in the type archive
- pub fn current_snapshot_id(&self) -> BnString {
- let result = unsafe { BNGetTypeArchiveCurrentSnapshotId(self.as_raw()) };
- assert!(!result.is_null());
- unsafe { BnString::from_raw(result) }
- }
-
- /// Revert the type archive's current snapshot to the given snapshot
- pub fn set_current_snapshot_id<S: BnStrCompatible>(&self, id: S) {
- let id = id.into_bytes_with_nul();
- unsafe {
- BNSetTypeArchiveCurrentSnapshot(
- self.as_raw(),
- id.as_ref().as_ptr() as *const ffi::c_char,
- )
- }
- }
-
- /// Get a list of every snapshot's id
- pub fn all_snapshot_ids(&self) -> Array<BnString> {
- let mut count = 0;
- let result = unsafe { BNGetTypeArchiveAllSnapshotIds(self.as_raw(), &mut count) };
- assert!(!result.is_null());
- unsafe { Array::new(result, count, ()) }
- }
-
- /// Get the ids of the parents to the given snapshot
- pub fn get_snapshot_parent_ids<S: BnStrCompatible>(
- &self,
- snapshot: S,
- ) -> Option<Array<BnString>> {
- let snapshot = snapshot.into_bytes_with_nul();
- let mut count = 0;
- let result = unsafe {
- BNGetTypeArchiveSnapshotParentIds(
- self.as_raw(),
- snapshot.as_ref().as_ptr() as *const ffi::c_char,
- &mut count,
- )
- };
- (!result.is_null()).then(|| unsafe { Array::new(result, count, ()) })
- }
-
- /// Get the ids of the children to the given snapshot
- pub fn get_snapshot_child_ids<S: BnStrCompatible>(
- &self,
- snapshot: S,
- ) -> Option<Array<BnString>> {
- let snapshot = snapshot.into_bytes_with_nul();
- let mut count = 0;
- let result = unsafe {
- BNGetTypeArchiveSnapshotChildIds(
- self.as_raw(),
- snapshot.as_ref().as_ptr() as *const ffi::c_char,
- &mut count,
- )
- };
- (!result.is_null()).then(|| unsafe { Array::new(result, count, ()) })
- }
-
- /// Add named types to the type archive. Type must have all dependant named types added
- /// prior to being added, or this function will fail.
- /// If the type already exists, it will be overwritten.
- ///
- /// * `name` - Name of new type
- /// * `type` - Definition of new type
- pub fn add_type(&self, name: &QualifiedNameAndType) {
- self.add_types(core::slice::from_ref(name))
- }
-
- /// Add named types to the type archive. Types must have all dependant named
- /// types prior to being added, or included in the list, or this function will fail.
- /// Types already existing with any added names will be overwritten.
- ///
- /// * `new_types` - Names and definitions of new types
- pub fn add_types(&self, new_types: &[QualifiedNameAndType]) {
- // SAFETY BNQualifiedNameAndType and QualifiedNameAndType are transparent
- let new_types_raw: &[BNQualifiedNameAndType] = unsafe { mem::transmute(new_types) };
- let result = unsafe {
- BNAddTypeArchiveTypes(self.as_raw(), new_types_raw.as_ptr(), new_types.len())
- };
- assert!(result);
- }
-
- /// Change the name of an existing type in the type archive.
- ///
- /// * `old_name` - Old type name in archive
- /// * `new_name` - New type name
- pub fn rename_type(&self, old_name: &QualifiedName, new_name: &QualifiedNameAndType) {
- let id = self
- .get_type_id(old_name, self.current_snapshot_id())
- .unwrap();
- return self.rename_type_by_id(id, new_name.name());
- }
-
- /// Change the name of an existing type in the type archive.
- ///
- /// * `id` - Old id of type in archive
- /// * `new_name` - New type name
- pub fn rename_type_by_id<S: BnStrCompatible>(&self, id: S, new_name: &QualifiedName) {
- let id = id.into_bytes_with_nul();
- let result = unsafe {
- BNRenameTypeArchiveType(
- self.as_raw(),
- id.as_ref().as_ptr() as *const ffi::c_char,
- &new_name.0,
- )
- };
- assert!(result);
- }
-
- /// Delete an existing type in the type archive.
- pub fn delete_type(&self, name: &QualifiedName) {
- let id = self.get_type_id(name, self.current_snapshot_id());
- let Some(id) = id else {
- panic!("Unknown type {}", name.string())
- };
- self.delete_type_by_id(id);
- }
-
- /// Delete an existing type in the type archive.
- pub fn delete_type_by_id<S: BnStrCompatible>(&self, id: S) {
- let id = id.into_bytes_with_nul();
- let result = unsafe {
- BNDeleteTypeArchiveType(self.as_raw(), id.as_ref().as_ptr() as *const ffi::c_char)
- };
- assert!(result);
- }
-
- /// Retrieve a stored type in the archive
- ///
- /// * `name` - Type name
- /// * `snapshot` - Snapshot id to search for types
- pub fn get_type_by_name<S: BnStrCompatible>(
- &self,
- name: &QualifiedName,
- snapshot: S,
- ) -> Option<Ref<Type>> {
- let snapshot = snapshot.into_bytes_with_nul();
- let result = unsafe {
- BNGetTypeArchiveTypeByName(
- self.as_raw(),
- &name.0,
- snapshot.as_ref().as_ptr() as *const ffi::c_char,
- )
- };
- (!result.is_null()).then(|| unsafe { Type::ref_from_raw(result) })
- }
-
- /// Retrieve a stored type in the archive by id
- ///
- /// * `id` - Type id
- /// * `snapshot` - Snapshot id to search for types
- pub fn get_type_by_id<I: BnStrCompatible, S: BnStrCompatible>(
- &self,
- id: I,
- snapshot: S,
- ) -> Option<Ref<Type>> {
- let snapshot = snapshot.into_bytes_with_nul();
- let id = id.into_bytes_with_nul();
- let result = unsafe {
- BNGetTypeArchiveTypeById(
- self.as_raw(),
- id.as_ref().as_ptr() as *const ffi::c_char,
- snapshot.as_ref().as_ptr() as *const ffi::c_char,
- )
- };
- (!result.is_null()).then(|| unsafe { Type::ref_from_raw(result) })
- }
-
- /// Retrieve a type's name by its id
- ///
- /// * `id` - Type id
- /// * `snapshot` - Snapshot id to search for types
- pub fn get_type_name_by_id<I: BnStrCompatible, S: BnStrCompatible>(
- &self,
- id: I,
- snapshot: S,
- ) -> QualifiedName {
- let snapshot = snapshot.into_bytes_with_nul();
- let id = id.into_bytes_with_nul();
- let result = unsafe {
- BNGetTypeArchiveTypeName(
- self.as_raw(),
- id.as_ref().as_ptr() as *const ffi::c_char,
- snapshot.as_ref().as_ptr() as *const ffi::c_char,
- )
- };
- QualifiedName(result)
- }
-
- /// Retrieve a type's id by its name
- ///
- /// * `name` - Type name
- /// * `snapshot` - Snapshot id to search for types
- pub fn get_type_id<S: BnStrCompatible>(
- &self,
- name: &QualifiedName,
- snapshot: S,
- ) -> Option<BnString> {
- let snapshot = snapshot.into_bytes_with_nul();
- let result = unsafe {
- BNGetTypeArchiveTypeId(
- self.as_raw(),
- &name.0,
- snapshot.as_ref().as_ptr() as *const ffi::c_char,
- )
- };
- (!result.is_null()).then(|| unsafe { BnString::from_raw(result) })
- }
-
- /// Retrieve all stored types in the archive at a snapshot
- ///
- /// * `snapshot` - Snapshot id to search for types
- pub fn get_types_and_ids<S: BnStrCompatible>(
- &self,
- snapshot: S,
- ) -> Array<QualifiedNameTypeAndId> {
- let snapshot = snapshot.into_bytes_with_nul();
- let mut count = 0;
- let result = unsafe {
- BNGetTypeArchiveTypes(
- self.as_raw(),
- snapshot.as_ref().as_ptr() as *const ffi::c_char,
- &mut count,
- )
- };
- assert!(!result.is_null());
- unsafe { Array::new(result, count, ()) }
- }
-
- /// Get a list of all types' ids in the archive at a snapshot
- ///
- /// * `snapshot` - Snapshot id to search for types
- pub fn get_type_ids<S: BnStrCompatible>(&self, snapshot: S) -> Array<BnString> {
- let snapshot = snapshot.into_bytes_with_nul();
- let mut count = 0;
- let result = unsafe {
- BNGetTypeArchiveTypeIds(
- self.as_raw(),
- snapshot.as_ref().as_ptr() as *const ffi::c_char,
- &mut count,
- )
- };
- assert!(!result.is_null());
- unsafe { Array::new(result, count, ()) }
- }
-
- /// Get a list of all types' names in the archive at a snapshot
- ///
- /// * `snapshot` - Snapshot id to search for types
- pub fn get_type_names<S: BnStrCompatible>(&self, snapshot: S) -> Array<QualifiedName> {
- let snapshot = snapshot.into_bytes_with_nul();
- let mut count = 0;
- let result = unsafe {
- BNGetTypeArchiveTypeNames(
- self.as_raw(),
- snapshot.as_ref().as_ptr() as *const ffi::c_char,
- &mut count,
- )
- };
- assert!(!result.is_null());
- unsafe { Array::new(result, count, ()) }
- }
-
- /// Get a list of all types' names and ids in the archive at a current snapshot
-
- /// * `snapshot` - Snapshot id to search for types
- pub fn get_type_names_and_ids<S: BnStrCompatible>(
- &self,
- snapshot: S,
- ) -> (Array<QualifiedName>, Array<BnString>) {
- let snapshot = snapshot.into_bytes_with_nul();
- let mut count = 0;
- let mut names = ptr::null_mut();
- let mut ids = ptr::null_mut();
- let result = unsafe {
- BNGetTypeArchiveTypeNamesAndIds(
- self.as_raw(),
- snapshot.as_ref().as_ptr() as *const ffi::c_char,
- &mut names,
- &mut ids,
- &mut count,
- )
- };
- assert!(result);
- (unsafe { Array::new(names, count, ()) }, unsafe {
- Array::new(ids, count, ())
- })
- }
-
- /// Get all types a given type references directly
- ///
- /// * `id` - Source type id
- /// * `snapshot` - Snapshot id to search for types
- pub fn get_outgoing_direct_references<I: BnStrCompatible, S: BnStrCompatible>(
- &self,
- id: I,
- snapshot: S,
- ) -> Array<BnString> {
- let snapshot = snapshot.into_bytes_with_nul();
- let id = id.into_bytes_with_nul();
- let mut count = 0;
- let result = unsafe {
- BNGetTypeArchiveOutgoingDirectTypeReferences(
- self.as_raw(),
- id.as_ref().as_ptr() as *const ffi::c_char,
- snapshot.as_ref().as_ptr() as *const ffi::c_char,
- &mut count,
- )
- };
- assert!(!result.is_null());
- unsafe { Array::new(result, count, ()) }
- }
-
- /// Get all types a given type references, and any types that the referenced types reference
- ///
- /// :param id: Source type id
- /// :param snapshot: Snapshot id to search for types
- pub fn get_outgoing_recursive_references<I: BnStrCompatible, S: BnStrCompatible>(
- &self,
- id: I,
- snapshot: S,
- ) -> Array<BnString> {
- let snapshot = snapshot.into_bytes_with_nul();
- let id = id.into_bytes_with_nul();
- let mut count = 0;
- let result = unsafe {
- BNGetTypeArchiveOutgoingRecursiveTypeReferences(
- self.as_raw(),
- id.as_ref().as_ptr() as *const ffi::c_char,
- snapshot.as_ref().as_ptr() as *const ffi::c_char,
- &mut count,
- )
- };
- assert!(!result.is_null());
- unsafe { Array::new(result, count, ()) }
- }
-
- /// Get all types that reference a given type
- ///
- /// * `id` - Target type id
- /// * `snapshot` - Snapshot id to search for types
- pub fn get_incoming_direct_references<I: BnStrCompatible, S: BnStrCompatible>(
- &self,
- id: I,
- snapshot: S,
- ) -> Array<BnString> {
- let snapshot = snapshot.into_bytes_with_nul();
- let id = id.into_bytes_with_nul();
- let mut count = 0;
- let result = unsafe {
- BNGetTypeArchiveIncomingDirectTypeReferences(
- self.as_raw(),
- id.as_ref().as_ptr() as *const ffi::c_char,
- snapshot.as_ref().as_ptr() as *const ffi::c_char,
- &mut count,
- )
- };
- assert!(!result.is_null());
- unsafe { Array::new(result, count, ()) }
- }
-
- /// Get all types that reference a given type, and all types that reference them, recursively
- ///
- /// * `id` - Target type id
- /// * `snapshot` - Snapshot id to search for types, or empty string to search the latest snapshot
- pub fn get_incoming_recursive_references<I: BnStrCompatible, S: BnStrCompatible>(
- &self,
- id: I,
- snapshot: S,
- ) -> Array<BnString> {
- let snapshot = snapshot.into_bytes_with_nul();
- let id = id.into_bytes_with_nul();
- let mut count = 0;
- let result = unsafe {
- BNGetTypeArchiveIncomingRecursiveTypeReferences(
- self.as_raw(),
- id.as_ref().as_ptr() as *const ffi::c_char,
- snapshot.as_ref().as_ptr() as *const ffi::c_char,
- &mut count,
- )
- };
- assert!(!result.is_null());
- unsafe { Array::new(result, count, ()) }
- }
-
- /// Look up a metadata entry in the archive
- pub fn query_metadata<S: BnStrCompatible>(&self, key: S) -> Option<Ref<Metadata>> {
- let key = key.into_bytes_with_nul();
- let result = unsafe {
- BNTypeArchiveQueryMetadata(self.as_raw(), key.as_ref().as_ptr() as *const ffi::c_char)
- };
- (!result.is_null()).then(|| unsafe { Metadata::ref_from_raw(result) })
- }
-
- /// Store a key/value pair in the archive's metadata storage
- ///
- /// * `key` - key value to associate the Metadata object with
- /// * `md` - object to store.
- pub fn store_metadata<S: BnStrCompatible>(&self, key: S, md: &Metadata) {
- let key = key.into_bytes_with_nul();
- let result = unsafe {
- BNTypeArchiveStoreMetadata(
- self.as_raw(),
- key.as_ref().as_ptr() as *const ffi::c_char,
- md.handle,
- )
- };
- assert!(result);
- }
-
- /// Delete a given metadata entry in the archive from the `key`
- pub fn remove_metadata<S: BnStrCompatible>(&self, key: S) -> bool {
- let key = key.into_bytes_with_nul();
- unsafe {
- BNTypeArchiveRemoveMetadata(self.as_raw(), key.as_ref().as_ptr() as *const ffi::c_char)
- }
- }
-
- /// Turn a given `snapshot` id into a data stream
- pub fn serialize_snapshot<S: BnStrCompatible>(&self, snapshot: S) -> DataBuffer {
- let snapshot = snapshot.into_bytes_with_nul();
- let result = unsafe {
- BNTypeArchiveSerializeSnapshot(
- self.as_raw(),
- snapshot.as_ref().as_ptr() as *const ffi::c_char,
- )
- };
- assert!(!result.is_null());
- DataBuffer::from_raw(result)
- }
-
- /// Take a serialized snapshot `data` stream and create a new snapshot from it
- pub fn deserialize_snapshot(&self, data: &DataBuffer) -> BnString {
- let result = unsafe { BNTypeArchiveDeserializeSnapshot(self.as_raw(), data.as_raw()) };
- assert!(!result.is_null());
- unsafe { BnString::from_raw(result) }
- }
-
- /// Register a notification listener
- pub fn register_notification_callback<T: TypeArchiveNotificationCallback>(
- &self,
- callback: T,
- ) -> TypeArchiveCallbackHandle<T> {
- // SAFETY free on [TypeArchiveCallbackHandle::Drop]
- let callback = Box::leak(Box::new(callback));
- let mut notification = BNTypeArchiveNotification {
- context: callback as *mut T as *mut ffi::c_void,
- typeAdded: Some(cb_type_added::<T>),
- typeUpdated: Some(cb_type_updated::<T>),
- typeRenamed: Some(cb_type_renamed::<T>),
- typeDeleted: Some(cb_type_deleted::<T>),
- };
- unsafe { BNRegisterTypeArchiveNotification(self.as_raw(), &mut notification) }
- TypeArchiveCallbackHandle {
- callback,
- type_archive: self.clone(),
- }
- }
-
- // NOTE NotificationClosure is left private, there is no need for the user
- // to know or use it.
- #[allow(private_interfaces)]
- pub fn register_notification_closure<A, U, R, D>(
- &self,
- type_added: A,
- type_updated: U,
- type_renamed: R,
- type_deleted: D,
- ) -> TypeArchiveCallbackHandle<NotificationClosure<A, U, R, D>>
- where
- A: FnMut(&TypeArchive, &str, &Type),
- U: FnMut(&TypeArchive, &str, &Type, &Type),
- R: FnMut(&TypeArchive, &str, &QualifiedName, &QualifiedName),
- D: FnMut(&TypeArchive, &str, &Type),
- {
- self.register_notification_callback(NotificationClosure {
- fun_type_added: type_added,
- fun_type_updated: type_updated,
- fun_type_renamed: type_renamed,
- fun_type_deleted: type_deleted,
- })
- }
-
- /// Close a type archive, disconnecting it from any active views and closing
- /// any open file handles
- pub fn close(self) {
- unsafe { BNCloseTypeArchive(self.as_raw()) }
- // NOTE self must be dropped after, don't make it `&self`
- }
-
- /// Determine if `file` is a Type Archive
- pub fn is_type_archive<P: BnStrCompatible>(file: P) -> bool {
- let file = file.into_bytes_with_nul();
- unsafe { BNIsTypeArchive(file.as_ref().as_ptr() as *const ffi::c_char) }
- }
-
- // TODO implement TypeContainer
- ///// Get the TypeContainer interface for this Type Archive, presenting types
- ///// at the current snapshot in the archive.
- //pub fn type_container(&self) -> TypeContainer {
- // let result = unsafe { BNGetTypeArchiveTypeContainer(self.as_raw()) };
- // unsafe { TypeContainer::from_raw(ptr::NonNull::new(result).unwrap()) }
- //}
-
- /// Do some function in a transaction making a new snapshot whose id is passed to func. If func throws,
- /// the transaction will be rolled back and the snapshot will not be created.
- ///
- /// * `func` - Function to call
- /// * `parents` - Parent snapshot ids
- ///
- /// Returns Created snapshot id
- pub fn new_snapshot_transaction<P, F>(&self, mut function: F, parents: &[BnString]) -> BnString
- where
- P: BnStrCompatible,
- F: FnMut(&str) -> bool,
- {
- unsafe extern "C" fn cb_callback<F: FnMut(&str) -> bool>(
- ctxt: *mut ffi::c_void,
- id: *const ffi::c_char,
- ) -> bool {
- let fun: &mut F = &mut *(ctxt as *mut F);
- fun(&ffi::CStr::from_ptr(id).to_string_lossy())
- }
-
- // SAFETY BnString and `*const ffi::c_char` are transparent
- let parents_raw = parents.as_ptr() as *const *const ffi::c_char;
-
- let result = unsafe {
- BNTypeArchiveNewSnapshotTransaction(
- self.as_raw(),
- Some(cb_callback::<F>),
- &mut function as *mut F as *mut ffi::c_void,
- parents_raw,
- parents.len(),
- )
- };
- assert!(!result.is_null());
- unsafe { BnString::from_raw(result) }
- }
-
- /// Merge two snapshots in the archive to produce a new snapshot
- ///
- /// * `base_snapshot` - Common ancestor of snapshots
- /// * `first_snapshot` - First snapshot to merge
- /// * `second_snapshot` - Second snapshot to merge
- /// * `merge_conflicts` - List of all conflicting types, id <-> target snapshot
- /// * `progress` - Function to call for progress updates
- ///
- /// Returns Snapshot id, if merge was successful, otherwise the List of
- /// conflicting type ids
- pub fn merge_snapshots<B, F, S, P, M, MI, MK>(
- &self,
- base_snapshot: B,
- first_snapshot: F,
- second_snapshot: S,
- merge_conflicts: M,
- mut progress: P,
- ) -> Result<BnString, Array<BnString>>
- where
- B: BnStrCompatible,
- F: BnStrCompatible,
- S: BnStrCompatible,
- P: FnMut(usize, usize) -> bool,
- M: IntoIterator<Item = (MI, MK)>,
- MI: BnStrCompatible,
- MK: BnStrCompatible,
- {
- unsafe extern "C" fn cb_callback<F: FnMut(usize, usize) -> bool>(
- ctxt: *mut ffi::c_void,
- progress: usize,
- total: usize,
- ) -> bool {
- let ctxt: &mut F = &mut *(ctxt as *mut F);
- ctxt(progress, total)
- }
-
- let base_snapshot = base_snapshot.into_bytes_with_nul();
- let first_snapshot = first_snapshot.into_bytes_with_nul();
- let second_snapshot = second_snapshot.into_bytes_with_nul();
- let (merge_keys, merge_values): (Vec<BnString>, Vec<BnString>) = merge_conflicts
- .into_iter()
- .map(|(k, v)| (BnString::new(k), BnString::new(v)))
- .unzip();
- // SAFETY BnString and `*const ffi::c_char` are transparent
- let merge_keys_raw = merge_keys.as_ptr() as *const *const ffi::c_char;
- let merge_values_raw = merge_values.as_ptr() as *const *const ffi::c_char;
-
- let mut conflicts_errors = ptr::null_mut();
- let mut conflicts_errors_count = 0;
-
- let mut result = ptr::null_mut();
-
- let success = unsafe {
- BNTypeArchiveMergeSnapshots(
- self.as_raw(),
- base_snapshot.as_ref().as_ptr() as *const ffi::c_char,
- first_snapshot.as_ref().as_ptr() as *const ffi::c_char,
- second_snapshot.as_ref().as_ptr() as *const ffi::c_char,
- merge_keys_raw,
- merge_values_raw,
- merge_keys.len(),
- &mut conflicts_errors,
- &mut conflicts_errors_count,
- &mut result,
- Some(cb_callback::<P>),
- (&mut progress) as *mut P as *mut ffi::c_void,
- )
- };
- if success {
- assert!(!result.is_null());
- Ok(unsafe { BnString::from_raw(result) })
- } else {
- assert!(!conflicts_errors.is_null());
- Err(unsafe { Array::new(conflicts_errors, conflicts_errors_count, ()) })
- }
- }
-}
-
-impl CoreArrayProvider for TypeArchive {
- type Raw = *mut BNTypeArchive;
- type Context = ();
- type Wrapped<'a> = &'a TypeArchive;
-}
-
-unsafe impl CoreArrayProviderInner for TypeArchive {
- unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
- BNFreeTypeArchiveList(raw, count)
- }
-
- unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
- Self::ref_from_raw(raw)
- }
-}
-
-pub struct TypeArchiveCallbackHandle<T: TypeArchiveNotificationCallback> {
- callback: *mut T,
- type_archive: TypeArchive,
-}
-
-impl<T: TypeArchiveNotificationCallback> Drop for TypeArchiveCallbackHandle<T> {
- fn drop(&mut self) {
- let mut notification = BNTypeArchiveNotification {
- context: self.callback as *mut ffi::c_void,
- typeAdded: Some(cb_type_added::<T>),
- typeUpdated: Some(cb_type_updated::<T>),
- typeRenamed: Some(cb_type_renamed::<T>),
- typeDeleted: Some(cb_type_deleted::<T>),
- };
- // unregister the notification callback
- unsafe {
- BNUnregisterTypeArchiveNotification(self.type_archive.as_raw(), &mut notification)
- }
- // free the context created at [TypeArchive::register_notification_callback]
- drop(unsafe { Box::from_raw(self.callback) });
- }
-}
-
-pub trait TypeArchiveNotificationCallback {
- /// Called when a type is added to the archive
- ///
- /// * `archive` - Source Type archive
- /// * `id` - Id of type added
- /// * `definition` - Definition of type
- fn type_added(&mut self, _archive: &TypeArchive, _id: &str, _definition: &Type) {}
-
- /// Called when a type in the archive is updated to a new definition
- ///
- /// * `archive` - Source Type archive
- /// * `id` - Id of type
- /// * `old_definition` - Previous definition
- /// * `new_definition` - Current definition
- fn type_updated(
- &mut self,
- _archive: &TypeArchive,
- _id: &str,
- _old_definition: &Type,
- _new_definition: &Type,
- ) {
- }
-
- /// Called when a type in the archive is renamed
- ///
- /// * `archive` - Source Type archive
- /// * `id` - Type id
- /// * `old_name` - Previous name
- /// * `new_name` - Current name
- fn type_renamed(
- &mut self,
- _archive: &TypeArchive,
- _id: &str,
- _old_name: &QualifiedName,
- _new_name: &QualifiedName,
- ) {
- }
-
- /// Called when a type in the archive is deleted from the archive
- ///
- /// * `archive` - Source Type archive
- /// * `id` - Id of type deleted
- /// * `definition` - Definition of type deleted
- fn type_deleted(&mut self, _archive: &TypeArchive, _id: &str, _definition: &Type) {}
-}
-
-struct NotificationClosure<A, U, R, D>
-where
- A: FnMut(&TypeArchive, &str, &Type),
- U: FnMut(&TypeArchive, &str, &Type, &Type),
- R: FnMut(&TypeArchive, &str, &QualifiedName, &QualifiedName),
- D: FnMut(&TypeArchive, &str, &Type),
-{
- fun_type_added: A,
- fun_type_updated: U,
- fun_type_renamed: R,
- fun_type_deleted: D,
-}
-
-impl<A, U, R, D> TypeArchiveNotificationCallback for NotificationClosure<A, U, R, D>
-where
- A: FnMut(&TypeArchive, &str, &Type),
- U: FnMut(&TypeArchive, &str, &Type, &Type),
- R: FnMut(&TypeArchive, &str, &QualifiedName, &QualifiedName),
- D: FnMut(&TypeArchive, &str, &Type),
-{
- fn type_added(&mut self, archive: &TypeArchive, id: &str, definition: &Type) {
- (self.fun_type_added)(archive, id, definition)
- }
-
- fn type_updated(
- &mut self,
- archive: &TypeArchive,
- id: &str,
- old_definition: &Type,
- new_definition: &Type,
- ) {
- (self.fun_type_updated)(archive, id, old_definition, new_definition)
- }
-
- fn type_renamed(
- &mut self,
- archive: &TypeArchive,
- id: &str,
- old_name: &QualifiedName,
- new_name: &QualifiedName,
- ) {
- (self.fun_type_renamed)(archive, id, old_name, new_name)
- }
-
- fn type_deleted(&mut self, archive: &TypeArchive, id: &str, definition: &Type) {
- (self.fun_type_deleted)(archive, id, definition)
- }
-}
-
-unsafe extern "C" fn cb_type_added<T: TypeArchiveNotificationCallback>(
- ctxt: *mut ::std::os::raw::c_void,
- archive: *mut BNTypeArchive,
- id: *const ::std::os::raw::c_char,
- definition: *mut BNType,
-) {
- let ctxt: &mut T = &mut *(ctxt as *mut T);
- ctxt.type_added(
- unsafe { TypeArchive::ref_from_raw(&archive) },
- unsafe { ffi::CStr::from_ptr(id).to_string_lossy().as_ref() },
- &Type { handle: definition },
- )
-}
-unsafe extern "C" fn cb_type_updated<T: TypeArchiveNotificationCallback>(
- ctxt: *mut ::std::os::raw::c_void,
- archive: *mut BNTypeArchive,
- id: *const ::std::os::raw::c_char,
- old_definition: *mut BNType,
- new_definition: *mut BNType,
-) {
- let ctxt: &mut T = &mut *(ctxt as *mut T);
- ctxt.type_updated(
- unsafe { TypeArchive::ref_from_raw(&archive) },
- unsafe { ffi::CStr::from_ptr(id).to_string_lossy().as_ref() },
- &Type {
- handle: old_definition,
- },
- &Type {
- handle: new_definition,
- },
- )
-}
-unsafe extern "C" fn cb_type_renamed<T: TypeArchiveNotificationCallback>(
- ctxt: *mut ::std::os::raw::c_void,
- archive: *mut BNTypeArchive,
- id: *const ::std::os::raw::c_char,
- old_name: *const BNQualifiedName,
- new_name: *const BNQualifiedName,
-) {
- let ctxt: &mut T = &mut *(ctxt as *mut T);
- let old_name = mem::ManuallyDrop::new(QualifiedName(*old_name));
- let new_name = mem::ManuallyDrop::new(QualifiedName(*new_name));
- ctxt.type_renamed(
- unsafe { TypeArchive::ref_from_raw(&archive) },
- unsafe { ffi::CStr::from_ptr(id).to_string_lossy().as_ref() },
- &old_name,
- &new_name,
- )
-}
-unsafe extern "C" fn cb_type_deleted<T: TypeArchiveNotificationCallback>(
- ctxt: *mut ::std::os::raw::c_void,
- archive: *mut BNTypeArchive,
- id: *const ::std::os::raw::c_char,
- definition: *mut BNType,
-) {
- let ctxt: &mut T = &mut *(ctxt as *mut T);
- ctxt.type_deleted(
- unsafe { TypeArchive::ref_from_raw(&archive) },
- unsafe { ffi::CStr::from_ptr(id).to_string_lossy().as_ref() },
- &Type { handle: definition },
- )
-}