@@ -83,16 +83,17 @@ macro_rules! trait_handler {
8383 ) -> DataNotificationHandle <' a, H > {
8484 // SAFETY: this leak is undone on drop
8585 let leak_notify = Box :: leak( Box :: new( notify) ) ;
86- let handle = BNBinaryDataNotification {
86+ let notifications = BNBinaryDataNotification {
8787 context: leak_notify as * mut _ as * mut c_void,
88+ unregistered: None ,
8889 $( $ffi_param_name: triggers. $fun_name. then_some( $fun_name:: <H >) ) ,* ,
8990 // TODO: Require all BNBinaryDataNotification's to be implemented?
9091 // Since core developers are not required to write Rust bindings (yet) we do not
91- // force new binary data notifications callbacks to be written here.of core developers who do not wish to write
92+ // force new binary data notifications callbacks to be written here.
9293 ..Default :: default ( )
9394 } ;
9495 // Box it to prevent a copy being returned in `DataNotificationHandle`.
95- let mut boxed_handle = Box :: new( handle ) ;
96+ let mut boxed_handle = Box :: new( notifications ) ;
9697 unsafe { BNRegisterDataNotification ( view. handle, boxed_handle. as_mut( ) ) } ;
9798 DataNotificationHandle {
9899 bv: view. to_owned( ) ,
@@ -101,12 +102,38 @@ macro_rules! trait_handler {
101102 }
102103 }
103104
104- /// Implement closures that will be called by on the event of data modification.
105+ fn register_persisted_data_notification<' a, H : CustomDataNotification + ' a>(
106+ view: & BinaryView ,
107+ notify: H ,
108+ triggers: DataNotificationTriggers ,
109+ ) -> PersistedDataNotificationHandle <' a, H > {
110+ // SAFETY: this leak is undone on drop
111+ let leak_notify = Box :: leak( Box :: new( notify) ) ;
112+ // NOTE: The notification structure here is passed as ptr but eventually gets copied, so
113+ // the lifetime of this object just needs to live to after `BNRegisterDataNotification`.
114+ let notifications = BNBinaryDataNotification {
115+ context: leak_notify as * mut _ as * mut c_void,
116+ unregistered: Some ( cb_unregistered:: <H >) ,
117+ $( $ffi_param_name: triggers. $fun_name. then_some( $fun_name:: <H >) ) ,* ,
118+ // TODO: Require all BNBinaryDataNotification's to be implemented?
119+ // Since core developers are not required to write Rust bindings (yet) we do not
120+ // force new binary data notifications callbacks to be written here.
121+ ..Default :: default ( )
122+ } ;
123+ let mut boxed_handle = Box :: new( notifications) ;
124+ unsafe { BNRegisterDataNotification ( view. handle, boxed_handle. as_mut( ) ) } ;
125+ PersistedDataNotificationHandle {
126+ handle: boxed_handle,
127+ _life: std:: marker:: PhantomData ,
128+ }
129+ }
130+
131+ /// Implement closures that will be called in the event of data modification.
105132 ///
106- /// Once dropped the closures will stop being called.
133+ /// Once dropped, the closures will stop being called.
107134 ///
108135 /// NOTE: Closures are not executed on the same thread as the event that occurred, you must not depend
109- /// on any serial behavior
136+ /// on any serial behavior.
110137 ///
111138 /// # Example
112139 ///
@@ -148,6 +175,8 @@ macro_rules! trait_handler {
148175 ) *
149176
150177 /// Register the closures to be notified up until the [`DataNotificationHandle`] is dropped.
178+ ///
179+ /// If you need to have the closures notified indefinitely, use [`DataNotificationClosure::register_persisted`].
151180 pub fn register(
152181 self ,
153182 view: & BinaryView ,
@@ -160,6 +189,20 @@ macro_rules! trait_handler {
160189 ) *
161190 register_data_notification( view, self , triggers)
162191 }
192+
193+ /// Register the closures to be notified up until the [`BinaryView`] is dropped.
194+ pub fn register_persisted(
195+ self ,
196+ view: & BinaryView ,
197+ ) -> PersistedDataNotificationHandle <' a, Self > {
198+ let mut triggers = DataNotificationTriggers :: default ( ) ;
199+ $(
200+ if self . $fun_name. is_some( ) {
201+ triggers = triggers. $fun_name( ) ;
202+ }
203+ ) *
204+ register_persisted_data_notification( view, self , triggers)
205+ }
163206 }
164207
165208 impl CustomDataNotification for DataNotificationClosure <' _> {
@@ -352,27 +395,27 @@ trait_handler! {
352395 var: * mut BNDataVariable : & DataVariable = & DataVariable :: from_raw( & * var) ,
353396 ) ,
354397 externalLibraryAdded => external_library_added(
355- data : * mut BNBinaryView : & BinaryView = & BinaryView :: from_raw( data ) ,
398+ view : * mut BNBinaryView : & BinaryView = & BinaryView :: from_raw( view ) ,
356399 library: * mut BNExternalLibrary : & ExternalLibrary = & ExternalLibrary :: from_raw( NonNull :: new( library) . unwrap( ) ) ,
357400 ) ,
358401 externalLibraryUpdated => external_library_updated(
359- data : * mut BNBinaryView : & BinaryView = & BinaryView :: from_raw( data ) ,
402+ view : * mut BNBinaryView : & BinaryView = & BinaryView :: from_raw( view ) ,
360403 library: * mut BNExternalLibrary : & ExternalLibrary = & ExternalLibrary :: from_raw( NonNull :: new( library) . unwrap( ) ) ,
361404 ) ,
362405 externalLibraryRemoved => external_library_removed(
363- data : * mut BNBinaryView : & BinaryView = & BinaryView :: from_raw( data ) ,
406+ view : * mut BNBinaryView : & BinaryView = & BinaryView :: from_raw( view ) ,
364407 library: * mut BNExternalLibrary : & ExternalLibrary = & ExternalLibrary :: from_raw( NonNull :: new( library) . unwrap( ) ) ,
365408 ) ,
366409 externalLocationAdded => external_location_added(
367- data : * mut BNBinaryView : & BinaryView = & BinaryView :: from_raw( data ) ,
410+ view : * mut BNBinaryView : & BinaryView = & BinaryView :: from_raw( view ) ,
368411 location: * mut BNExternalLocation : & ExternalLocation = & ExternalLocation :: from_raw( NonNull :: new( location) . unwrap( ) ) ,
369412 ) ,
370413 externalLocationUpdated => external_location_updated(
371- data : * mut BNBinaryView : & BinaryView = & BinaryView :: from_raw( data ) ,
414+ view : * mut BNBinaryView : & BinaryView = & BinaryView :: from_raw( view ) ,
372415 location: * mut BNExternalLocation : & ExternalLocation = & ExternalLocation :: from_raw( NonNull :: new( location) . unwrap( ) ) ,
373416 ) ,
374417 externalLocationRemoved => external_location_removed(
375- data : * mut BNBinaryView : & BinaryView = & BinaryView :: from_raw( data ) ,
418+ view : * mut BNBinaryView : & BinaryView = & BinaryView :: from_raw( view ) ,
376419 location: * mut BNExternalLocation : & ExternalLocation = & ExternalLocation :: from_raw( NonNull :: new( location) . unwrap( ) ) ,
377420 ) ,
378421 typeArchiveAttached => type_archive_attached(
@@ -406,8 +449,8 @@ trait_handler! {
406449 entry: * mut BNUndoEntry : & UndoEntry = & UndoEntry :: from_raw( NonNull :: new( entry) . unwrap( ) ) ,
407450 ) ,
408451 rebased => rebased(
409- oldview : * mut BNBinaryView : & BinaryView = & BinaryView :: from_raw( oldview ) ,
410- newview : * mut BNBinaryView : & BinaryView = & BinaryView :: from_raw( newview ) ,
452+ old_view : * mut BNBinaryView : & BinaryView = & BinaryView :: from_raw( old_view ) ,
453+ new_view : * mut BNBinaryView : & BinaryView = & BinaryView :: from_raw( new_view ) ,
411454 ) ,
412455}
413456
@@ -430,7 +473,7 @@ impl<T: CustomDataNotification> DataNotificationHandle<'_, T> {
430473 }
431474
432475 pub fn unregister ( self ) -> T {
433- // NOTE don 't drop the ctxt, return it
476+ // NOTE: Don 't drop the ctxt, return it
434477 let mut slf = core:: mem:: ManuallyDrop :: new ( self ) ;
435478 unsafe { slf. unregister_bv ( ) } ;
436479 unsafe { * slf. extract_context ( ) }
@@ -444,3 +487,38 @@ impl<T: CustomDataNotification> Drop for DataNotificationHandle<'_, T> {
444487 let _ctxt = unsafe { self . extract_context ( ) } ;
445488 }
446489}
490+
491+ unsafe impl < T : CustomDataNotification > Send for DataNotificationHandle < ' _ , T > { }
492+ unsafe impl < T : CustomDataNotification > Sync for DataNotificationHandle < ' _ , T > { }
493+
494+ pub struct PersistedDataNotificationHandle < ' a , T : CustomDataNotification >
495+ where
496+ T : ' a ,
497+ {
498+ handle : Box < BNBinaryDataNotification > ,
499+ _life : std:: marker:: PhantomData < & ' a T > ,
500+ }
501+
502+ impl < T : CustomDataNotification > PersistedDataNotificationHandle < ' _ , T > {
503+ unsafe fn unregister_bv ( & mut self , view : & BinaryView ) {
504+ BNUnregisterDataNotification ( view. handle , self . handle . as_mut ( ) )
505+ }
506+
507+ unsafe fn extract_context ( & mut self ) -> Box < T > {
508+ Box :: from_raw ( self . handle . context as * mut T )
509+ }
510+
511+ pub fn unregister ( self , view : & BinaryView ) -> T {
512+ // NOTE: Don't drop the ctxt, return it
513+ let mut slf = core:: mem:: ManuallyDrop :: new ( self ) ;
514+ unsafe { slf. unregister_bv ( view) } ;
515+ unsafe { * slf. extract_context ( ) }
516+ }
517+ }
518+
519+ unsafe impl < T : CustomDataNotification > Send for PersistedDataNotificationHandle < ' _ , T > { }
520+ unsafe impl < T : CustomDataNotification > Sync for PersistedDataNotificationHandle < ' _ , T > { }
521+
522+ unsafe extern "C" fn cb_unregistered < T : CustomDataNotification > ( ctxt : * mut c_void ) {
523+ let _ = Box :: from_raw ( ctxt as * mut T ) ;
524+ }
0 commit comments