@@ -5,6 +5,7 @@ use crate::{Bound, Python};
55use  crate :: { PyErr ,  PyResult } ; 
66use  std:: ffi:: { CStr ,  CString } ; 
77use  std:: os:: raw:: { c_char,  c_int,  c_void} ; 
8+ use  std:: ptr:: { self ,  NonNull } ; 
89/// Represents a Python Capsule 
910/// as described in [Capsules](https://docs.python.org/3/c-api/capsule.html#capsules): 
1011/// > This subtype of PyObject represents an opaque value, useful for C extension 
@@ -153,6 +154,32 @@ impl PyCapsule {
153154/// `arbitrary_self_types`. 
154155#[ doc( alias = "PyCapsule" ) ]  
155156pub  trait  PyCapsuleMethods < ' py > :  crate :: sealed:: Sealed  { 
157+     /// Gets the raw pointer stored in the capsule. 
158+      /// 
159+      /// Returns an error if the `name` does not exactly match the name stored in the capsule, or if 
160+      /// the pointer stored in the capsule is null. 
161+      fn  pointer ( & self ,  name :  Option < & CStr > )  -> PyResult < NonNull < c_void > > ; 
162+ 
163+     /// Obtains a reference dereferenced from the pointer of this capsule. 
164+      /// 
165+      /// # Safety 
166+      /// 
167+      /// It must be known that the pointer stored in the capsule points to an item of type `T`. 
168+      unsafe  fn  reference < T > ( & self ,  name :  Option < & CStr > )  -> PyResult < & ' py  T > ; 
169+ 
170+     /// Checks if this is a valid capsule. 
171+      /// 
172+      /// Returns true if all of these conditions are satisfied: 
173+      /// - `self` is a valid, non-null capsule (should be always true) 
174+      /// - the stored pointer is not null 
175+      /// - the name of the capsule is equal to `name` 
176+      fn  is_valid ( & self ,  name :  Option < & CStr > )  -> bool ; 
177+ 
178+     /// Retrieves the name of this capsule, if set. 
179+      /// 
180+      /// Returns an error if this capsule is not valid. 
181+      fn  name ( & self )  -> PyResult < Option < & ' py  CStr > > ; 
182+ 
156183    /// Sets the context pointer in the capsule. 
157184     /// 
158185     /// Returns an error if this capsule is not valid. 
@@ -197,68 +224,27 @@ pub trait PyCapsuleMethods<'py>: crate::sealed::Sealed {
197224     /// 
198225     /// Returns an error if this capsule is not valid. 
199226     fn  context ( & self )  -> PyResult < * mut  c_void > ; 
200- 
201-     /// Obtains a reference to the value of this capsule. 
202-      /// 
203-      /// # Safety 
204-      /// 
205-      /// It must be known that this capsule is valid and its pointer is to an item of type `T`. 
206-      unsafe  fn  reference < T > ( & self )  -> & ' py  T ; 
207- 
208-     /// Gets the raw `c_void` pointer to the value in this capsule. 
209-      /// 
210-      /// Returns null if this capsule is not valid. 
211-      fn  pointer ( & self )  -> * mut  c_void ; 
212- 
213-     /// Checks if this is a valid capsule. 
214-      /// 
215-      /// Returns true if the stored `pointer()` is non-null. 
216-      fn  is_valid ( & self )  -> bool ; 
217- 
218-     /// Retrieves the name of this capsule, if set. 
219-      /// 
220-      /// Returns an error if this capsule is not valid. 
221-      fn  name ( & self )  -> PyResult < Option < & ' py  CStr > > ; 
222227} 
223228
224229impl < ' py >  PyCapsuleMethods < ' py >  for  Bound < ' py ,  PyCapsule >  { 
225-     #[ allow( clippy:: not_unsafe_ptr_arg_deref) ]  
226-     fn  set_context ( & self ,  context :  * mut  c_void )  -> PyResult < ( ) >  { 
227-         let  result = unsafe  {  ffi:: PyCapsule_SetContext ( self . as_ptr ( ) ,  context)  } ; 
228-         if  result != 0  { 
229-             Err ( PyErr :: fetch ( self . py ( ) ) ) 
230-         }  else  { 
231-             Ok ( ( ) ) 
230+     fn  pointer ( & self ,  name :  Option < & CStr > )  -> PyResult < NonNull < c_void > >  { 
231+         let  ptr = unsafe  {  ffi:: PyCapsule_GetPointer ( self . as_ptr ( ) ,  name_ptr ( name) )  } ; 
232+         match  NonNull :: new ( ptr)  { 
233+             Some ( ptr)  => Ok ( ptr) , 
234+             None  => Err ( PyErr :: fetch ( self . py ( ) ) ) , 
232235        } 
233236    } 
234237
235-     fn  context ( & self )  -> PyResult < * mut  c_void >  { 
236-         let  ctx = unsafe  {  ffi:: PyCapsule_GetContext ( self . as_ptr ( ) )  } ; 
237-         if  ctx. is_null ( )  { 
238-             ensure_no_error ( self . py ( ) ) ?
239-         } 
240-         Ok ( ctx) 
241-     } 
242- 
243-     unsafe  fn  reference < T > ( & self )  -> & ' py  T  { 
244-         unsafe  {  & * self . pointer ( ) . cast ( )  } 
245-     } 
246- 
247-     fn  pointer ( & self )  -> * mut  c_void  { 
248-         unsafe  { 
249-             let  ptr = ffi:: PyCapsule_GetPointer ( self . as_ptr ( ) ,  name_ptr_ignore_error ( self ) ) ; 
250-             if  ptr. is_null ( )  { 
251-                 ffi:: PyErr_Clear ( ) ; 
252-             } 
253-             ptr
254-         } 
238+     unsafe  fn  reference < T > ( & self ,  name :  Option < & CStr > )  -> PyResult < & ' py  T >  { 
239+         let  ptr = self . pointer ( name) ?; 
240+         Ok ( unsafe  {  & * ptr. as_ptr ( ) . cast ( )  } ) 
255241    } 
256242
257-     fn  is_valid ( & self )  -> bool  { 
243+     fn  is_valid ( & self ,   name :   Option < & CStr > )  -> bool  { 
258244        // As well as if the stored pointer is null, PyCapsule_IsValid also returns false if 
259245        // self.as_ptr() is null or not a ptr to a PyCapsule object. Both of these are guaranteed 
260246        // to not be the case thanks to invariants of this PyCapsule struct. 
261-         let  r = unsafe  {  ffi:: PyCapsule_IsValid ( self . as_ptr ( ) ,  name_ptr_ignore_error ( self ) )  } ; 
247+         let  r = unsafe  {  ffi:: PyCapsule_IsValid ( self . as_ptr ( ) ,  name_ptr ( name ) )  } ; 
262248        r != 0 
263249    } 
264250
@@ -273,9 +259,27 @@ impl<'py> PyCapsuleMethods<'py> for Bound<'py, PyCapsule> {
273259            } 
274260        } 
275261    } 
262+ 
263+     #[ allow( clippy:: not_unsafe_ptr_arg_deref) ]  
264+     fn  set_context ( & self ,  context :  * mut  c_void )  -> PyResult < ( ) >  { 
265+         let  result = unsafe  {  ffi:: PyCapsule_SetContext ( self . as_ptr ( ) ,  context)  } ; 
266+         if  result != 0  { 
267+             Err ( PyErr :: fetch ( self . py ( ) ) ) 
268+         }  else  { 
269+             Ok ( ( ) ) 
270+         } 
271+     } 
272+ 
273+     fn  context ( & self )  -> PyResult < * mut  c_void >  { 
274+         let  ctx = unsafe  {  ffi:: PyCapsule_GetContext ( self . as_ptr ( ) )  } ; 
275+         if  ctx. is_null ( )  { 
276+             ensure_no_error ( self . py ( ) ) ?
277+         } 
278+         Ok ( ctx) 
279+     } 
276280} 
277281
278- // C layout, as PyCapsule::get_reference  depends on `T` being first. 
282+ // C layout, as PyCapsule::reference  depends on `T` being first. 
279283#[ repr( C ) ]  
280284struct  CapsuleContents < T :  ' static  + Send ,  D :  FnOnce ( T ,  * mut  c_void )  + Send >  { 
281285    /// Value of the capsule 
@@ -323,12 +327,11 @@ fn ensure_no_error(py: Python<'_>) -> PyResult<()> {
323327    } 
324328} 
325329
326- fn  name_ptr_ignore_error ( slf :   & Bound < ' _ ,   PyCapsule > )  -> * const  c_char  { 
327-     let  ptr =  unsafe   {  ffi :: PyCapsule_GetName ( slf . as_ptr ( ) )   } ; 
328-     if  ptr . is_null ( )   { 
329-         unsafe   {  ffi :: PyErr_Clear ( )   } ; 
330+ fn  name_ptr ( name :   Option < & CStr > )  -> * const  c_char  { 
331+     match  name  { 
332+          Some ( name )  => name . as_ptr ( ) , 
333+         None  => ptr :: null ( ) , 
330334    } 
331-     ptr
332335} 
333336
334337#[ cfg( test) ]  
@@ -359,9 +362,9 @@ mod tests {
359362            let  name = CString :: new ( "foo" ) . unwrap ( ) ; 
360363
361364            let  cap = PyCapsule :: new ( py,  foo,  Some ( name. clone ( ) ) ) ?; 
362-             assert ! ( cap. is_valid( ) ) ; 
365+             assert ! ( cap. is_valid( Some ( c"foo" ) ) ) ; 
363366
364-             let  foo_capi = unsafe  {  cap. reference :: < Foo > ( )   } ; 
367+             let  foo_capi = unsafe  {  cap. reference :: < Foo > ( Some ( name . as_ref ( ) ) )   } . unwrap ( ) ; 
365368            assert_eq ! ( foo_capi. val,  123 ) ; 
366369            assert_eq ! ( foo_capi. get_val( ) ,  123 ) ; 
367370            assert_eq ! ( cap. name( ) . unwrap( ) ,  Some ( name. as_ref( ) ) ) ; 
@@ -375,14 +378,18 @@ mod tests {
375378            x
376379        } 
377380
381+         let  name = CString :: new ( "foo" ) . unwrap ( ) ; 
378382        let  cap:  Py < PyCapsule >  = Python :: attach ( |py| { 
379-             let  name = CString :: new ( "foo" ) . unwrap ( ) ; 
380-             let  cap = PyCapsule :: new ( py,  foo as  fn ( u32 )  -> u32 ,  Some ( name) ) . unwrap ( ) ; 
383+             let  cap = PyCapsule :: new ( py,  foo as  fn ( u32 )  -> u32 ,  Some ( name. clone ( ) ) ) . unwrap ( ) ; 
381384            cap. into ( ) 
382385        } ) ; 
383386
384387        Python :: attach ( move  |py| { 
385-             let  f = unsafe  {  cap. bind ( py) . reference :: < fn ( u32 )  -> u32 > ( )  } ; 
388+             let  f = unsafe  { 
389+                 cap. bind ( py) 
390+                     . reference :: < fn ( u32 )  -> u32 > ( Some ( name. as_ref ( ) ) ) 
391+             } 
392+             . unwrap ( ) ; 
386393            assert_eq ! ( f( 123 ) ,  123 ) ; 
387394        } ) ; 
388395    } 
@@ -436,17 +443,16 @@ mod tests {
436443
437444    #[ test]  
438445    fn  test_vec_storage ( )  { 
446+         let  name = CString :: new ( "foo" ) . unwrap ( ) ; 
439447        let  cap:  Py < PyCapsule >  = Python :: attach ( |py| { 
440-             let  name = CString :: new ( "foo" ) . unwrap ( ) ; 
441- 
442448            let  stuff:  Vec < u8 >  = vec ! [ 1 ,  2 ,  3 ,  4 ] ; 
443-             let  cap = PyCapsule :: new ( py,  stuff,  Some ( name) ) . unwrap ( ) ; 
449+             let  cap = PyCapsule :: new ( py,  stuff,  Some ( name. clone ( ) ) ) . unwrap ( ) ; 
444450
445451            cap. into ( ) 
446452        } ) ; 
447453
448454        Python :: attach ( move  |py| { 
449-             let  ctx:  & Vec < u8 >  = unsafe  {  cap. bind ( py) . reference ( )   } ; 
455+             let  ctx:  & Vec < u8 >  = unsafe  {  cap. bind ( py) . reference ( Some ( name . as_ref ( ) ) )   } . unwrap ( ) ; 
450456            assert_eq ! ( ctx,  & [ 1 ,  2 ,  3 ,  4 ] ) ; 
451457        } ) 
452458    } 
@@ -496,7 +502,7 @@ mod tests {
496502        Python :: attach ( |py| { 
497503            let  cap = PyCapsule :: new ( py,  0usize ,  None ) . unwrap ( ) ; 
498504
499-             assert_eq ! ( unsafe  {  cap. reference:: <usize >( )  } ,  & 0usize ) ; 
505+             assert_eq ! ( unsafe  {  cap. reference:: <usize >( None )  } . unwrap ( ) ,  & 0usize ) ; 
500506            assert_eq ! ( cap. name( ) . unwrap( ) ,  None ) ; 
501507            assert_eq ! ( cap. context( ) . unwrap( ) ,  std:: ptr:: null_mut( ) ) ; 
502508        } ) ; 
0 commit comments