@@ -616,36 +616,40 @@ impl TypeArchive {
616616 }
617617
618618 /// Register a notification listener
619- pub fn register_notification_callback < T : TypeArchiveNotificationCallback > (
619+ #[ must_use]
620+ pub fn register_notification_callback < ' a , T : TypeArchiveNotificationCallback + ' a > (
620621 & self ,
621622 callback : T ,
622- ) -> TypeArchiveCallbackHandle < T > {
623+ ) -> TypeArchiveCallbackHandle < ' a , T > {
623624 // SAFETY free on [TypeArchiveCallbackHandle::Drop]
624625 let callback = Box :: leak ( Box :: new ( callback) ) ;
625- let mut notification = BNTypeArchiveNotification {
626+ let notification = BNTypeArchiveNotification {
626627 context : callback as * mut T as * mut c_void ,
627628 typeAdded : Some ( cb_type_added :: < T > ) ,
628629 typeUpdated : Some ( cb_type_updated :: < T > ) ,
629630 typeRenamed : Some ( cb_type_renamed :: < T > ) ,
630631 typeDeleted : Some ( cb_type_deleted :: < T > ) ,
632+ closed : Some ( cb_type_archive_closed :: < T > ) ,
631633 } ;
632- unsafe { BNRegisterTypeArchiveNotification ( self . handle . as_ptr ( ) , & mut notification) }
634+ let mut boxed_notification = Box :: new ( notification) ;
635+ unsafe {
636+ BNRegisterTypeArchiveNotification ( self . handle . as_ptr ( ) , boxed_notification. as_mut ( ) )
637+ }
633638 TypeArchiveCallbackHandle {
634- callback,
635639 type_archive : self . to_owned ( ) ,
640+ handle : boxed_notification,
641+ _lifetime : Default :: default ( ) ,
636642 }
637643 }
638644
639- // NOTE NotificationClosure is left private, there is no need for the user
640- // to know or use it.
641- #[ allow( private_interfaces) ]
642- pub fn register_notification_closure < A , U , R , D > (
645+ #[ must_use]
646+ pub fn register_notification_closure < ' a , A , U , R , D > (
643647 & self ,
644648 type_added : A ,
645649 type_updated : U ,
646650 type_renamed : R ,
647651 type_deleted : D ,
648- ) -> TypeArchiveCallbackHandle < NotificationClosure < A , U , R , D > >
652+ ) -> TypeArchiveCallbackHandle < ' a , NotificationClosure < A , U , R , D > >
649653 where
650654 A : FnMut ( & TypeArchive , & str , & Type ) ,
651655 U : FnMut ( & TypeArchive , & str , & Type , & Type ) ,
@@ -661,7 +665,9 @@ impl TypeArchive {
661665 }
662666
663667 /// Close a type archive, disconnecting it from any active views and closing
664- /// any open file handles
668+ /// any open file handles.
669+ ///
670+ /// This will signal all registered notification callbacks with [`TypeArchiveNotificationCallback::closed`].
665671 pub fn close ( & self ) {
666672 unsafe { BNCloseTypeArchive ( self . handle . as_ptr ( ) ) }
667673 }
@@ -874,29 +880,35 @@ unsafe impl CoreArrayProviderInner for TypeArchive {
874880 }
875881}
876882
877- pub struct TypeArchiveCallbackHandle < T : TypeArchiveNotificationCallback > {
878- callback : * mut T ,
883+ pub struct TypeArchiveCallbackHandle < ' a , T : TypeArchiveNotificationCallback >
884+ where
885+ T : ' a ,
886+ {
879887 type_archive : Ref < TypeArchive > ,
888+ handle : Box < BNTypeArchiveNotification > ,
889+ _lifetime : std:: marker:: PhantomData < & ' a T > ,
880890}
881891
882- impl < T : TypeArchiveNotificationCallback > Drop for TypeArchiveCallbackHandle < T > {
892+ impl < T : TypeArchiveNotificationCallback > TypeArchiveCallbackHandle < ' _ , T > {
893+ unsafe fn unregister_for_archive ( & mut self ) {
894+ BNUnregisterTypeArchiveNotification ( self . type_archive . handle . as_ptr ( ) , self . handle . as_mut ( ) )
895+ }
896+
897+ unsafe fn extract_context ( & mut self ) -> Box < T > {
898+ Box :: from_raw ( self . handle . context as * mut T )
899+ }
900+
901+ pub fn unregister ( mut self ) -> T {
902+ unsafe { self . unregister_for_archive ( ) } ;
903+ unsafe { * self . extract_context ( ) }
904+ }
905+ }
906+
907+ impl < T : TypeArchiveNotificationCallback > Drop for TypeArchiveCallbackHandle < ' _ , T > {
883908 fn drop ( & mut self ) {
884- let mut notification = BNTypeArchiveNotification {
885- context : self . callback as * mut c_void ,
886- typeAdded : Some ( cb_type_added :: < T > ) ,
887- typeUpdated : Some ( cb_type_updated :: < T > ) ,
888- typeRenamed : Some ( cb_type_renamed :: < T > ) ,
889- typeDeleted : Some ( cb_type_deleted :: < T > ) ,
890- } ;
891- // unregister the notification callback
892- unsafe {
893- BNUnregisterTypeArchiveNotification (
894- self . type_archive . handle . as_ptr ( ) ,
895- & mut notification,
896- )
897- }
898- // free the context created at [TypeArchive::register_notification_callback]
899- drop ( unsafe { Box :: from_raw ( self . callback ) } ) ;
909+ unsafe { self . unregister_for_archive ( ) } ;
910+ // drop context, avoid memory leak
911+ let _ctxt = unsafe { self . extract_context ( ) } ;
900912 }
901913}
902914
@@ -944,9 +956,14 @@ pub trait TypeArchiveNotificationCallback {
944956 /// * `id` - Id of type deleted
945957 /// * `definition` - Definition of type deleted
946958 fn type_deleted ( & mut self , _archive : & TypeArchive , _id : & str , _definition : & Type ) { }
959+
960+ /// Called when the associated type archive is closed.
961+ ///
962+ /// Useful to free up data in this context associated with the type archive.
963+ fn closed ( & mut self , _archive : & TypeArchive ) { }
947964}
948965
949- struct NotificationClosure < A , U , R , D >
966+ pub struct NotificationClosure < A , U , R , D >
950967where
951968 A : FnMut ( & TypeArchive , & str , & Type ) ,
952969 U : FnMut ( & TypeArchive , & str , & Type , & Type ) ,
@@ -1068,6 +1085,16 @@ unsafe extern "C" fn cb_type_deleted<T: TypeArchiveNotificationCallback>(
10681085 )
10691086}
10701087
1088+ unsafe extern "C" fn cb_type_archive_closed < T : TypeArchiveNotificationCallback > (
1089+ ctxt : * mut :: std:: os:: raw:: c_void ,
1090+ archive : * mut BNTypeArchive ,
1091+ ) {
1092+ let ctxt: & mut T = & mut * ( ctxt as * mut T ) ;
1093+ // `archive` is owned by the caller.
1094+ let archive = unsafe { TypeArchive :: from_raw ( NonNull :: new ( archive) . unwrap ( ) ) } ;
1095+ ctxt. closed ( & archive)
1096+ }
1097+
10711098#[ repr( transparent) ]
10721099pub struct TypeArchiveMergeConflict {
10731100 handle : NonNull < BNTypeArchiveMergeConflict > ,
0 commit comments