diff options
Diffstat (limited to 'rust/src/database.rs')
| -rw-r--r-- | rust/src/database.rs | 617 |
1 files changed, 106 insertions, 511 deletions
diff --git a/rust/src/database.rs b/rust/src/database.rs index 3274c9c0..7174ebe8 100644 --- a/rust/src/database.rs +++ b/rust/src/database.rs @@ -1,115 +1,123 @@ -use std::collections::HashMap; -use std::time::{Duration, SystemTime, UNIX_EPOCH}; -use std::{ffi, mem, ptr}; +pub mod kvs; +pub mod snapshot; +pub mod undo; use binaryninjacore_sys::*; +use std::collections::HashMap; +use std::ffi::{c_char, c_void}; +use std::fmt::Debug; +use std::ptr::NonNull; -use crate::binaryview::BinaryView; -use crate::databuffer::DataBuffer; -use crate::disassembly::InstructionTextToken; -use crate::filemetadata::FileMetadata; -use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref}; +use crate::binary_view::BinaryView; +use crate::data_buffer::DataBuffer; +use crate::database::kvs::KeyValueStore; +use crate::database::snapshot::{Snapshot, SnapshotId}; +use crate::file_metadata::FileMetadata; +use crate::progress::{NoProgressCallback, ProgressCallback}; +use crate::rc::{Array, Ref, RefCountable}; use crate::string::{BnStrCompatible, BnString}; -#[repr(transparent)] pub struct Database { - handle: ptr::NonNull<BNDatabase>, + pub(crate) handle: NonNull<BNDatabase>, } impl Database { - pub(crate) unsafe fn from_raw(handle: ptr::NonNull<BNDatabase>) -> Self { + pub(crate) unsafe fn from_raw(handle: NonNull<BNDatabase>) -> Self { Self { handle } } - #[allow(clippy::mut_from_ref)] - pub(crate) unsafe fn as_raw(&self) -> &mut BNDatabase { - &mut *self.handle.as_ptr() + pub(crate) unsafe fn ref_from_raw(handle: NonNull<BNDatabase>) -> Ref<Self> { + Ref::new(Self { handle }) } /// Get a snapshot by its id, or None if no snapshot with that id exists - pub fn snapshot(&self, id: i64) -> Option<Snapshot> { - let result = unsafe { BNGetDatabaseSnapshot(self.as_raw(), id) }; - ptr::NonNull::new(result).map(|handle| unsafe { Snapshot::from_raw(handle) }) + pub fn snapshot_by_id(&self, id: SnapshotId) -> Option<Ref<Snapshot>> { + let result = unsafe { BNGetDatabaseSnapshot(self.handle.as_ptr(), id.0) }; + NonNull::new(result).map(|handle| unsafe { Snapshot::ref_from_raw(handle) }) } /// Get a list of all snapshots in the database pub fn snapshots(&self) -> Array<Snapshot> { let mut count = 0; - let result = unsafe { BNGetDatabaseSnapshots(self.as_raw(), &mut count) }; + let result = unsafe { BNGetDatabaseSnapshots(self.handle.as_ptr(), &mut count) }; assert!(!result.is_null()); unsafe { Array::new(result, count, ()) } } /// Get the current snapshot - pub fn current_snapshot(&self) -> Option<Snapshot> { - let result = unsafe { BNGetDatabaseCurrentSnapshot(self.as_raw()) }; - ptr::NonNull::new(result).map(|handle| unsafe { Snapshot::from_raw(handle) }) + pub fn current_snapshot(&self) -> Option<Ref<Snapshot>> { + let result = unsafe { BNGetDatabaseCurrentSnapshot(self.handle.as_ptr()) }; + NonNull::new(result).map(|handle| unsafe { Snapshot::ref_from_raw(handle) }) } + /// Equivalent to [`Self::set_current_snapshot_id`]. pub fn set_current_snapshot(&self, value: &Snapshot) { - unsafe { BNSetDatabaseCurrentSnapshot(self.as_raw(), value.id()) } + self.set_current_snapshot_id(value.id()) + } + + /// Sets the current snapshot to the [`SnapshotId`]. + /// + /// **No** validation is done to ensure that the id is valid. + pub fn set_current_snapshot_id(&self, id: SnapshotId) { + unsafe { BNSetDatabaseCurrentSnapshot(self.handle.as_ptr(), id.0) } } pub fn write_snapshot_data<N: BnStrCompatible>( &self, - parents: &[i64], + parents: &[SnapshotId], file: &BinaryView, name: N, data: &KeyValueStore, auto_save: bool, - ) -> i64 { - let name_raw = name.into_bytes_with_nul(); - let name_ptr = name_raw.as_ref().as_ptr() as *const ffi::c_char; - unsafe { - BNWriteDatabaseSnapshotData( - self.as_raw(), - parents.as_ptr() as *mut _, - parents.len(), - file.handle, - name_ptr, - data.as_raw(), - auto_save, - ptr::null_mut(), - Some(cb_progress_nop), - ) - } + ) -> SnapshotId { + self.write_snapshot_data_with_progress( + parents, + file, + name, + data, + auto_save, + NoProgressCallback, + ) } - pub fn write_snapshot_data_with_progress<N, F>( + pub fn write_snapshot_data_with_progress<N, P>( &self, - parents: &[i64], + parents: &[SnapshotId], file: &BinaryView, name: N, data: &KeyValueStore, auto_save: bool, - mut progress: F, - ) -> i64 + mut progress: P, + ) -> SnapshotId where N: BnStrCompatible, - F: FnMut(usize, usize) -> bool, + P: ProgressCallback, { let name_raw = name.into_bytes_with_nul(); - let name_ptr = name_raw.as_ref().as_ptr() as *const ffi::c_char; - let ctxt = &mut progress as *mut _ as *mut ffi::c_void; - unsafe { + let name_ptr = name_raw.as_ref().as_ptr() as *const c_char; + + let new_id = unsafe { BNWriteDatabaseSnapshotData( - self.as_raw(), + self.handle.as_ptr(), + // SAFETY: SnapshotId is just i64 parents.as_ptr() as *mut _, parents.len(), file.handle, name_ptr, - data.as_raw(), + data.handle.as_ptr(), auto_save, - ctxt, - Some(cb_progress::<F>), + &mut progress as *mut P as *mut c_void, + Some(P::cb_progress_callback), ) - } + }; + + SnapshotId(new_id) } /// Trim a snapshot's contents in the database by id, but leave the parent/child /// hierarchy intact. Future references to this snapshot will return False for has_contents - pub fn trim_snapshot(&self, id: i64) -> Result<(), ()> { - if unsafe { BNTrimDatabaseSnapshot(self.as_raw(), id) } { + pub fn trim_snapshot(&self, id: SnapshotId) -> Result<(), ()> { + if unsafe { BNTrimDatabaseSnapshot(self.handle.as_ptr(), id.0) } { Ok(()) } else { Err(()) @@ -118,8 +126,8 @@ impl Database { /// Remove a snapshot in the database by id, deleting its contents and references. /// Attempting to remove a snapshot with children will raise an exception. - pub fn remove_snapshot(&self, id: i64) -> Result<(), ()> { - if unsafe { BNRemoveDatabaseSnapshot(self.as_raw(), id) } { + pub fn remove_snapshot(&self, id: SnapshotId) -> Result<(), ()> { + if unsafe { BNRemoveDatabaseSnapshot(self.handle.as_ptr(), id.0) } { Ok(()) } else { Err(()) @@ -127,14 +135,14 @@ impl Database { } pub fn has_global<S: BnStrCompatible>(&self, key: S) -> bool { let key_raw = key.into_bytes_with_nul(); - let key_ptr = key_raw.as_ref().as_ptr() as *const ffi::c_char; - unsafe { BNDatabaseHasGlobal(self.as_raw(), key_ptr) != 0 } + let key_ptr = key_raw.as_ref().as_ptr() as *const c_char; + unsafe { BNDatabaseHasGlobal(self.handle.as_ptr(), key_ptr) != 0 } } /// Get a list of keys for all globals in the database pub fn global_keys(&self) -> Array<BnString> { let mut count = 0; - let result = unsafe { BNGetDatabaseGlobalKeys(self.as_raw(), &mut count) }; + let result = unsafe { BNGetDatabaseGlobalKeys(self.handle.as_ptr(), &mut count) }; assert!(!result.is_null()); unsafe { Array::new(result, count, ()) } } @@ -150,505 +158,92 @@ impl Database { /// Get a specific global by key pub fn read_global<S: BnStrCompatible>(&self, key: S) -> Option<BnString> { let key_raw = key.into_bytes_with_nul(); - let key_ptr = key_raw.as_ref().as_ptr() as *const ffi::c_char; - let result = unsafe { BNReadDatabaseGlobal(self.as_raw(), key_ptr) }; - unsafe { ptr::NonNull::new(result).map(|_| BnString::from_raw(result)) } + let key_ptr = key_raw.as_ref().as_ptr() as *const c_char; + let result = unsafe { BNReadDatabaseGlobal(self.handle.as_ptr(), key_ptr) }; + unsafe { NonNull::new(result).map(|_| BnString::from_raw(result)) } } /// Write a global into the database pub fn write_global<K: BnStrCompatible, V: BnStrCompatible>(&self, key: K, value: V) -> bool { let key_raw = key.into_bytes_with_nul(); - let key_ptr = key_raw.as_ref().as_ptr() as *const ffi::c_char; + let key_ptr = key_raw.as_ref().as_ptr() as *const c_char; let value_raw = value.into_bytes_with_nul(); - let value_ptr = value_raw.as_ref().as_ptr() as *const ffi::c_char; - unsafe { BNWriteDatabaseGlobal(self.as_raw(), key_ptr, value_ptr) } + let value_ptr = value_raw.as_ref().as_ptr() as *const c_char; + unsafe { BNWriteDatabaseGlobal(self.handle.as_ptr(), key_ptr, value_ptr) } } /// Get a specific global by key, as a binary buffer pub fn read_global_data<S: BnStrCompatible>(&self, key: S) -> Option<DataBuffer> { let key_raw = key.into_bytes_with_nul(); - let key_ptr = key_raw.as_ref().as_ptr() as *const ffi::c_char; - let result = unsafe { BNReadDatabaseGlobalData(self.as_raw(), key_ptr) }; - ptr::NonNull::new(result).map(|_| DataBuffer::from_raw(result)) + let key_ptr = key_raw.as_ref().as_ptr() as *const c_char; + let result = unsafe { BNReadDatabaseGlobalData(self.handle.as_ptr(), key_ptr) }; + NonNull::new(result).map(|_| DataBuffer::from_raw(result)) } /// Write a binary buffer into a global in the database pub fn write_global_data<K: BnStrCompatible>(&self, key: K, value: &DataBuffer) -> bool { let key_raw = key.into_bytes_with_nul(); - let key_ptr = key_raw.as_ref().as_ptr() as *const ffi::c_char; - unsafe { BNWriteDatabaseGlobalData(self.as_raw(), key_ptr, value.as_raw()) } + let key_ptr = key_raw.as_ref().as_ptr() as *const c_char; + unsafe { BNWriteDatabaseGlobalData(self.handle.as_ptr(), key_ptr, value.as_raw()) } } /// Get the owning FileMetadata pub fn file(&self) -> Ref<FileMetadata> { - let result = unsafe { BNGetDatabaseFile(self.as_raw()) }; + let result = unsafe { BNGetDatabaseFile(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { Ref::new(FileMetadata::from_raw(result)) } + FileMetadata::ref_from_raw(result) } /// Get the backing analysis cache kvs - pub fn analysis_cache(&self) -> KeyValueStore { - let result = unsafe { BNReadDatabaseAnalysisCache(self.as_raw()) }; - unsafe { KeyValueStore::from_raw(ptr::NonNull::new(result).unwrap()) } + pub fn analysis_cache(&self) -> Ref<KeyValueStore> { + let result = unsafe { BNReadDatabaseAnalysisCache(self.handle.as_ptr()) }; + unsafe { KeyValueStore::ref_from_raw(NonNull::new(result).unwrap()) } } pub fn reload_connection(&self) { - unsafe { BNDatabaseReloadConnection(self.as_raw()) } + unsafe { BNDatabaseReloadConnection(self.handle.as_ptr()) } } pub fn write_analysis_cache(&self, val: &KeyValueStore) -> Result<(), ()> { - if unsafe { BNWriteDatabaseAnalysisCache(self.as_raw(), val.as_raw()) } { + if unsafe { BNWriteDatabaseAnalysisCache(self.handle.as_ptr(), val.handle.as_ptr()) } { Ok(()) } else { Err(()) } } - pub fn snapshot_has_data(&self, id: i64) -> bool { - unsafe { BNSnapshotHasData(self.as_raw(), id) } + pub fn snapshot_has_data(&self, id: SnapshotId) -> bool { + unsafe { BNSnapshotHasData(self.handle.as_ptr(), id.0) } } } -impl Clone for Database { - fn clone(&self) -> Self { - unsafe { Self::from_raw(ptr::NonNull::new(BNNewDatabaseReference(self.as_raw())).unwrap()) } +impl Debug for Database { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Database") + .field("current_snapshot", &self.current_snapshot()) + .field("snapshot_count", &self.snapshots().len()) + .field("globals", &self.globals()) + .field("analysis_cache", &self.analysis_cache()) + .finish() } } -impl Drop for Database { - fn drop(&mut self) { - unsafe { BNFreeDatabase(self.as_raw()) } - } -} - -#[repr(transparent)] -pub struct Snapshot { - handle: ptr::NonNull<BNSnapshot>, -} +impl ToOwned for Database { + type Owned = Ref<Self>; -impl Snapshot { - pub(crate) unsafe fn from_raw(handle: ptr::NonNull<BNSnapshot>) -> Self { - Self { handle } - } - - pub(crate) unsafe fn ref_from_raw(handle: &*mut BNSnapshot) -> &Self { - mem::transmute(handle) - } - - #[allow(clippy::mut_from_ref)] - pub(crate) unsafe fn as_raw(&self) -> &mut BNSnapshot { - &mut *self.handle.as_ptr() - } - - /// Get the owning database - pub fn database(&self) -> Database { - unsafe { - Database::from_raw(ptr::NonNull::new(BNGetSnapshotDatabase(self.as_raw())).unwrap()) - } - } - - /// Get the numerical id (read-only) - pub fn id(&self) -> i64 { - unsafe { BNGetSnapshotId(self.as_raw()) } - } - - /// Get the displayed snapshot name - pub fn name(&self) -> BnString { - unsafe { BnString::from_raw(BNGetSnapshotName(self.as_raw())) } - } - - /// Set the displayed snapshot name - pub fn set_name<S: BnStrCompatible>(&self, value: S) { - let value_raw = value.into_bytes_with_nul(); - let value_ptr = value_raw.as_ref().as_ptr() as *const ffi::c_char; - unsafe { BNSetSnapshotName(self.as_raw(), value_ptr) } - } - - /// If the snapshot was the result of an auto-save - pub fn is_auto_save(&self) -> bool { - unsafe { BNIsSnapshotAutoSave(self.as_raw()) } - } - - /// If the snapshot has contents, and has not been trimmed - pub fn has_contents(&self) -> bool { - unsafe { BNSnapshotHasContents(self.as_raw()) } - } - - /// If the snapshot has undo data - pub fn has_undo(&self) -> bool { - unsafe { BNSnapshotHasUndo(self.as_raw()) } - } - - /// Get the first parent of the snapshot, or None if it has no parents - pub fn first_parent(&self) -> Option<Snapshot> { - let result = unsafe { BNGetSnapshotFirstParent(self.as_raw()) }; - ptr::NonNull::new(result).map(|s| unsafe { Snapshot::from_raw(s) }) - } - - /// Get a list of all parent snapshots of the snapshot - pub fn parents(&self) -> Array<Snapshot> { - let mut count = 0; - let result = unsafe { BNGetSnapshotParents(self.as_raw(), &mut count) }; - assert!(!result.is_null()); - unsafe { Array::new(result, count, ()) } - } - - /// Get a list of all child snapshots of the snapshot - pub fn children(&self) -> Array<Snapshot> { - let mut count = 0; - let result = unsafe { BNGetSnapshotChildren(self.as_raw(), &mut count) }; - assert!(!result.is_null()); - unsafe { Array::new(result, count, ()) } - } - - /// Get a buffer of the raw data at the time of the snapshot - pub fn file_contents(&self) -> Option<DataBuffer> { - self.has_contents().then(|| unsafe { - let result = BNGetSnapshotFileContents(self.as_raw()); - assert!(!result.is_null()); - DataBuffer::from_raw(result) - }) - } - - /// Get a hash of the data at the time of the snapshot - pub fn file_contents_hash(&self) -> Option<DataBuffer> { - self.has_contents().then(|| unsafe { - let result = BNGetSnapshotFileContentsHash(self.as_raw()); - assert!(!result.is_null()); - DataBuffer::from_raw(result) - }) - } - - /// Get a list of undo entries at the time of the snapshot - pub fn undo_entries(&self) -> Array<UndoEntry> { - assert!(self.has_undo()); - let mut count = 0; - let result = unsafe { BNGetSnapshotUndoEntries(self.as_raw(), &mut count) }; - assert!(!result.is_null()); - unsafe { Array::new(result, count, ()) } - } - - pub fn undo_entries_with_progress<F: FnMut(usize, usize) -> bool>( - &self, - mut progress: F, - ) -> Array<UndoEntry> { - assert!(self.has_undo()); - let ctxt = &mut progress as *mut _ as *mut ffi::c_void; - let mut count = 0; - let result = unsafe { - BNGetSnapshotUndoEntriesWithProgress( - self.as_raw(), - ctxt, - Some(cb_progress::<F>), - &mut count, - ) - }; - assert!(!result.is_null()); - unsafe { Array::new(result, count, ()) } - } - - /// Get the backing kvs data with snapshot fields - pub fn read_data(&self) -> KeyValueStore { - let result = unsafe { BNReadSnapshotData(self.as_raw()) }; - unsafe { KeyValueStore::from_raw(ptr::NonNull::new(result).unwrap()) } - } - - pub fn read_data_with_progress<F: FnMut(usize, usize) -> bool>( - &self, - mut progress: F, - ) -> KeyValueStore { - let ctxt = &mut progress as *mut _ as *mut ffi::c_void; - let result = - unsafe { BNReadSnapshotDataWithProgress(self.as_raw(), ctxt, Some(cb_progress::<F>)) }; - unsafe { KeyValueStore::from_raw(ptr::NonNull::new(result).unwrap()) } - } - - pub fn undo_data(&self) -> DataBuffer { - let result = unsafe { BNGetSnapshotUndoData(self.as_raw()) }; - assert!(!result.is_null()); - DataBuffer::from_raw(result) - } - - pub fn store_data<F: FnMut(usize, usize) -> bool>( - &self, - data: KeyValueStore, - mut progress: F, - ) -> bool { - let ctxt = &mut progress as *mut _ as *mut ffi::c_void; - unsafe { BNSnapshotStoreData(self.as_raw(), data.as_raw(), ctxt, Some(cb_progress::<F>)) } - } - - /// Determine if this snapshot has another as an ancestor - pub fn has_ancestor(self, other: &Snapshot) -> bool { - unsafe { BNSnapshotHasAncestor(self.as_raw(), other.as_raw()) } - } -} - -impl Clone for Snapshot { - fn clone(&self) -> Self { - unsafe { Self::from_raw(ptr::NonNull::new(BNNewSnapshotReference(self.as_raw())).unwrap()) } - } -} - -impl Drop for Snapshot { - fn drop(&mut self) { - unsafe { BNFreeSnapshot(self.as_raw()) } + fn to_owned(&self) -> Self::Owned { + unsafe { RefCountable::inc_ref(self) } } } -impl CoreArrayProvider for Snapshot { - type Raw = *mut BNSnapshot; - type Context = (); - type Wrapped<'a> = &'a Self; -} - -unsafe impl CoreArrayProviderInner for Snapshot { - unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) { - BNFreeSnapshotList(raw, count); - } - - unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> { - Self::ref_from_raw(raw) - } -} - -#[repr(transparent)] -pub struct KeyValueStore { - handle: ptr::NonNull<BNKeyValueStore>, -} - -impl KeyValueStore { - pub(crate) unsafe fn from_raw(handle: ptr::NonNull<BNKeyValueStore>) -> Self { - Self { handle } - } - - #[allow(clippy::mut_from_ref)] - pub(crate) unsafe fn as_raw(&self) -> &mut BNKeyValueStore { - &mut *self.handle.as_ptr() - } - - /// Get a list of all keys stored in the kvs - pub fn keys(&self) -> Array<BnString> { - let mut count = 0; - let result = unsafe { BNGetKeyValueStoreKeys(self.as_raw(), &mut count) }; - assert!(!result.is_null()); - unsafe { Array::new(result, count, ()) } - } - - /// Get the value for a single key - pub fn value<S: BnStrCompatible>(&self, key: S) -> Option<DataBuffer> { - let key_raw = key.into_bytes_with_nul(); - let key_ptr = key_raw.as_ref().as_ptr() as *const ffi::c_char; - let result = unsafe { BNGetKeyValueStoreBuffer(self.as_raw(), key_ptr) }; - ptr::NonNull::new(result).map(|_| DataBuffer::from_raw(result)) - } - - /// Set the value for a single key - pub fn set_value<S: BnStrCompatible>(&self, key: S, value: &DataBuffer) -> bool { - let key_raw = key.into_bytes_with_nul(); - let key_ptr = key_raw.as_ref().as_ptr() as *const ffi::c_char; - unsafe { BNSetKeyValueStoreBuffer(self.as_raw(), key_ptr, value.as_raw()) } - } - - /// Get the stored representation of the kvs - pub fn serialized_data(&self) -> DataBuffer { - let result = unsafe { BNGetKeyValueStoreSerializedData(self.as_raw()) }; - assert!(!result.is_null()); - DataBuffer::from_raw(result) - } - - /// Begin storing new keys into a namespace - pub fn begin_namespace<S: BnStrCompatible>(&self, name: S) { - let name_raw = name.into_bytes_with_nul(); - let name_ptr = name_raw.as_ref().as_ptr() as *const ffi::c_char; - unsafe { BNBeginKeyValueStoreNamespace(self.as_raw(), name_ptr) } - } - - /// End storing new keys into a namespace - pub fn end_namespace(&self) { - unsafe { BNEndKeyValueStoreNamespace(self.as_raw()) } - } - - /// If the kvs is empty - pub fn empty(&self) -> bool { - unsafe { BNIsKeyValueStoreEmpty(self.as_raw()) } - } - - /// Number of values in the kvs - pub fn value_size(&self) -> usize { - unsafe { BNGetKeyValueStoreValueSize(self.as_raw()) } - } - - /// Length of serialized data - pub fn data_size(&self) -> usize { - unsafe { BNGetKeyValueStoreDataSize(self.as_raw()) } - } - - /// Size of all data in storage - pub fn value_storage_size(self) -> usize { - unsafe { BNGetKeyValueStoreValueStorageSize(self.as_raw()) } - } - - /// Number of namespaces pushed with begin_namespace - pub fn namespace_size(self) -> usize { - unsafe { BNGetKeyValueStoreNamespaceSize(self.as_raw()) } - } -} - -impl Clone for KeyValueStore { - fn clone(&self) -> Self { - unsafe { - Self::from_raw(ptr::NonNull::new(BNNewKeyValueStoreReference(self.as_raw())).unwrap()) - } - } -} - -impl Drop for KeyValueStore { - fn drop(&mut self) { - unsafe { BNFreeKeyValueStore(self.as_raw()) } - } -} - -#[repr(transparent)] -pub struct UndoEntry { - handle: ptr::NonNull<BNUndoEntry>, -} - -impl UndoEntry { - pub(crate) unsafe fn from_raw(handle: ptr::NonNull<BNUndoEntry>) -> Self { - Self { handle } - } - - pub(crate) unsafe fn ref_from_raw(handle: &*mut BNUndoEntry) -> &Self { - mem::transmute(handle) - } - - #[allow(clippy::mut_from_ref)] - pub(crate) unsafe fn as_raw(&self) -> &mut BNUndoEntry { - &mut *self.handle.as_ptr() - } - - pub fn id(&self) -> BnString { - let result = unsafe { BNUndoEntryGetId(self.as_raw()) }; - assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } - } - - pub fn actions(&self) -> Array<UndoAction> { - let mut count = 0; - let result = unsafe { BNUndoEntryGetActions(self.as_raw(), &mut count) }; - assert!(!result.is_null()); - unsafe { Array::new(result, count, ()) } - } - - pub fn time(&self) -> SystemTime { - let m = Duration::from_secs(unsafe { BNUndoEntryGetTimestamp(self.as_raw()) }); - UNIX_EPOCH + m - } -} - -impl Clone for UndoEntry { - fn clone(&self) -> Self { - unsafe { - Self::from_raw(ptr::NonNull::new(BNNewUndoEntryReference(self.as_raw())).unwrap()) - } - } -} - -impl Drop for UndoEntry { - fn drop(&mut self) { - unsafe { BNFreeUndoEntry(self.as_raw()) } - } -} - -impl CoreArrayProvider for UndoEntry { - type Raw = *mut BNUndoEntry; - type Context = (); - type Wrapped<'a> = &'a Self; -} - -unsafe impl CoreArrayProviderInner for UndoEntry { - unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) { - BNFreeUndoEntryList(raw, count); - } - - unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> { - Self::ref_from_raw(raw) - } -} - -#[repr(transparent)] -pub struct UndoAction { - handle: ptr::NonNull<BNUndoAction>, -} - -impl UndoAction { - pub(crate) unsafe fn from_raw(handle: ptr::NonNull<BNUndoAction>) -> Self { - Self { handle } - } - - pub(crate) unsafe fn ref_from_raw(handle: &*mut BNUndoAction) -> &Self { - mem::transmute(handle) - } - - #[allow(clippy::mut_from_ref)] - pub(crate) unsafe fn as_raw(&self) -> &mut BNUndoAction { - &mut *self.handle.as_ptr() - } - - pub fn summary_text(&self) -> BnString { - let result = unsafe { BNUndoActionGetSummaryText(self.as_raw()) }; - assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } - } - - pub fn summary(&self) -> Array<InstructionTextToken> { - let mut count = 0; - let result = unsafe { BNUndoActionGetSummary(self.as_raw(), &mut count) }; - assert!(!result.is_null()); - unsafe { Array::new(result, count, ()) } - } -} - -impl Clone for UndoAction { - fn clone(&self) -> Self { - unsafe { - Self::from_raw(ptr::NonNull::new(BNNewUndoActionReference(self.as_raw())).unwrap()) - } - } -} - -impl Drop for UndoAction { - fn drop(&mut self) { - unsafe { BNFreeUndoAction(self.as_raw()) } - } -} - -impl CoreArrayProvider for UndoAction { - type Raw = *mut BNUndoAction; - type Context = (); - type Wrapped<'a> = &'a Self; -} - -unsafe impl CoreArrayProviderInner for UndoAction { - unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) { - BNFreeUndoActionList(raw, count); +unsafe impl RefCountable for Database { + unsafe fn inc_ref(handle: &Self) -> Ref<Self> { + Ref::new(Self { + handle: NonNull::new(BNNewDatabaseReference(handle.handle.as_ptr())).unwrap(), + }) } - unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> { - Self::ref_from_raw(raw) + unsafe fn dec_ref(handle: &Self) { + BNFreeDatabase(handle.handle.as_ptr()); } } - -unsafe extern "C" fn cb_progress<F: FnMut(usize, usize) -> bool>( - ctxt: *mut ffi::c_void, - arg1: usize, - arg2: usize, -) -> bool { - let ctxt: &mut F = &mut *(ctxt as *mut F); - ctxt(arg1, arg2) -} - -unsafe extern "C" fn cb_progress_nop(_ctxt: *mut ffi::c_void, _arg1: usize, _arg2: usize) -> bool { - true -} |
