binaryninja/collaboration/
changeset.rs

1use binaryninjacore_sys::*;
2use std::ptr::NonNull;
3
4use super::{RemoteFile, RemoteUser};
5
6use crate::database::snapshot::SnapshotId;
7use crate::database::Database;
8use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable};
9use crate::string::{BnString, IntoCStr};
10
11/// A collection of snapshots in a local database
12#[repr(transparent)]
13pub struct Changeset {
14    handle: NonNull<BNCollaborationChangeset>,
15}
16
17impl Changeset {
18    pub(crate) unsafe fn from_raw(handle: NonNull<BNCollaborationChangeset>) -> Self {
19        Self { handle }
20    }
21
22    #[allow(unused)]
23    pub(crate) unsafe fn ref_from_raw(handle: NonNull<BNCollaborationChangeset>) -> Ref<Self> {
24        Ref::new(Self { handle })
25    }
26
27    /// Owning database for snapshots
28    pub fn database(&self) -> Result<Database, ()> {
29        let result = unsafe { BNCollaborationChangesetGetDatabase(self.handle.as_ptr()) };
30        let raw = NonNull::new(result).ok_or(())?;
31        Ok(unsafe { Database::from_raw(raw) })
32    }
33
34    /// Relevant remote File object
35    pub fn file(&self) -> Result<Ref<RemoteFile>, ()> {
36        let result = unsafe { BNCollaborationChangesetGetFile(self.handle.as_ptr()) };
37        NonNull::new(result)
38            .map(|raw| unsafe { RemoteFile::ref_from_raw(raw) })
39            .ok_or(())
40    }
41
42    /// List of snapshot ids in the database
43    pub fn snapshot_ids(&self) -> Result<Array<SnapshotId>, ()> {
44        let mut count = 0;
45        let result =
46            unsafe { BNCollaborationChangesetGetSnapshotIds(self.handle.as_ptr(), &mut count) };
47        (!result.is_null())
48            .then(|| unsafe { Array::new(result, count, ()) })
49            .ok_or(())
50    }
51
52    /// Relevant remote author User
53    pub fn author(&self) -> Result<Ref<RemoteUser>, ()> {
54        let result = unsafe { BNCollaborationChangesetGetAuthor(self.handle.as_ptr()) };
55        NonNull::new(result)
56            .map(|raw| unsafe { RemoteUser::ref_from_raw(raw) })
57            .ok_or(())
58    }
59
60    /// Changeset name
61    pub fn name(&self) -> String {
62        let result = unsafe { BNCollaborationChangesetGetName(self.handle.as_ptr()) };
63        assert!(!result.is_null());
64        unsafe { BnString::into_string(result) }
65    }
66
67    /// Set the name of the changeset, e.g. in a name changeset function.
68    pub fn set_name(&self, value: &str) -> bool {
69        let value = value.to_cstr();
70        unsafe { BNCollaborationChangesetSetName(self.handle.as_ptr(), value.as_ptr()) }
71    }
72}
73
74impl ToOwned for Changeset {
75    type Owned = Ref<Self>;
76
77    fn to_owned(&self) -> Self::Owned {
78        unsafe { RefCountable::inc_ref(self) }
79    }
80}
81
82unsafe impl RefCountable for Changeset {
83    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
84        Ref::new(Self {
85            handle: NonNull::new(BNNewCollaborationChangesetReference(handle.handle.as_ptr()))
86                .unwrap(),
87        })
88    }
89
90    unsafe fn dec_ref(handle: &Self) {
91        BNFreeCollaborationChangeset(handle.handle.as_ptr());
92    }
93}
94
95impl CoreArrayProvider for Changeset {
96    type Raw = *mut BNCollaborationChangeset;
97    type Context = ();
98    type Wrapped<'a> = Guard<'a, Self>;
99}
100
101unsafe impl CoreArrayProviderInner for Changeset {
102    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
103        BNFreeCollaborationChangesetList(raw, count)
104    }
105
106    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
107        let raw_ptr = NonNull::new(*raw).unwrap();
108        Guard::new(Self::from_raw(raw_ptr), context)
109    }
110}