1use std::ffi::c_void;
2use std::fmt::Debug;
3use std::path::PathBuf;
4use std::ptr::NonNull;
5use std::time::SystemTime;
6
7use binaryninjacore_sys::*;
8
9use super::{
10 sync, CollaborationPermissionLevel, NameChangeset, Permission, Remote, RemoteFile,
11 RemoteFileType, RemoteFolder,
12};
13
14use crate::binary_view::{BinaryView, BinaryViewExt};
15use crate::database::Database;
16use crate::file_metadata::FileMetadata;
17use crate::progress::{NoProgressCallback, ProgressCallback};
18use crate::project::Project;
19use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable};
20use crate::string::{BnString, IntoCStr};
21
22#[repr(transparent)]
23pub struct RemoteProject {
24 pub(crate) handle: NonNull<BNRemoteProject>,
25}
26
27impl RemoteProject {
28 pub(crate) unsafe fn from_raw(handle: NonNull<BNRemoteProject>) -> Self {
29 Self { handle }
30 }
31
32 pub(crate) unsafe fn ref_from_raw(handle: NonNull<BNRemoteProject>) -> Ref<Self> {
33 Ref::new(Self { handle })
34 }
35
36 pub fn is_open(&self) -> bool {
38 unsafe { BNRemoteProjectIsOpen(self.handle.as_ptr()) }
39 }
40
41 pub fn open(&self) -> Result<(), ()> {
44 self.open_with_progress(NoProgressCallback)
45 }
46
47 pub fn open_with_progress<F: ProgressCallback>(&self, mut progress: F) -> Result<(), ()> {
50 if self.is_open() {
51 return Ok(());
52 }
53 let success = unsafe {
54 BNRemoteProjectOpen(
55 self.handle.as_ptr(),
56 Some(F::cb_progress_callback),
57 &mut progress as *mut F as *mut c_void,
58 )
59 };
60 success.then_some(()).ok_or(())
61 }
62
63 pub fn close(&self) {
65 unsafe { BNRemoteProjectClose(self.handle.as_ptr()) }
66 }
67
68 pub fn get_for_local_database(database: &Database) -> Result<Option<Ref<Self>>, ()> {
70 if sync::pull_projects(database)? {
72 return Ok(None);
73 }
74 sync::get_remote_project_for_local_database(database)
75 }
76
77 pub fn get_for_binaryview(bv: &BinaryView) -> Result<Option<Ref<Self>>, ()> {
79 let file = bv.file();
80 let Some(database) = file.database() else {
81 return Ok(None);
82 };
83 Self::get_for_local_database(&database)
84 }
85
86 pub fn core_project(&self) -> Result<Ref<Project>, ()> {
90 self.open()?;
92
93 let value = unsafe { BNRemoteProjectGetCoreProject(self.handle.as_ptr()) };
94 NonNull::new(value)
95 .map(|handle| unsafe { Project::ref_from_raw(handle) })
96 .ok_or(())
97 }
98
99 pub fn remote(&self) -> Result<Ref<Remote>, ()> {
101 let value = unsafe { BNRemoteProjectGetRemote(self.handle.as_ptr()) };
102 NonNull::new(value)
103 .map(|handle| unsafe { Remote::ref_from_raw(handle) })
104 .ok_or(())
105 }
106
107 pub fn url(&self) -> String {
109 let result = unsafe { BNRemoteProjectGetUrl(self.handle.as_ptr()) };
110 assert!(!result.is_null());
111 unsafe { BnString::into_string(result) }
112 }
113
114 pub fn id(&self) -> String {
116 let result = unsafe { BNRemoteProjectGetId(self.handle.as_ptr()) };
117 assert!(!result.is_null());
118 unsafe { BnString::into_string(result) }
119 }
120
121 pub fn created(&self) -> SystemTime {
123 let result = unsafe { BNRemoteProjectGetCreated(self.handle.as_ptr()) };
124 crate::ffi::time_from_bn(result.try_into().unwrap())
125 }
126
127 pub fn last_modified(&self) -> SystemTime {
129 let result = unsafe { BNRemoteProjectGetLastModified(self.handle.as_ptr()) };
130 crate::ffi::time_from_bn(result.try_into().unwrap())
131 }
132
133 pub fn name(&self) -> String {
135 let result = unsafe { BNRemoteProjectGetName(self.handle.as_ptr()) };
136 assert!(!result.is_null());
137 unsafe { BnString::into_string(result) }
138 }
139
140 pub fn set_name(&self, name: &str) -> Result<(), ()> {
142 let name = name.to_cstr();
143 let success = unsafe { BNRemoteProjectSetName(self.handle.as_ptr(), name.as_ptr()) };
144 success.then_some(()).ok_or(())
145 }
146
147 pub fn description(&self) -> String {
149 let result = unsafe { BNRemoteProjectGetDescription(self.handle.as_ptr()) };
150 assert!(!result.is_null());
151 unsafe { BnString::into_string(result) }
152 }
153
154 pub fn set_description(&self, description: &str) -> Result<(), ()> {
156 let description = description.to_cstr();
157 let success =
158 unsafe { BNRemoteProjectSetDescription(self.handle.as_ptr(), description.as_ptr()) };
159 success.then_some(()).ok_or(())
160 }
161
162 pub fn received_file_count(&self) -> u64 {
164 unsafe { BNRemoteProjectGetReceivedFileCount(self.handle.as_ptr()) }
165 }
166
167 pub fn received_folder_count(&self) -> u64 {
169 unsafe { BNRemoteProjectGetReceivedFolderCount(self.handle.as_ptr()) }
170 }
171
172 pub fn default_path(&self) -> Result<PathBuf, ()> {
175 sync::default_project_path(self)
176 }
177
178 pub fn has_pulled_files(&self) -> bool {
180 unsafe { BNRemoteProjectHasPulledFiles(self.handle.as_ptr()) }
181 }
182
183 pub fn has_pulled_folders(&self) -> bool {
185 unsafe { BNRemoteProjectHasPulledFolders(self.handle.as_ptr()) }
186 }
187
188 pub fn has_pulled_group_permissions(&self) -> bool {
190 unsafe { BNRemoteProjectHasPulledGroupPermissions(self.handle.as_ptr()) }
191 }
192
193 pub fn has_pulled_user_permissions(&self) -> bool {
195 unsafe { BNRemoteProjectHasPulledUserPermissions(self.handle.as_ptr()) }
196 }
197
198 pub fn is_admin(&self) -> bool {
201 unsafe { BNRemoteProjectIsAdmin(self.handle.as_ptr()) }
202 }
203
204 pub fn files(&self) -> Result<Array<RemoteFile>, ()> {
210 if !self.has_pulled_files() {
212 self.pull_files()?;
213 }
214
215 let mut count = 0;
216 let result = unsafe { BNRemoteProjectGetFiles(self.handle.as_ptr(), &mut count) };
217 (!result.is_null())
218 .then(|| unsafe { Array::new(result, count, ()) })
219 .ok_or(())
220 }
221
222 pub fn get_file_by_id(&self, id: &str) -> Result<Option<Ref<RemoteFile>>, ()> {
227 if !self.has_pulled_files() {
229 self.pull_files()?;
230 }
231 let id = id.to_cstr();
232 let result = unsafe { BNRemoteProjectGetFileById(self.handle.as_ptr(), id.as_ptr()) };
233 Ok(NonNull::new(result).map(|handle| unsafe { RemoteFile::ref_from_raw(handle) }))
234 }
235
236 pub fn get_file_by_name(&self, name: &str) -> Result<Option<Ref<RemoteFile>>, ()> {
241 if !self.has_pulled_files() {
243 self.pull_files()?;
244 }
245 let id = name.to_cstr();
246 let result = unsafe { BNRemoteProjectGetFileByName(self.handle.as_ptr(), id.as_ptr()) };
247 Ok(NonNull::new(result).map(|handle| unsafe { RemoteFile::ref_from_raw(handle) }))
248 }
249
250 pub fn pull_files(&self) -> Result<(), ()> {
255 self.pull_files_with_progress(NoProgressCallback)
256 }
257
258 pub fn pull_files_with_progress<P: ProgressCallback>(&self, mut progress: P) -> Result<(), ()> {
263 if !self.has_pulled_folders() {
265 self.pull_folders()?;
266 }
267 let success = unsafe {
268 BNRemoteProjectPullFiles(
269 self.handle.as_ptr(),
270 Some(P::cb_progress_callback),
271 &mut progress as *mut P as *mut c_void,
272 )
273 };
274 success.then_some(()).ok_or(())
275 }
276
277 pub fn create_file(
288 &self,
289 filename: &str,
290 contents: &[u8],
291 name: &str,
292 description: &str,
293 parent_folder: Option<&RemoteFolder>,
294 file_type: RemoteFileType,
295 ) -> Result<Ref<RemoteFile>, ()> {
296 self.create_file_with_progress(
297 filename,
298 contents,
299 name,
300 description,
301 parent_folder,
302 file_type,
303 NoProgressCallback,
304 )
305 }
306
307 pub fn create_file_with_progress<P>(
319 &self,
320 filename: &str,
321 contents: &[u8],
322 name: &str,
323 description: &str,
324 parent_folder: Option<&RemoteFolder>,
325 file_type: RemoteFileType,
326 mut progress: P,
327 ) -> Result<Ref<RemoteFile>, ()>
328 where
329 P: ProgressCallback,
330 {
331 self.open()?;
333
334 let filename = filename.to_cstr();
335 let name = name.to_cstr();
336 let description = description.to_cstr();
337 let folder_handle = parent_folder.map_or(std::ptr::null_mut(), |f| f.handle.as_ptr());
338 let file_ptr = unsafe {
339 BNRemoteProjectCreateFile(
340 self.handle.as_ptr(),
341 filename.as_ptr(),
342 contents.as_ptr() as *mut _,
343 contents.len(),
344 name.as_ptr(),
345 description.as_ptr(),
346 folder_handle,
347 file_type,
348 Some(P::cb_progress_callback),
349 &mut progress as *mut P as *mut c_void,
350 )
351 };
352
353 NonNull::new(file_ptr)
354 .map(|handle| unsafe { RemoteFile::ref_from_raw(handle) })
355 .ok_or(())
356 }
357
358 pub fn push_file<I>(&self, file: &RemoteFile, extra_fields: I) -> Result<(), ()>
362 where
363 I: IntoIterator<Item = (String, String)>,
364 {
365 self.open()?;
367
368 let (keys, values): (Vec<_>, Vec<_>) = extra_fields
369 .into_iter()
370 .map(|(k, v)| (k.to_cstr(), v.to_cstr()))
371 .unzip();
372 let mut keys_raw = keys.iter().map(|s| s.as_ptr()).collect::<Vec<_>>();
373 let mut values_raw = values.iter().map(|s| s.as_ptr()).collect::<Vec<_>>();
374 let success = unsafe {
375 BNRemoteProjectPushFile(
376 self.handle.as_ptr(),
377 file.handle.as_ptr(),
378 keys_raw.as_mut_ptr(),
379 values_raw.as_mut_ptr(),
380 keys_raw.len(),
381 )
382 };
383 success.then_some(()).ok_or(())
384 }
385
386 pub fn delete_file(&self, file: &RemoteFile) -> Result<(), ()> {
387 self.open()?;
389
390 let success =
391 unsafe { BNRemoteProjectDeleteFile(self.handle.as_ptr(), file.handle.as_ptr()) };
392 success.then_some(()).ok_or(())
393 }
394
395 pub fn folders(&self) -> Result<Array<RemoteFolder>, ()> {
400 if !self.has_pulled_folders() {
402 self.pull_folders()?;
403 }
404 let mut count = 0;
405 let result = unsafe { BNRemoteProjectGetFolders(self.handle.as_ptr(), &mut count) };
406 if result.is_null() {
407 return Err(());
408 }
409 Ok(unsafe { Array::new(result, count, ()) })
410 }
411
412 pub fn get_folder_by_id(&self, id: &str) -> Result<Option<Ref<RemoteFolder>>, ()> {
417 if !self.has_pulled_folders() {
419 self.pull_folders()?;
420 }
421 let id = id.to_cstr();
422 let result = unsafe { BNRemoteProjectGetFolderById(self.handle.as_ptr(), id.as_ptr()) };
423 Ok(NonNull::new(result).map(|handle| unsafe { RemoteFolder::ref_from_raw(handle) }))
424 }
425
426 pub fn pull_folders(&self) -> Result<(), ()> {
430 self.pull_folders_with_progress(NoProgressCallback)
431 }
432
433 pub fn pull_folders_with_progress<P: ProgressCallback>(
437 &self,
438 mut progress: P,
439 ) -> Result<(), ()> {
440 self.open()?;
442
443 let success = unsafe {
444 BNRemoteProjectPullFolders(
445 self.handle.as_ptr(),
446 Some(P::cb_progress_callback),
447 &mut progress as *mut P as *mut c_void,
448 )
449 };
450 success.then_some(()).ok_or(())
451 }
452
453 pub fn create_folder(
461 &self,
462 name: &str,
463 description: &str,
464 parent_folder: Option<&RemoteFolder>,
465 ) -> Result<Ref<RemoteFolder>, ()> {
466 self.create_folder_with_progress(name, description, parent_folder, NoProgressCallback)
467 }
468
469 pub fn create_folder_with_progress<P>(
478 &self,
479 name: &str,
480 description: &str,
481 parent_folder: Option<&RemoteFolder>,
482 mut progress: P,
483 ) -> Result<Ref<RemoteFolder>, ()>
484 where
485 P: ProgressCallback,
486 {
487 self.open()?;
489
490 let name = name.to_cstr();
491 let description = description.to_cstr();
492 let folder_handle = parent_folder.map_or(std::ptr::null_mut(), |f| f.handle.as_ptr());
493 let file_ptr = unsafe {
494 BNRemoteProjectCreateFolder(
495 self.handle.as_ptr(),
496 name.as_ptr(),
497 description.as_ptr(),
498 folder_handle,
499 Some(P::cb_progress_callback),
500 &mut progress as *mut P as *mut c_void,
501 )
502 };
503
504 NonNull::new(file_ptr)
505 .map(|handle| unsafe { RemoteFolder::ref_from_raw(handle) })
506 .ok_or(())
507 }
508
509 pub fn push_folder<I>(&self, folder: &RemoteFolder, extra_fields: I) -> Result<(), ()>
516 where
517 I: IntoIterator<Item = (String, String)>,
518 {
519 self.open()?;
521
522 let (keys, values): (Vec<_>, Vec<_>) = extra_fields
523 .into_iter()
524 .map(|(k, v)| (k.to_cstr(), v.to_cstr()))
525 .unzip();
526 let mut keys_raw = keys.iter().map(|s| s.as_ptr()).collect::<Vec<_>>();
527 let mut values_raw = values.iter().map(|s| s.as_ptr()).collect::<Vec<_>>();
528 let success = unsafe {
529 BNRemoteProjectPushFolder(
530 self.handle.as_ptr(),
531 folder.handle.as_ptr(),
532 keys_raw.as_mut_ptr(),
533 values_raw.as_mut_ptr(),
534 keys_raw.len(),
535 )
536 };
537 success.then_some(()).ok_or(())
538 }
539
540 pub fn delete_folder(&self, folder: &RemoteFolder) -> Result<(), ()> {
544 self.open()?;
546
547 let success =
548 unsafe { BNRemoteProjectDeleteFolder(self.handle.as_ptr(), folder.handle.as_ptr()) };
549 success.then_some(()).ok_or(())
550 }
551
552 pub fn group_permissions(&self) -> Result<Array<Permission>, ()> {
556 if !self.has_pulled_group_permissions() {
558 self.pull_group_permissions()?;
559 }
560
561 let mut count: usize = 0;
562 let value = unsafe { BNRemoteProjectGetGroupPermissions(self.handle.as_ptr(), &mut count) };
563 assert!(!value.is_null());
564 Ok(unsafe { Array::new(value, count, ()) })
565 }
566
567 pub fn user_permissions(&self) -> Result<Array<Permission>, ()> {
571 if !self.has_pulled_user_permissions() {
573 self.pull_user_permissions()?;
574 }
575
576 let mut count: usize = 0;
577 let value = unsafe { BNRemoteProjectGetUserPermissions(self.handle.as_ptr(), &mut count) };
578 assert!(!value.is_null());
579 Ok(unsafe { Array::new(value, count, ()) })
580 }
581
582 pub fn get_permission_by_id(&self, id: &str) -> Result<Option<Ref<Permission>>, ()> {
586 if !self.has_pulled_user_permissions() {
588 self.pull_user_permissions()?;
589 }
590 if !self.has_pulled_group_permissions() {
592 self.pull_group_permissions()?;
593 }
594
595 let id = id.to_cstr();
596 let value = unsafe {
597 BNRemoteProjectGetPermissionById(self.handle.as_ptr(), id.as_ref().as_ptr() as *const _)
598 };
599 Ok(NonNull::new(value).map(|v| unsafe { Permission::ref_from_raw(v) }))
600 }
601
602 pub fn pull_group_permissions(&self) -> Result<(), ()> {
604 self.pull_group_permissions_with_progress(NoProgressCallback)
605 }
606
607 pub fn pull_group_permissions_with_progress<F: ProgressCallback>(
609 &self,
610 mut progress: F,
611 ) -> Result<(), ()> {
612 let success = unsafe {
613 BNRemoteProjectPullGroupPermissions(
614 self.handle.as_ptr(),
615 Some(F::cb_progress_callback),
616 &mut progress as *mut F as *mut c_void,
617 )
618 };
619 success.then_some(()).ok_or(())
620 }
621
622 pub fn pull_user_permissions(&self) -> Result<(), ()> {
624 self.pull_user_permissions_with_progress(NoProgressCallback)
625 }
626
627 pub fn pull_user_permissions_with_progress<F: ProgressCallback>(
629 &self,
630 mut progress: F,
631 ) -> Result<(), ()> {
632 let success = unsafe {
633 BNRemoteProjectPullUserPermissions(
634 self.handle.as_ptr(),
635 Some(F::cb_progress_callback),
636 &mut progress as *mut F as *mut c_void,
637 )
638 };
639 success.then_some(()).ok_or(())
640 }
641
642 pub fn create_group_permission(
649 &self,
650 group_id: i64,
651 level: CollaborationPermissionLevel,
652 ) -> Result<Ref<Permission>, ()> {
653 self.create_group_permission_with_progress(group_id, level, NoProgressCallback)
654 }
655
656 pub fn create_group_permission_with_progress<F: ProgressCallback>(
664 &self,
665 group_id: i64,
666 level: CollaborationPermissionLevel,
667 mut progress: F,
668 ) -> Result<Ref<Permission>, ()> {
669 let value = unsafe {
670 BNRemoteProjectCreateGroupPermission(
671 self.handle.as_ptr(),
672 group_id,
673 level,
674 Some(F::cb_progress_callback),
675 &mut progress as *mut F as *mut c_void,
676 )
677 };
678
679 NonNull::new(value)
680 .map(|v| unsafe { Permission::ref_from_raw(v) })
681 .ok_or(())
682 }
683
684 pub fn create_user_permission(
691 &self,
692 user_id: &str,
693 level: CollaborationPermissionLevel,
694 ) -> Result<Ref<Permission>, ()> {
695 self.create_user_permission_with_progress(user_id, level, NoProgressCallback)
696 }
697
698 pub fn create_user_permission_with_progress<F: ProgressCallback>(
706 &self,
707 user_id: &str,
708 level: CollaborationPermissionLevel,
709 mut progress: F,
710 ) -> Result<Ref<Permission>, ()> {
711 let user_id = user_id.to_cstr();
712 let value = unsafe {
713 BNRemoteProjectCreateUserPermission(
714 self.handle.as_ptr(),
715 user_id.as_ptr(),
716 level,
717 Some(F::cb_progress_callback),
718 &mut progress as *mut F as *mut c_void,
719 )
720 };
721
722 NonNull::new(value)
723 .map(|v| unsafe { Permission::ref_from_raw(v) })
724 .ok_or(())
725 }
726
727 pub fn push_permission<I>(&self, permission: &Permission, extra_fields: I) -> Result<(), ()>
734 where
735 I: IntoIterator<Item = (String, String)>,
736 {
737 let (keys, values): (Vec<_>, Vec<_>) = extra_fields
738 .into_iter()
739 .map(|(k, v)| (k.to_cstr(), v.to_cstr()))
740 .unzip();
741 let mut keys_raw = keys.iter().map(|s| s.as_ptr()).collect::<Vec<_>>();
742 let mut values_raw = values.iter().map(|s| s.as_ptr()).collect::<Vec<_>>();
743
744 let success = unsafe {
745 BNRemoteProjectPushPermission(
746 self.handle.as_ptr(),
747 permission.handle.as_ptr(),
748 keys_raw.as_mut_ptr(),
749 values_raw.as_mut_ptr(),
750 keys_raw.len(),
751 )
752 };
753 success.then_some(()).ok_or(())
754 }
755
756 pub fn delete_permission(&self, permission: &Permission) -> Result<(), ()> {
758 let success = unsafe {
759 BNRemoteProjectDeletePermission(self.handle.as_ptr(), permission.handle.as_ptr())
760 };
761 success.then_some(()).ok_or(())
762 }
763
764 pub fn can_user_view(&self, username: &str) -> bool {
770 let username = username.to_cstr();
771 unsafe { BNRemoteProjectCanUserView(self.handle.as_ptr(), username.as_ptr()) }
772 }
773
774 pub fn can_user_edit(&self, username: &str) -> bool {
780 let username = username.to_cstr();
781 unsafe { BNRemoteProjectCanUserEdit(self.handle.as_ptr(), username.as_ptr()) }
782 }
783
784 pub fn can_user_admin(&self, username: &str) -> bool {
790 let username = username.to_cstr();
791 unsafe { BNRemoteProjectCanUserAdmin(self.handle.as_ptr(), username.as_ptr()) }
792 }
793
794 pub fn default_project_path(&self) -> String {
798 let result = unsafe { BNCollaborationDefaultProjectPath(self.handle.as_ptr()) };
799 unsafe { BnString::into_string(result) }
800 }
801
802 pub fn upload_database<C>(
808 &self,
809 metadata: &FileMetadata,
810 parent_folder: Option<&RemoteFolder>,
811 name_changeset: C,
812 ) -> Result<Ref<RemoteFile>, ()>
813 where
814 C: NameChangeset,
815 {
816 if !self.has_pulled_files() {
820 self.pull_files()?;
821 }
822 sync::upload_database(self, parent_folder, metadata, name_changeset)
823 }
824
825 pub fn upload_database_with_progress<C>(
832 &self,
833 metadata: &FileMetadata,
834 parent_folder: Option<&RemoteFolder>,
835 name_changeset: C,
836 progress_function: impl ProgressCallback,
837 ) -> Result<Ref<RemoteFile>, ()>
838 where
839 C: NameChangeset,
840 {
841 sync::upload_database_with_progress(
842 self,
843 parent_folder,
844 metadata,
845 name_changeset,
846 progress_function,
847 )
848 }
849
850 }
873
874impl Debug for RemoteProject {
875 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
876 f.debug_struct("RemoteProject")
877 .field("id", &self.id())
878 .field("name", &self.name())
879 .field("description", &self.description())
880 .finish()
881 }
882}
883
884impl PartialEq for RemoteProject {
885 fn eq(&self, other: &Self) -> bool {
886 self.id() == other.id()
887 }
888}
889
890impl Eq for RemoteProject {}
891
892impl ToOwned for RemoteProject {
893 type Owned = Ref<Self>;
894
895 fn to_owned(&self) -> Self::Owned {
896 unsafe { RefCountable::inc_ref(self) }
897 }
898}
899
900unsafe impl Send for RemoteProject {}
901unsafe impl Sync for RemoteProject {}
902
903unsafe impl RefCountable for RemoteProject {
904 unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
905 Ref::new(Self {
906 handle: NonNull::new(BNNewRemoteProjectReference(handle.handle.as_ptr())).unwrap(),
907 })
908 }
909
910 unsafe fn dec_ref(handle: &Self) {
911 BNFreeRemoteProject(handle.handle.as_ptr());
912 }
913}
914
915impl CoreArrayProvider for RemoteProject {
916 type Raw = *mut BNRemoteProject;
917 type Context = ();
918 type Wrapped<'a> = Guard<'a, Self>;
919}
920
921unsafe impl CoreArrayProviderInner for RemoteProject {
922 unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
923 BNFreeRemoteProjectList(raw, count)
924 }
925
926 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
927 let raw_ptr = NonNull::new(*raw).unwrap();
928 Guard::new(Self::from_raw(raw_ptr), context)
929 }
930}