diff options
Diffstat (limited to 'rust/src/typearchive.rs')
| -rw-r--r-- | rust/src/typearchive.rs | 947 |
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 }, - ) -} |
