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};
#[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()
}
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) })
}
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) })
}
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) })
}
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) })
}
pub fn path(&self) -> Option<BnString> {
let result = unsafe { BNGetTypeArchivePath(self.as_raw()) };
(!result.is_null()).then(|| unsafe { BnString::from_raw(result) })
}
pub fn id(&self) -> Option<BnString> {
let result = unsafe { BNGetTypeArchiveId(self.as_raw()) };
(!result.is_null()).then(|| unsafe { BnString::from_raw(result) })
}
pub fn platform(&self) -> Ref<Platform> {
let result = unsafe { BNGetTypeArchivePlatform(self.as_raw()) };
assert!(!result.is_null());
unsafe { Platform::ref_from_raw(result) }
}
pub fn current_snapshot_id(&self) -> BnString {
let result = unsafe { BNGetTypeArchiveCurrentSnapshotId(self.as_raw()) };
assert!(!result.is_null());
unsafe { BnString::from_raw(result) }
}
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,
)
}
}
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, ()) }
}
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, ()) })
}
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, ()) })
}
pub fn add_type(&self, name: &QualifiedNameAndType) {
self.add_types(core::slice::from_ref(name))
}
pub fn add_types(&self, new_types: &[QualifiedNameAndType]) {
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);
}
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());
}
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);
}
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);
}
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);
}
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) })
}
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) })
}
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)
}
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) })
}
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, ()) }
}
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, ()) }
}
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, ()) }
}
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, ())
})
}
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, ()) }
}
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, ()) }
}
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, ()) }
}
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, ()) }
}
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) })
}
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);
}
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)
}
}
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)
}
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) }
}
pub fn register_notification_callback<T: TypeArchiveNotificationCallback>(
&self,
callback: T,
) -> TypeArchiveCallbackHandle<T> {
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(),
}
}
#[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,
})
}
pub fn close(self) {
unsafe { BNCloseTypeArchive(self.as_raw()) }
}
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) }
}
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())
}
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) }
}
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();
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>),
};
unsafe {
BNUnregisterTypeArchiveNotification(self.type_archive.as_raw(), &mut notification)
}
drop(unsafe { Box::from_raw(self.callback) });
}
}
pub trait TypeArchiveNotificationCallback {
fn type_added(&mut self, _archive: &TypeArchive, _id: &str, _definition: &Type) {}
fn type_updated(
&mut self,
_archive: &TypeArchive,
_id: &str,
_old_definition: &Type,
_new_definition: &Type,
) {
}
fn type_renamed(
&mut self,
_archive: &TypeArchive,
_id: &str,
_old_name: &QualifiedName,
_new_name: &QualifiedName,
) {
}
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 },
)
}