summaryrefslogtreecommitdiff
path: root/rust/src/database/undo.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rust/src/database/undo.rs')
-rw-r--r--rust/src/database/undo.rs168
1 files changed, 168 insertions, 0 deletions
diff --git a/rust/src/database/undo.rs b/rust/src/database/undo.rs
new file mode 100644
index 00000000..727a777b
--- /dev/null
+++ b/rust/src/database/undo.rs
@@ -0,0 +1,168 @@
+use crate::disassembly::InstructionTextToken;
+use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable};
+use crate::string::BnString;
+use binaryninjacore_sys::{
+ BNFreeUndoAction, BNFreeUndoActionList, BNFreeUndoEntry, BNFreeUndoEntryList,
+ BNNewUndoActionReference, BNNewUndoEntryReference, BNUndoAction, BNUndoActionGetSummary,
+ BNUndoActionGetSummaryText, BNUndoEntry, BNUndoEntryGetActions, BNUndoEntryGetId,
+ BNUndoEntryGetTimestamp,
+};
+use std::fmt::Debug;
+use std::ptr::NonNull;
+use std::time::{Duration, SystemTime, UNIX_EPOCH};
+
+#[repr(transparent)]
+pub struct UndoEntry {
+ handle: NonNull<BNUndoEntry>,
+}
+
+impl UndoEntry {
+ pub(crate) unsafe fn from_raw(handle: NonNull<BNUndoEntry>) -> Self {
+ Self { handle }
+ }
+
+ #[allow(dead_code)]
+ pub(crate) unsafe fn ref_from_raw(handle: NonNull<BNUndoEntry>) -> Ref<Self> {
+ Ref::new(Self { handle })
+ }
+
+ pub fn id(&self) -> BnString {
+ let result = unsafe { BNUndoEntryGetId(self.handle.as_ptr()) };
+ assert!(!result.is_null());
+ unsafe { BnString::from_raw(result) }
+ }
+
+ pub fn actions(&self) -> Array<UndoAction> {
+ let mut count = 0;
+ let result = unsafe { BNUndoEntryGetActions(self.handle.as_ptr(), &mut count) };
+ assert!(!result.is_null());
+ unsafe { Array::new(result, count, ()) }
+ }
+
+ pub fn time(&self) -> SystemTime {
+ let m = Duration::from_secs(unsafe { BNUndoEntryGetTimestamp(self.handle.as_ptr()) });
+ UNIX_EPOCH + m
+ }
+}
+
+impl Debug for UndoEntry {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.debug_struct("UndoEntry")
+ .field("id", &self.id())
+ .field("time", &self.time())
+ .field("actions", &self.actions().to_vec())
+ .finish()
+ }
+}
+
+impl ToOwned for UndoEntry {
+ type Owned = Ref<Self>;
+
+ fn to_owned(&self) -> Self::Owned {
+ unsafe { RefCountable::inc_ref(self) }
+ }
+}
+
+unsafe impl RefCountable for UndoEntry {
+ unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
+ Ref::new(Self {
+ handle: NonNull::new(BNNewUndoEntryReference(handle.handle.as_ptr())).unwrap(),
+ })
+ }
+
+ unsafe fn dec_ref(handle: &Self) {
+ BNFreeUndoEntry(handle.handle.as_ptr());
+ }
+}
+
+impl CoreArrayProvider for UndoEntry {
+ type Raw = *mut BNUndoEntry;
+ type Context = ();
+ type Wrapped<'a> = Guard<'a, UndoEntry>;
+}
+
+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> {
+ let raw_ptr = NonNull::new(*raw).unwrap();
+ Guard::new(Self::from_raw(raw_ptr), context)
+ }
+}
+
+#[repr(transparent)]
+pub struct UndoAction {
+ handle: NonNull<BNUndoAction>,
+}
+
+impl UndoAction {
+ pub(crate) unsafe fn from_raw(handle: NonNull<BNUndoAction>) -> Self {
+ Self { handle }
+ }
+
+ #[allow(dead_code)]
+ pub(crate) unsafe fn ref_from_raw(handle: NonNull<BNUndoAction>) -> Ref<Self> {
+ Ref::new(Self { handle })
+ }
+
+ pub fn summary(&self) -> Array<InstructionTextToken> {
+ let mut count = 0;
+ let result = unsafe { BNUndoActionGetSummary(self.handle.as_ptr(), &mut count) };
+ assert!(!result.is_null());
+ unsafe { Array::new(result, count, ()) }
+ }
+
+ /// Gets the [`UndoAction`] summary as text rather than [`InstructionTextToken`]'s.
+ pub fn summary_as_string(&self) -> BnString {
+ let result = unsafe { BNUndoActionGetSummaryText(self.handle.as_ptr()) };
+ assert!(!result.is_null());
+ unsafe { BnString::from_raw(result) }
+ }
+}
+
+impl Debug for UndoAction {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.debug_struct("UndoAction")
+ .field("summary", &self.summary_as_string())
+ .finish()
+ }
+}
+
+impl ToOwned for UndoAction {
+ type Owned = Ref<Self>;
+
+ fn to_owned(&self) -> Self::Owned {
+ unsafe { RefCountable::inc_ref(self) }
+ }
+}
+
+unsafe impl RefCountable for UndoAction {
+ unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
+ Ref::new(Self {
+ handle: NonNull::new(BNNewUndoActionReference(handle.handle.as_ptr())).unwrap(),
+ })
+ }
+
+ unsafe fn dec_ref(handle: &Self) {
+ BNFreeUndoAction(handle.handle.as_ptr());
+ }
+}
+
+impl CoreArrayProvider for UndoAction {
+ type Raw = *mut BNUndoAction;
+ type Context = ();
+ type Wrapped<'a> = Guard<'a, UndoAction>;
+}
+
+unsafe impl CoreArrayProviderInner for UndoAction {
+ unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
+ BNFreeUndoActionList(raw, count);
+ }
+
+ unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
+ let raw_ptr = NonNull::new(*raw).unwrap();
+ Guard::new(Self::from_raw(raw_ptr), context)
+ }
+}