binaryninja/database/
undo.rs1use crate::disassembly::InstructionTextToken;
2use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable};
3use crate::string::BnString;
4use binaryninjacore_sys::{
5 BNFreeUndoAction, BNFreeUndoActionList, BNFreeUndoEntry, BNFreeUndoEntryList,
6 BNNewUndoActionReference, BNNewUndoEntryReference, BNUndoAction, BNUndoActionGetSummary,
7 BNUndoActionGetSummaryText, BNUndoEntry, BNUndoEntryGetActions, BNUndoEntryGetId,
8 BNUndoEntryGetTimestamp,
9};
10use std::fmt::Debug;
11use std::ptr::NonNull;
12use std::time::{Duration, SystemTime, UNIX_EPOCH};
13
14#[repr(transparent)]
15pub struct UndoEntry {
16 handle: NonNull<BNUndoEntry>,
17}
18
19impl UndoEntry {
20 pub(crate) unsafe fn from_raw(handle: NonNull<BNUndoEntry>) -> Self {
21 Self { handle }
22 }
23
24 #[allow(dead_code)]
25 pub(crate) unsafe fn ref_from_raw(handle: NonNull<BNUndoEntry>) -> Ref<Self> {
26 Ref::new(Self { handle })
27 }
28
29 pub fn id(&self) -> String {
30 let result = unsafe { BNUndoEntryGetId(self.handle.as_ptr()) };
31 assert!(!result.is_null());
32 unsafe { BnString::into_string(result) }
33 }
34
35 pub fn actions(&self) -> Array<UndoAction> {
36 let mut count = 0;
37 let result = unsafe { BNUndoEntryGetActions(self.handle.as_ptr(), &mut count) };
38 assert!(!result.is_null());
39 unsafe { Array::new(result, count, ()) }
40 }
41
42 pub fn time(&self) -> SystemTime {
43 let m = Duration::from_secs(unsafe { BNUndoEntryGetTimestamp(self.handle.as_ptr()) });
44 UNIX_EPOCH + m
45 }
46}
47
48impl Debug for UndoEntry {
49 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
50 f.debug_struct("UndoEntry")
51 .field("id", &self.id())
52 .field("time", &self.time())
53 .field("actions", &self.actions().to_vec())
54 .finish()
55 }
56}
57
58impl ToOwned for UndoEntry {
59 type Owned = Ref<Self>;
60
61 fn to_owned(&self) -> Self::Owned {
62 unsafe { RefCountable::inc_ref(self) }
63 }
64}
65
66unsafe impl RefCountable for UndoEntry {
67 unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
68 Ref::new(Self {
69 handle: NonNull::new(BNNewUndoEntryReference(handle.handle.as_ptr())).unwrap(),
70 })
71 }
72
73 unsafe fn dec_ref(handle: &Self) {
74 BNFreeUndoEntry(handle.handle.as_ptr());
75 }
76}
77
78impl CoreArrayProvider for UndoEntry {
79 type Raw = *mut BNUndoEntry;
80 type Context = ();
81 type Wrapped<'a> = Guard<'a, UndoEntry>;
82}
83
84unsafe impl CoreArrayProviderInner for UndoEntry {
85 unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
86 BNFreeUndoEntryList(raw, count);
87 }
88
89 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
90 let raw_ptr = NonNull::new(*raw).unwrap();
91 Guard::new(Self::from_raw(raw_ptr), context)
92 }
93}
94
95#[repr(transparent)]
96pub struct UndoAction {
97 handle: NonNull<BNUndoAction>,
98}
99
100impl UndoAction {
101 pub(crate) unsafe fn from_raw(handle: NonNull<BNUndoAction>) -> Self {
102 Self { handle }
103 }
104
105 #[allow(dead_code)]
106 pub(crate) unsafe fn ref_from_raw(handle: NonNull<BNUndoAction>) -> Ref<Self> {
107 Ref::new(Self { handle })
108 }
109
110 pub fn summary(&self) -> Array<InstructionTextToken> {
111 let mut count = 0;
112 let result = unsafe { BNUndoActionGetSummary(self.handle.as_ptr(), &mut count) };
113 assert!(!result.is_null());
114 unsafe { Array::new(result, count, ()) }
115 }
116
117 pub fn summary_as_string(&self) -> String {
119 let result = unsafe { BNUndoActionGetSummaryText(self.handle.as_ptr()) };
120 assert!(!result.is_null());
121 unsafe { BnString::into_string(result) }
122 }
123}
124
125impl Debug for UndoAction {
126 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
127 f.debug_struct("UndoAction")
128 .field("summary", &self.summary_as_string())
129 .finish()
130 }
131}
132
133impl ToOwned for UndoAction {
134 type Owned = Ref<Self>;
135
136 fn to_owned(&self) -> Self::Owned {
137 unsafe { RefCountable::inc_ref(self) }
138 }
139}
140
141unsafe impl RefCountable for UndoAction {
142 unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
143 Ref::new(Self {
144 handle: NonNull::new(BNNewUndoActionReference(handle.handle.as_ptr())).unwrap(),
145 })
146 }
147
148 unsafe fn dec_ref(handle: &Self) {
149 BNFreeUndoAction(handle.handle.as_ptr());
150 }
151}
152
153impl CoreArrayProvider for UndoAction {
154 type Raw = *mut BNUndoAction;
155 type Context = ();
156 type Wrapped<'a> = Guard<'a, UndoAction>;
157}
158
159unsafe impl CoreArrayProviderInner for UndoAction {
160 unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
161 BNFreeUndoActionList(raw, count);
162 }
163
164 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
165 let raw_ptr = NonNull::new(*raw).unwrap();
166 Guard::new(Self::from_raw(raw_ptr), context)
167 }
168}