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, } 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(&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) -> 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(path: S) -> Option { 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(path: S, platform: &Platform) -> Option { 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( path: P, id: I, platform: &Platform, ) -> Option { 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(id: S) -> Option { 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 { 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 { 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 { 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(&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 { 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( &self, snapshot: S, ) -> Option> { 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( &self, snapshot: S, ) -> Option> { 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(&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(&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( &self, name: &QualifiedName, snapshot: S, ) -> Option> { 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( &self, id: I, snapshot: S, ) -> Option> { 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( &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( &self, name: &QualifiedName, snapshot: S, ) -> Option { 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( &self, snapshot: S, ) -> Array { 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(&self, snapshot: S) -> Array { 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(&self, snapshot: S) -> Array { 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( &self, snapshot: S, ) -> (Array, Array) { 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( &self, id: I, snapshot: S, ) -> Array { 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( &self, id: I, snapshot: S, ) -> Array { 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( &self, id: I, snapshot: S, ) -> Array { 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( &self, id: I, snapshot: S, ) -> Array { 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(&self, key: S) -> Option> { 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(&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(&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(&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( &self, callback: T, ) -> TypeArchiveCallbackHandle { // 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::), typeUpdated: Some(cb_type_updated::), typeRenamed: Some(cb_type_renamed::), typeDeleted: Some(cb_type_deleted::), }; 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( &self, type_added: A, type_updated: U, type_renamed: R, type_deleted: D, ) -> TypeArchiveCallbackHandle> 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(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(&self, mut function: F, parents: &[BnString]) -> BnString where P: BnStrCompatible, F: FnMut(&str) -> bool, { unsafe extern "C" fn cb_callback 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::), &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( &self, base_snapshot: B, first_snapshot: F, second_snapshot: S, merge_conflicts: M, mut progress: P, ) -> Result> where B: BnStrCompatible, F: BnStrCompatible, S: BnStrCompatible, P: FnMut(usize, usize) -> bool, M: IntoIterator, MI: BnStrCompatible, MK: BnStrCompatible, { unsafe extern "C" fn cb_callback 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, Vec) = 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::

), (&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 { callback: *mut T, type_archive: TypeArchive, } impl Drop for TypeArchiveCallbackHandle { fn drop(&mut self) { let mut notification = BNTypeArchiveNotification { context: self.callback as *mut ffi::c_void, typeAdded: Some(cb_type_added::), typeUpdated: Some(cb_type_updated::), typeRenamed: Some(cb_type_renamed::), typeDeleted: Some(cb_type_deleted::), }; // 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 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 TypeArchiveNotificationCallback for NotificationClosure 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( 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( 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( 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( 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 }, ) }