pyo3/types/capsule.rs
1#![deny(clippy::undocumented_unsafe_blocks)]
2
3use crate::exceptions::PySystemError;
4use crate::ffi_ptr_ext::FfiPtrExt;
5use crate::internal_tricks::box_into_non_null;
6use crate::py_result_ext::PyResultExt;
7use crate::{ffi, PyAny};
8#[cfg(RustPython)]
9use crate::{
10 sync::PyOnceLock,
11 types::{PyType, PyTypeMethods},
12 Py,
13};
14use crate::{Bound, Python};
15use crate::{PyErr, PyResult};
16use core::ffi::CStr;
17use core::ffi::{c_char, c_int, c_void};
18use core::mem::offset_of;
19use core::ptr::{self, NonNull};
20use std::ffi::CString;
21
22/// Represents a Python Capsule
23/// as described in [Capsules](https://docs.python.org/3/c-api/capsule.html#capsules):
24/// > This subtype of PyObject represents an opaque value, useful for C extension
25/// > modules who need to pass an opaque value (as a void* pointer) through Python
26/// > code to other C code. It is often used to make a C function pointer defined
27/// > in one module available to other modules, so the regular import mechanism can
28/// > be used to access C APIs defined in dynamically loaded modules.
29///
30/// Values of this type are accessed via PyO3's smart pointers, e.g. as
31/// [`Py<PyCapsule>`][crate::Py] or [`Bound<'py, PyCapsule>`][Bound].
32///
33/// For APIs available on capsule objects, see the [`PyCapsuleMethods`] trait which is implemented for
34/// [`Bound<'py, PyCapsule>`][Bound].
35///
36/// # Safety
37///
38/// `capsule` objects are designed to share data opaque to Python code between multiple compiled extensions.
39/// This comes with a loss of type safety, and the best defense against invalid casts is to use the
40/// [capsule name][CapsuleName] to hint at the expected type of capsule contents.
41///
42/// Once the capsule name is verified, it is also crucial that the data stored within has a stable layout
43/// guaranteed between the producer and consumer of the capsule. Practically speaking, this means that:
44/// - any structs stored in capsules should be [`#[repr(C)]`][repr-c],
45/// - any enums stored within should either be [`#[repr(C)]`][enum-repr-c] or have a [fixed primitive representation], and
46/// - any function pointers stored within should have a fixed ABI (e.g. `extern "C"`) and only use arguments and return values
47/// which themselves have a stable layout.
48///
49/// In particular, note that Rust's default `#[repr(Rust)]` and `extern "Rust"` functions have no stability
50/// guarantees, so storing and dereferencing a pointer to a Rust function in a capsule which was produced
51/// by a separate compiled extension is UB.
52///
53/// If the data opaque to Python needs to be only accessed within a single extension, it is recommended to
54/// use a `#[pyclass]` with no public getters/setters. PyO3 can guarantee the type safety of the contents
55/// and provide a safe API for accessing it (e.g. via [`Bound::borrow`] and [`Bound::get`]).
56///
57/// # Example
58/// ```
59/// use pyo3::{prelude::*, types::PyCapsule, ffi::c_str};
60///
61/// #[repr(C)]
62/// struct Foo {
63/// pub val: u32,
64/// }
65///
66/// let r = Python::attach(|py| -> PyResult<()> {
67/// let foo = Foo { val: 123 };
68/// let capsule = PyCapsule::new_with_value(py, foo, c"builtins.capsule")?;
69///
70/// let module = PyModule::import(py, "builtins")?;
71/// module.add("capsule", capsule)?;
72///
73/// let cap: &Foo = unsafe { PyCapsule::import(py, c"builtins.capsule")? };
74/// assert_eq!(cap.val, 123);
75/// Ok(())
76/// });
77/// assert!(r.is_ok());
78/// ```
79///
80/// [repr-c]: <https://doc.rust-lang.org/reference/type-layout.html#the-c-representation>
81/// [enum-repr-c]: <https://doc.rust-lang.org/reference/type-layout.html#reprc-enums-with-fields>
82/// [fixed primitive representation]: <https://doc.rust-lang.org/reference/type-layout.html#primitive-representation-of-enums-with-fields>
83#[repr(transparent)]
84pub struct PyCapsule(PyAny);
85
86#[cfg(not(RustPython))]
87pyobject_native_type_core!(PyCapsule, pyobject_native_static_type_object!(ffi::PyCapsule_Type), "types", "CapsuleType", #checkfunction=ffi::PyCapsule_CheckExact);
88
89#[cfg(RustPython)]
90pyobject_native_type_core!(
91 PyCapsule,
92 |py| {
93 static TYPE: PyOnceLock<Py<PyType>> = PyOnceLock::new();
94 TYPE.import(py, "types", "CapsuleType").unwrap().as_type_ptr()
95 },
96 "types",
97 "CapsuleType",
98 #checkfunction=ffi::PyCapsule_CheckExact
99);
100
101impl PyCapsule {
102 /// Constructs a new capsule whose contents are `value`, associated with `name`.
103 /// `name` is the identifier for the capsule; if it is stored as an attribute of a module,
104 /// the name should be in the format `"modulename.attribute"`.
105 ///
106 /// Rust function items need to be cast to a function pointer (`fn(args) -> result`) to be put
107 /// into a capsule.
108 ///
109 /// # Example
110 ///
111 /// ```
112 /// use pyo3::{prelude::*, types::PyCapsule, ffi::c_str};
113 /// use core::ffi::CStr;
114 /// use core::ptr::NonNull;
115 ///
116 /// // this can be c"foo" on Rust 1.77+
117 /// const NAME: &CStr = c"foo";
118 ///
119 /// # fn main() -> PyResult<()> {
120 /// Python::attach(|py| {
121 /// let capsule = PyCapsule::new_with_value(py, 123_u32, NAME)?;
122 /// let val: NonNull<u32> = capsule.pointer_checked(Some(NAME))?.cast();
123 /// assert_eq!(unsafe { *val.as_ref() }, 123);
124 /// # Ok(())
125 /// })
126 /// # }
127 /// ```
128 ///
129 /// # Note
130 /// This function will [`Box`] the `T` and store the pointer to the box in the capsule. For
131 /// manual control over allocations use [`PyCapsule::new_with_pointer`] instead.
132 pub fn new_with_value<'py, T>(
133 py: Python<'py>,
134 value: T,
135 name: &'static CStr,
136 ) -> PyResult<Bound<'py, Self>>
137 where
138 T: 'static + Send,
139 {
140 // NOTE: Not implemented in terms of `new_with_value_and_destructor` as this allows for
141 // storing the `Box<T>` directly without allocating additionally for the destructor
142 let val = box_into_non_null(Box::new(value));
143
144 unsafe extern "C" fn destructor<T>(capsule: *mut ffi::PyObject) {
145 // SAFETY: `capsule` is known to be a borrowed reference to the capsule being destroyed
146 let name = unsafe { ffi::PyCapsule_GetName(capsule) };
147
148 // SAFETY:
149 // - `capsule` is known to be a borrowed reference to the capsule being destroyed
150 // - `name` is known to be the capsule's name
151 let ptr = unsafe { ffi::PyCapsule_GetPointer(capsule, name) };
152
153 // SAFETY: `capsule` was knowingly constructed from a `Box<T>` and is now being
154 // destroyed, so we reconstruct the Box and drop it.
155 let _ = unsafe { Box::<T>::from_raw(ptr.cast()) };
156 }
157
158 // SAFETY:
159 // - `val` is aligned and valid for a `T` until the destructor runs
160 // - `destructor` will deallocate the `Box`
161 // - `destructor` can be called from any thread as `T: Send`
162 unsafe {
163 Self::new_with_pointer_and_destructor(py, val.cast(), name, Some(destructor::<T>))
164 }
165 }
166
167 /// See [`PyCapsule::new_with_value`]
168 #[deprecated(since = "0.29.0", note = "use `PyCapsule::new_with_value` instead")]
169 pub fn new<T: 'static + Send>(
170 py: Python<'_>,
171 value: T,
172 name: Option<CString>,
173 ) -> PyResult<Bound<'_, Self>> {
174 #[allow(deprecated)]
175 Self::new_with_destructor(py, value, name, |_, _| {})
176 }
177
178 /// Constructs a new capsule whose contents are `value`, associated with `name`.
179 ///
180 /// Also provides a destructor: when the `PyCapsule` is destroyed, it will be passed the original object,
181 /// as well as a `*mut c_void` which will point to the capsule's context, if any.
182 ///
183 /// The `destructor` must be `Send`, because there is no guarantee which thread it will eventually
184 /// be called from.
185 ///
186 /// # Note
187 /// If `destructor` panics the process will (safely) abort.
188 ///
189 /// This function will [`Box`] the `T` together with the provided destructor and store the
190 /// pointer to the box in the capsule. For manual control over allocations use
191 /// [`PyCapsule::new_with_pointer_and_destructor`] instead.
192 pub fn new_with_value_and_destructor<'py, T, F>(
193 py: Python<'py>,
194 value: T,
195 name: &'static CStr,
196 destructor: F,
197 ) -> PyResult<Bound<'py, Self>>
198 where
199 T: 'static + Send,
200 F: FnOnce(T, *mut c_void) + Send + 'static,
201 {
202 // Sanity check for capsule layout
203 debug_assert_eq!(offset_of!(CapsuleContents::<T, F>, value), 0);
204
205 // SAFETY: `Box` pointers are guaranteed to be non-null
206 let val = box_into_non_null(Box::new(CapsuleContents {
207 value,
208 destructor,
209 name: None,
210 }));
211
212 // SAFETY:
213 // - `val` is an aligned and valid pointer to a `CapsuleContents` until the destructor runs
214 // - `CapsuleContents` is `#[repr(C)]` with `T` as its first field, so `val` may be used as
215 // an aligned and valid pointer to a `T`
216 // - `capsule_destructor` will deallocate the `Box` and call the user provided `destructor`
217 // - `capsule_destructor` can be called from any thread as `T: Send` and `F: Send`
218 unsafe {
219 Self::new_with_pointer_and_destructor(
220 py,
221 val.cast(),
222 name,
223 Some(capsule_destructor::<T, F>),
224 )
225 }
226 }
227
228 /// See [`PyCapsule::new_with_value_and_destructor`]
229 #[deprecated(
230 since = "0.29.0",
231 note = "use `PyCapsule::new_with_value_and_destructor` instead"
232 )]
233 pub fn new_with_destructor<T: 'static + Send, F: FnOnce(T, *mut c_void) + Send + 'static>(
234 py: Python<'_>,
235 value: T,
236 name: Option<CString>,
237 destructor: F,
238 ) -> PyResult<Bound<'_, Self>> {
239 // Sanity check for capsule layout
240 debug_assert_eq!(offset_of!(CapsuleContents::<T, F>, value), 0);
241
242 let name_ptr = name
243 .as_ref()
244 .map_or(core::ptr::null(), |name| name.as_ptr());
245 let val = Box::into_raw(Box::new(CapsuleContents {
246 value,
247 destructor,
248 name,
249 }));
250
251 // SAFETY:
252 // - `val` is a non-null pointer to valid capsule data
253 // - `name_ptr` is either a valid C string or null
254 // - `destructor` will delete this data when called
255 // - thread is attached to the Python interpreter
256 // - `PyCapsule_New` returns a new reference or null on error
257 unsafe {
258 ffi::PyCapsule_New(val.cast(), name_ptr, Some(capsule_destructor::<T, F>))
259 .assume_owned_or_err(py)
260 .cast_into_unchecked()
261 }
262 }
263
264 /// Constructs a new capsule from a raw pointer.
265 ///
266 /// Unlike [`PyCapsule::new`], which stores a value and sets the capsule's pointer
267 /// to that value's address, this method uses the pointer directly. This is useful
268 /// for APIs that expect the capsule to hold a specific address (e.g., a function
269 /// pointer for FFI) rather than a pointer to owned data.
270 ///
271 /// The capsule's name should follow Python's naming convention:
272 /// `"module.attribute"` for capsules stored as module attributes.
273 ///
274 /// # Safety
275 ///
276 /// - The pointer must be valid for its intended use case.
277 /// - If the pointer refers to data, that data must outlive the capsule.
278 /// - No destructor is registered; use [`PyCapsule::new_with_pointer_and_destructor`]
279 /// if cleanup is needed.
280 ///
281 /// # Example
282 ///
283 /// ```
284 /// use pyo3::{prelude::*, types::PyCapsule};
285 /// use core::ffi::c_void;
286 /// use core::ptr::NonNull;
287 ///
288 /// extern "C" fn my_ffi_handler(_: *mut c_void) -> *mut c_void {
289 /// core::ptr::null_mut()
290 /// }
291 ///
292 /// Python::attach(|py| {
293 /// let ptr = NonNull::new(my_ffi_handler as *mut c_void).unwrap();
294 ///
295 /// // SAFETY: `ptr` is a valid function pointer
296 /// let capsule = unsafe {
297 /// PyCapsule::new_with_pointer(py, ptr, c"my_module.my_ffi_handler")
298 /// }.unwrap();
299 ///
300 /// let retrieved = capsule.pointer_checked(Some(c"my_module.my_ffi_handler")).unwrap();
301 /// assert_eq!(retrieved.as_ptr(), my_ffi_handler as *mut c_void);
302 /// });
303 /// ```
304 pub unsafe fn new_with_pointer<'py>(
305 py: Python<'py>,
306 pointer: NonNull<c_void>,
307 name: &'static CStr,
308 ) -> PyResult<Bound<'py, Self>> {
309 // SAFETY: Caller guarantees pointer validity; destructor is None.
310 unsafe { Self::new_with_pointer_and_destructor(py, pointer, name, None) }
311 }
312
313 /// Constructs a new capsule from a raw pointer with an optional destructor.
314 ///
315 /// This is the full-featured version of [`PyCapsule::new_with_pointer`], allowing
316 /// a destructor to be called when the capsule is garbage collected.
317 ///
318 /// Unlike [`PyCapsule::new_with_destructor`], the destructor here must be a raw
319 /// `extern "C"` function pointer, not a Rust closure. This is because there is
320 /// no internal storage for a closure—the capsule holds only the raw pointer you
321 /// provide.
322 ///
323 /// # Safety
324 ///
325 /// - The pointer must be valid for its intended use case.
326 /// - If the pointer refers to data, that data must remain valid for the capsule's
327 /// lifetime, or the destructor must clean it up.
328 /// - The destructor, if provided, must be safe to call from any thread.
329 ///
330 /// # Note
331 /// If `destructor` panics the process will (safely) abort.
332 ///
333 /// # Example
334 ///
335 /// ```
336 /// use pyo3::{prelude::*, types::PyCapsule};
337 /// use core::ffi::c_void;
338 /// use core::ptr::NonNull;
339 ///
340 /// unsafe extern "C" fn free_data(capsule: *mut pyo3::ffi::PyObject) {
341 /// let ptr = pyo3::ffi::PyCapsule_GetPointer(capsule, c"my_module.data".as_ptr());
342 /// if !ptr.is_null() {
343 /// drop(Box::from_raw(ptr as *mut u32));
344 /// }
345 /// }
346 ///
347 /// Python::attach(|py| {
348 /// let data = Box::new(42u32);
349 /// let ptr = NonNull::new(Box::into_raw(data).cast::<c_void>()).unwrap();
350 ///
351 /// // SAFETY: `ptr` is valid; `free_data` will deallocate it
352 /// let capsule = unsafe {
353 /// PyCapsule::new_with_pointer_and_destructor(
354 /// py,
355 /// ptr,
356 /// c"my_module.data",
357 /// Some(free_data),
358 /// )
359 /// }.unwrap();
360 /// });
361 /// ```
362 pub unsafe fn new_with_pointer_and_destructor<'py>(
363 py: Python<'py>,
364 pointer: NonNull<c_void>,
365 name: &'static CStr,
366 destructor: Option<ffi::PyCapsule_Destructor>,
367 ) -> PyResult<Bound<'py, Self>> {
368 let name_ptr = name.as_ptr();
369
370 // SAFETY:
371 // - `pointer` is non-null (guaranteed by `NonNull`)
372 // - `name_ptr` points to a valid C string (guaranteed by `&'static CStr`)
373 // - `destructor` is either None or a valid function pointer (caller guarantees)
374 // - Thread is attached to the Python interpreter
375 unsafe {
376 ffi::PyCapsule_New(pointer.as_ptr(), name_ptr, destructor)
377 .assume_owned_or_err(py)
378 .cast_into_unchecked()
379 }
380 }
381
382 /// Imports an existing capsule.
383 ///
384 /// The `name` should match the path to the module attribute exactly in the form
385 /// of `"module.attribute"`, which should be the same as the name within the capsule.
386 ///
387 /// # Safety
388 ///
389 /// It must be known that the capsule imported by `name` contains an item of type `T`.
390 pub unsafe fn import<'py, T>(py: Python<'py>, name: &CStr) -> PyResult<&'py T> {
391 let ptr = Self::import_pointer(py, name)?.cast();
392
393 if !ptr.is_aligned() {
394 return Err(PySystemError::new_err(format!(
395 "The pointer from the `{}` capsule is not aligned to rust type {}",
396 name.to_string_lossy(),
397 core::any::type_name::<T>()
398 )));
399 }
400
401 // SAFETY: caller has upheld the safety contract and we just checked pointer alignment
402 Ok(unsafe { ptr.as_ref() })
403 }
404
405 /// Imports an existing capsule as a pointer.
406 ///
407 /// The `name` should match the path to the module attribute exactly in the form
408 /// of `"module.attribute"`, which should be the same as the name within the capsule.
409 ///
410 /// # Safety
411 ///
412 /// This function is safe to call, but the pointer it returns is not safe to use.
413 /// The python interpreter does _NOT_ provide any synchronization guarantees for capsules.
414 pub fn import_pointer(py: Python<'_>, name: &CStr) -> PyResult<NonNull<c_void>> {
415 // SAFETY: `name` is a valid C string, thread is attached to the Python interpreter
416 let ptr = unsafe { ffi::PyCapsule_Import(name.as_ptr(), false as c_int) };
417 NonNull::new(ptr).ok_or_else(|| PyErr::fetch(py))
418 }
419}
420
421/// Implementation of functionality for [`PyCapsule`].
422///
423/// These methods are defined for the `Bound<'py, PyCapsule>` smart pointer, so to use method call
424/// syntax these methods are separated into a trait, because stable Rust does not yet support
425/// `arbitrary_self_types`.
426///
427/// # Name checking
428///
429/// Capsules contain pointers to arbitrary data which is cast to a specific type at runtime. This is
430/// inherently quite dangerous, so Python allows capsules to be "named" to provide a hint as to
431/// what data is contained in the capsule. Although not a perfect solution, this is better than
432/// nothing.
433///
434/// The methods in this trait take the `name` as an `Option<&CStr>`, which is compared to the name
435/// stored in the capsule (with `None` being used to indicate the capsule has no name).
436#[doc(alias = "PyCapsule")]
437pub trait PyCapsuleMethods<'py>: crate::sealed::Sealed {
438 /// Sets the context pointer in the capsule.
439 ///
440 /// Returns an error if this capsule is not valid.
441 ///
442 /// # Notes
443 ///
444 /// The context is treated much like the value of the capsule, but should likely act as
445 /// a place to store any state management when using the capsule.
446 ///
447 /// If you want to store a Rust value as the context, and drop it from the destructor, use
448 /// `Box::into_raw` to convert it into a pointer, see the example.
449 ///
450 /// # Example
451 ///
452 /// ```
453 /// use core::ffi::c_void;
454 /// use std::sync::mpsc::{channel, Sender};
455 /// use pyo3::{prelude::*, types::PyCapsule};
456 ///
457 /// # fn main() -> PyResult<()> {
458 /// let (tx, rx) = channel::<String>();
459 ///
460 /// fn destructor(val: u32, context: *mut c_void) {
461 /// let ctx = unsafe { *Box::from_raw(context.cast::<Sender<String>>()) };
462 /// ctx.send("Destructor called!".to_string()).unwrap();
463 /// }
464 ///
465 /// Python::attach(|py| {
466 /// let capsule = PyCapsule::new_with_value_and_destructor(
467 /// py,
468 /// 123,
469 /// c"foo",
470 /// destructor as fn(u32, *mut c_void)
471 /// )?;
472 /// let context = Box::new(tx); // `Sender<String>` is our context, box it up and ship it!
473 /// capsule.set_context(Box::into_raw(context).cast())?;
474 /// // This scope will end, causing our destructor to be called...
475 /// # Ok::<_, PyErr>(())
476 /// })?;
477 ///
478 /// assert_eq!(rx.recv(), Ok("Destructor called!".to_string()));
479 /// # Ok(())
480 /// }
481 /// ```
482 fn set_context(&self, context: *mut c_void) -> PyResult<()>;
483
484 /// Gets the current context stored in the capsule. If there is no context, the pointer
485 /// will be null.
486 ///
487 /// Returns an error if this capsule is not valid.
488 fn context(&self) -> PyResult<*mut c_void>;
489
490 /// Gets the raw pointer stored in this capsule.
491 ///
492 /// Returns an error if the capsule is not [valid][`PyCapsuleMethods::is_valid_checked`] with the given `name`.
493 ///
494 /// # Safety
495 ///
496 /// This function itself is not `unsafe`, but dereferencing the returned pointer to produce a reference
497 /// is very dangerous:
498 /// - The pointer will need to be [.cast()][NonNull::cast] to a concrete type before dereferencing.
499 /// As per [name checking](#name-checking), there is no way to statically guarantee this cast is
500 /// correct, the name is the best available hint to guard against accidental misuse.
501 /// - Arbitrary Python code can change the contents of the capsule, which may invalidate the
502 /// pointer. The pointer and the reference produced by dereferencing the pointer should both
503 /// be considered invalid after arbitrary Python code has run.
504 ///
505 /// Users should take care to cast to the correct type and consume the pointer for as little
506 /// duration as possible.
507 fn pointer_checked(&self, name: Option<&CStr>) -> PyResult<NonNull<c_void>>;
508
509 /// Checks that the capsule name matches `name` and that the pointer is not null.
510 fn is_valid_checked(&self, name: Option<&CStr>) -> bool;
511
512 /// Retrieves the name of this capsule, if set.
513 ///
514 /// Returns an error if this capsule is not valid.
515 ///
516 /// See [`CapsuleName`] for details of how to consume the return value.
517 fn name(&self) -> PyResult<Option<CapsuleName>>;
518}
519
520impl<'py> PyCapsuleMethods<'py> for Bound<'py, PyCapsule> {
521 #[allow(clippy::not_unsafe_ptr_arg_deref)]
522 fn set_context(&self, context: *mut c_void) -> PyResult<()> {
523 // SAFETY:
524 // - `self.as_ptr()` is a valid object pointer
525 // - `context` is user-provided
526 // - thread is attached to the Python interpreter
527 let result = unsafe { ffi::PyCapsule_SetContext(self.as_ptr(), context) };
528 if result != 0 {
529 Err(PyErr::fetch(self.py()))
530 } else {
531 Ok(())
532 }
533 }
534
535 fn context(&self) -> PyResult<*mut c_void> {
536 // SAFETY:
537 // - `self.as_ptr()` is a valid object pointer
538 // - thread is attached to the Python interpreter
539 let ctx = unsafe { ffi::PyCapsule_GetContext(self.as_ptr()) };
540 if ctx.is_null() {
541 ensure_no_error(self.py())?
542 }
543 Ok(ctx)
544 }
545
546 fn pointer_checked(&self, name: Option<&CStr>) -> PyResult<NonNull<c_void>> {
547 // SAFETY:
548 // - `self.as_ptr()` is a valid object pointer
549 // - `name_ptr` is either a valid C string or null
550 // - thread is attached to the Python interpreter
551 let ptr = unsafe { ffi::PyCapsule_GetPointer(self.as_ptr(), name_ptr(name)) };
552 NonNull::new(ptr).ok_or_else(|| PyErr::fetch(self.py()))
553 }
554
555 fn is_valid_checked(&self, name: Option<&CStr>) -> bool {
556 // SAFETY:
557 // - `self.as_ptr()` is a valid object pointer
558 // - `name_ptr` is either a valid C string or null
559 // - thread is attached to the Python interpreter
560 let r = unsafe { ffi::PyCapsule_IsValid(self.as_ptr(), name_ptr(name)) };
561 r != 0
562 }
563
564 fn name(&self) -> PyResult<Option<CapsuleName>> {
565 // SAFETY:
566 // - `self.as_ptr()` is a valid object pointer
567 // - thread is attached to the Python interpreter
568 let name = unsafe { ffi::PyCapsule_GetName(self.as_ptr()) };
569
570 match NonNull::new(name.cast_mut()) {
571 Some(name) => Ok(Some(CapsuleName { ptr: name })),
572 None => {
573 ensure_no_error(self.py())?;
574 Ok(None)
575 }
576 }
577 }
578}
579
580/// The name given to a `capsule` object.
581///
582/// This is a thin wrapper around `*const c_char`, which can be accessed with the [`as_ptr`][Self::as_ptr]
583/// method. The [`as_cstr`][Self::as_cstr] method can be used as a convenience to access the name as a `&CStr`.
584///
585/// There is no guarantee that this capsule name pointer valid for any length of time, as arbitrary
586/// Python code may change the name of a capsule object (by reaching native code which calls
587/// [`PyCapsule_SetName`][ffi::PyCapsule_SetName]). See the safety notes on [`as_cstr`][Self::as_cstr].
588#[derive(Clone, Copy)]
589pub struct CapsuleName {
590 /// Pointer to the name c-string, known to be non-null.
591 ptr: NonNull<c_char>,
592}
593
594impl CapsuleName {
595 /// Returns the capsule name as a `&CStr`.
596 ///
597 /// Note: this method is a thin wrapper around [`CStr::from_ptr`] so (as of Rust 1.91) incurs a
598 /// length calculation on each call.
599 ///
600 /// # Safety
601 ///
602 /// There is no guarantee that the capsule name remains valid for any length of time, as arbitrary
603 /// Python code may change the name of the capsule. The caller should be aware of any conventions
604 /// of the capsule in question related to the lifetime of the name (many capsule names are
605 /// statically allocated, i.e. have the `'static` lifetime, but Python does not require this).
606 ///
607 /// The returned lifetime `'a` is not related to the lifetime of the capsule itself, and the caller is
608 /// responsible for using the `&CStr` for as short a time as possible.
609 pub unsafe fn as_cstr<'a>(self) -> &'a CStr {
610 // SAFETY: caller has upheld the safety contract
611 unsafe { CStr::from_ptr(self.as_ptr()) }
612 }
613
614 /// Returns the raw pointer to the capsule name.
615 pub fn as_ptr(self) -> *const c_char {
616 self.ptr.as_ptr().cast_const()
617 }
618}
619
620// C layout, as casting the capsule pointer to `T` depends on `T` being first.
621#[repr(C)]
622struct CapsuleContents<T: 'static + Send, D: FnOnce(T, *mut c_void) + Send + 'static> {
623 /// Value of the capsule
624 value: T,
625 /// Destructor to be used by the capsule
626 destructor: D,
627 /// Name used when creating the capsule
628 // TODO: remove this field when `PyCapsule::new` and `PyCapsule::new_with_destructor` are removed
629 name: Option<CString>,
630}
631
632// Wrapping ffi::PyCapsule_Destructor for a user supplied FnOnce(T) for capsule destructor
633unsafe extern "C" fn capsule_destructor<
634 T: 'static + Send,
635 F: FnOnce(T, *mut c_void) + Send + 'static,
636>(
637 capsule: *mut ffi::PyObject,
638) {
639 /// Gets the pointer and context from the capsule.
640 ///
641 /// # Safety
642 ///
643 /// - `capsule` must be a valid capsule object
644 unsafe fn get_pointer_ctx(capsule: *mut ffi::PyObject) -> (*mut c_void, *mut c_void) {
645 // SAFETY: `capsule` is known to be a borrowed reference to the capsule being destroyed
646 let name = unsafe { ffi::PyCapsule_GetName(capsule) };
647
648 // SAFETY:
649 // - `capsule` is known to be a borrowed reference to the capsule being destroyed
650 // - `name` is known to be the capsule's name
651 let ptr = unsafe { ffi::PyCapsule_GetPointer(capsule, name) };
652
653 // SAFETY:
654 // - `capsule` is known to be a borrowed reference to the capsule being destroyed
655 let ctx = unsafe { ffi::PyCapsule_GetContext(capsule) };
656
657 (ptr, ctx)
658 }
659
660 // SAFETY: `capsule` is known to be a valid capsule object
661 let (ptr, ctx) = unsafe { get_pointer_ctx(capsule) };
662
663 // SAFETY: `capsule` was knowingly constructed with a boxed `CapsuleContents<T, F>`
664 // and is now being destroyed, so we can move the data from the box.
665 let CapsuleContents::<T, F> {
666 value, destructor, ..
667 } = *unsafe { Box::from_raw(ptr.cast()) };
668
669 destructor(value, ctx);
670}
671
672fn ensure_no_error(py: Python<'_>) -> PyResult<()> {
673 if let Some(err) = PyErr::take(py) {
674 Err(err)
675 } else {
676 Ok(())
677 }
678}
679
680fn name_ptr(name: Option<&CStr>) -> *const c_char {
681 match name {
682 Some(name) => name.as_ptr(),
683 None => ptr::null(),
684 }
685}
686
687#[cfg(test)]
688mod tests {
689 use crate::prelude::PyModule;
690 use crate::types::capsule::PyCapsuleMethods;
691 use crate::types::module::PyModuleMethods;
692 use crate::{types::PyCapsule, Py, PyResult, Python};
693 use core::ffi::{c_void, CStr};
694 use core::ptr::NonNull;
695 use std::sync::mpsc::{channel, Sender};
696
697 const NAME: &CStr = c"foo";
698
699 #[test]
700 fn test_pycapsule_struct() {
701 #[repr(C)]
702 struct Foo {
703 pub val: u32,
704 }
705
706 impl Foo {
707 fn get_val(&self) -> u32 {
708 self.val
709 }
710 }
711
712 Python::attach(|py| {
713 let foo = Foo { val: 123 };
714
715 let cap = PyCapsule::new_with_value(py, foo, NAME).unwrap();
716 assert!(cap.is_valid_checked(Some(NAME)));
717
718 let foo_capi = cap.pointer_checked(Some(NAME)).unwrap().cast::<Foo>();
719 // SAFETY: `foo_capi` contains a `Foo` and will be valid for the duration of the assert
720 assert_eq!(unsafe { foo_capi.as_ref() }.val, 123);
721 // SAFETY: as above
722 assert_eq!(unsafe { foo_capi.as_ref() }.get_val(), 123);
723 assert_eq!(
724 // SAFETY: `cap.name()` has a non-null name
725 unsafe { CStr::from_ptr(cap.name().unwrap().unwrap().as_ptr()) },
726 NAME
727 );
728 // SAFETY: as above
729 assert_eq!(unsafe { cap.name().unwrap().unwrap().as_cstr() }, NAME)
730 })
731 }
732
733 #[test]
734 fn test_pycapsule_func() {
735 fn foo(x: u32) -> u32 {
736 x
737 }
738
739 let cap: Py<PyCapsule> = Python::attach(|py| {
740 let cap = PyCapsule::new_with_value(py, foo as fn(u32) -> u32, NAME).unwrap();
741 cap.into()
742 });
743
744 Python::attach(move |py| {
745 let f = cap
746 .bind(py)
747 .pointer_checked(Some(NAME))
748 .unwrap()
749 .cast::<fn(u32) -> u32>();
750 // SAFETY: `f` contains a `fn(u32) -> u32` and will be valid for the duration of the assert
751 assert_eq!(unsafe { f.as_ref() }(123), 123);
752 });
753 }
754
755 #[test]
756 fn test_pycapsule_context() {
757 Python::attach(|py| {
758 let cap = PyCapsule::new_with_value(py, 0, NAME).unwrap();
759
760 let c = cap.context().unwrap();
761 assert!(c.is_null());
762
763 let ctx = Box::new(123_u32);
764 cap.set_context(Box::into_raw(ctx).cast()).unwrap();
765
766 let ctx_ptr: *mut c_void = cap.context().unwrap();
767 // SAFETY: `ctx_ptr` contains a boxed `u32` which is being moved out of the capsule
768 let ctx = unsafe { *Box::from_raw(ctx_ptr.cast::<u32>()) };
769 assert_eq!(ctx, 123);
770 })
771 }
772
773 #[test]
774 fn test_pycapsule_import() {
775 #[repr(C)]
776 struct Foo {
777 pub val: u32,
778 }
779
780 Python::attach(|py| {
781 let foo = Foo { val: 123 };
782 let name = c"builtins.capsule";
783
784 let capsule = PyCapsule::new_with_value(py, foo, name).unwrap();
785
786 let module = PyModule::import(py, "builtins").unwrap();
787 module.add("capsule", capsule).unwrap();
788
789 // check error when wrong named passed for capsule.
790 // SAFETY: this function will fail so the cast is never done
791 let result: PyResult<&Foo> = unsafe { PyCapsule::import(py, c"builtins.non_existent") };
792 assert!(result.is_err());
793
794 // correct name is okay.
795 // SAFETY: we know the capsule at `name` contains a `Foo`
796 let cap: &Foo = unsafe { PyCapsule::import(py, name) }.unwrap();
797 assert_eq!(cap.val, 123);
798 })
799 }
800
801 #[test]
802 fn test_misaligned_import() {
803 #[repr(align(128))]
804 struct Align128 {
805 _n: usize,
806 }
807
808 Python::attach(|py| {
809 let ptr = NonNull::new(129 as *mut c_void).unwrap();
810 let name = c"builtins.capsule";
811
812 // SAFETY: the pointer will never be dereferenced
813 let capsule = unsafe { PyCapsule::new_with_pointer(py, ptr, name) }.unwrap();
814
815 let module = PyModule::import(py, "builtins").unwrap();
816 module.add("capsule", capsule).unwrap();
817
818 // SAFETY: this should return an error so no reference will be created
819 assert!(unsafe { PyCapsule::import::<Align128>(py, name) }.is_err());
820 });
821 }
822
823 #[test]
824 fn test_vec_storage() {
825 let cap: Py<PyCapsule> = Python::attach(|py| {
826 let stuff: Vec<u8> = vec![1, 2, 3, 4];
827 let cap = PyCapsule::new_with_value(py, stuff, NAME).unwrap();
828 cap.into()
829 });
830
831 Python::attach(move |py| {
832 let stuff = cap
833 .bind(py)
834 .pointer_checked(Some(NAME))
835 .unwrap()
836 .cast::<Vec<u8>>();
837 // SAFETY: `stuff` contains a `Vec<u8>` and will be valid for the duration of the assert
838 assert_eq!(unsafe { stuff.as_ref() }, &[1, 2, 3, 4]);
839 })
840 }
841
842 #[test]
843 fn test_vec_context() {
844 let context: Vec<u8> = vec![1, 2, 3, 4];
845
846 let cap: Py<PyCapsule> = Python::attach(|py| {
847 let cap = PyCapsule::new_with_value(py, 0, NAME).unwrap();
848 cap.set_context(Box::into_raw(Box::new(&context)).cast())
849 .unwrap();
850
851 cap.into()
852 });
853
854 Python::attach(move |py| {
855 let ctx_ptr: *mut c_void = cap.bind(py).context().unwrap();
856 // SAFETY: `ctx_ptr` contains a boxed `&Vec<u8>` which is being moved out of the capsule
857 let ctx = unsafe { *Box::from_raw(ctx_ptr.cast::<&Vec<u8>>()) };
858 assert_eq!(ctx, &vec![1_u8, 2, 3, 4]);
859 })
860 }
861
862 #[test]
863 fn test_pycapsule_destructor() {
864 let (tx, rx) = channel::<bool>();
865
866 fn destructor(_val: u32, ctx: *mut c_void) {
867 assert!(!ctx.is_null());
868 // SAFETY: `ctx` is known to be a boxed `Sender<bool>` needing deletion
869 let context = unsafe { *Box::from_raw(ctx.cast::<Sender<bool>>()) };
870 context.send(true).unwrap();
871 }
872
873 Python::attach(move |py| {
874 let cap = PyCapsule::new_with_value_and_destructor(py, 0, NAME, destructor).unwrap();
875 cap.set_context(Box::into_raw(Box::new(tx)).cast()).unwrap();
876 });
877
878 // the destructor was called.
879 assert_eq!(rx.recv(), Ok(true));
880 }
881
882 #[test]
883 #[allow(deprecated)]
884 fn test_pycapsule_no_name() {
885 Python::attach(|py| {
886 let cap = PyCapsule::new(py, 0usize, None).unwrap();
887
888 assert_eq!(
889 // SAFETY: `cap` is known to contain a `usize`
890 unsafe { cap.pointer_checked(None).unwrap().cast::<usize>().as_ref() },
891 &0usize
892 );
893 assert!(cap.name().unwrap().is_none());
894 assert_eq!(cap.context().unwrap(), core::ptr::null_mut());
895 });
896 }
897
898 #[test]
899 fn test_pycapsule_new_with_pointer() {
900 extern "C" fn dummy_handler(_: *mut c_void) -> *mut c_void {
901 core::ptr::null_mut()
902 }
903
904 let fn_ptr =
905 NonNull::new(dummy_handler as *mut c_void).expect("function pointer is non-null");
906
907 Python::attach(|py| {
908 // SAFETY: `fn_ptr` is known to point to `dummy_handler`
909 let capsule =
910 unsafe { PyCapsule::new_with_pointer(py, fn_ptr, c"test.dummy_handler") }.unwrap();
911
912 let retrieved_ptr = capsule
913 .pointer_checked(Some(c"test.dummy_handler"))
914 .unwrap();
915 assert_eq!(retrieved_ptr.as_ptr(), fn_ptr.as_ptr());
916 });
917 }
918
919 #[test]
920 fn test_pycapsule_new_with_pointer_and_destructor() {
921 use std::sync::mpsc::{channel, TryRecvError};
922
923 let (tx, rx) = channel::<bool>();
924
925 unsafe extern "C" fn destructor_fn(capsule: *mut crate::ffi::PyObject) {
926 // SAFETY:
927 // - `capsule` is a valid capsule object being destroyed by Python
928 // - The context was set to a valid `Box<Sender<bool>>` below
929 unsafe {
930 let ctx = crate::ffi::PyCapsule_GetContext(capsule);
931 if !ctx.is_null() {
932 let sender: Box<Sender<bool>> = Box::from_raw(ctx.cast());
933 let _ = sender.send(true);
934 }
935 }
936 }
937
938 let dummy_ptr =
939 NonNull::new(0xDEADBEEF as *mut c_void).expect("function pointer is non-null");
940
941 Python::attach(|py| {
942 // SAFETY:
943 // - `dummy_ptr` is non-null (it's a made-up address for testing)
944 // - We're providing a valid destructor function
945 let capsule = unsafe {
946 PyCapsule::new_with_pointer_and_destructor(
947 py,
948 dummy_ptr,
949 c"test.destructor_capsule",
950 Some(destructor_fn),
951 )
952 }
953 .unwrap();
954
955 // Store the sender in the capsule's context
956 let sender_box = Box::new(tx);
957 capsule
958 .set_context(Box::into_raw(sender_box).cast())
959 .unwrap();
960
961 // The destructor hasn't fired yet
962 assert_eq!(rx.try_recv(), Err(TryRecvError::Empty));
963 });
964
965 // After Python::attach scope ends, the capsule should be destroyed
966 assert_eq!(rx.recv(), Ok(true));
967 }
968
969 #[test]
970 fn test_pycapsule_pointer_checked_wrong_name() {
971 Python::attach(|py| {
972 let cap = PyCapsule::new_with_value(py, 123u32, c"correct.name").unwrap();
973
974 // Requesting with wrong name should fail
975 let result = cap.pointer_checked(Some(c"wrong.name"));
976 assert!(result.is_err());
977
978 // Requesting with None when capsule has a name should also fail
979 let result = cap.pointer_checked(None);
980 assert!(result.is_err());
981 });
982 }
983
984 #[test]
985 #[allow(deprecated)]
986 fn test_pycapsule_pointer_checked_none_vs_some() {
987 Python::attach(|py| {
988 // Capsule with no name
989 let cap_no_name = PyCapsule::new(py, 123u32, None).unwrap();
990
991 // Should succeed with None
992 assert!(cap_no_name.pointer_checked(None).is_ok());
993
994 // Should fail with Some(name)
995 let result = cap_no_name.pointer_checked(Some(c"some.name"));
996 assert!(result.is_err());
997 });
998 }
999
1000 #[test]
1001 fn test_pycapsule_is_valid_checked_wrong_name() {
1002 Python::attach(|py| {
1003 let cap = PyCapsule::new_with_value(py, 123u32, c"correct.name").unwrap();
1004
1005 // Should be valid with correct name
1006 assert!(cap.is_valid_checked(Some(c"correct.name")));
1007
1008 // Should be invalid with wrong name
1009 assert!(!cap.is_valid_checked(Some(c"wrong.name")));
1010
1011 // Should be invalid with None when capsule has a name
1012 assert!(!cap.is_valid_checked(None));
1013 });
1014 }
1015
1016 #[test]
1017 #[allow(deprecated)]
1018 fn test_pycapsule_is_valid_checked_no_name() {
1019 Python::attach(|py| {
1020 let cap = PyCapsule::new(py, 123u32, None).unwrap();
1021
1022 // Should be valid with None
1023 assert!(cap.is_valid_checked(None));
1024
1025 // Should be invalid with any name
1026 assert!(!cap.is_valid_checked(Some(c"any.name")));
1027 });
1028 }
1029
1030 #[test]
1031 fn test_pycapsule_context_on_invalid_capsule() {
1032 Python::attach(|py| {
1033 let cap = PyCapsule::new_with_value(py, 123u32, NAME).unwrap();
1034
1035 // Invalidate the capsule
1036 // SAFETY: intentionally breaking the capsule for testing
1037 unsafe {
1038 crate::ffi::PyCapsule_SetPointer(cap.as_ptr(), core::ptr::null_mut());
1039 }
1040
1041 // context() on invalid capsule should fail
1042 let result = cap.context();
1043 assert!(result.is_err());
1044 });
1045 }
1046
1047 #[test]
1048 fn test_pycapsule_import_wrong_module() {
1049 Python::attach(|py| {
1050 // Try to import from a non-existent module
1051 // SAFETY: we expect this to fail, no cast will occur
1052 let result: PyResult<&u32> =
1053 unsafe { PyCapsule::import(py, c"nonexistent_module.capsule") };
1054 assert!(result.is_err());
1055 });
1056 }
1057
1058 #[test]
1059 fn test_pycapsule_import_wrong_attribute() {
1060 Python::attach(|py| {
1061 // Create a capsule and register it
1062 let cap = PyCapsule::new_with_value(py, 123u32, c"builtins.test_cap").unwrap();
1063 let module = PyModule::import(py, "builtins").unwrap();
1064 module.add("test_cap", cap).unwrap();
1065
1066 // Try to import with wrong attribute name
1067 // SAFETY: we expect this to fail
1068 let result: PyResult<&u32> =
1069 unsafe { PyCapsule::import(py, c"builtins.wrong_attribute") };
1070 assert!(result.is_err());
1071 });
1072 }
1073
1074 #[test]
1075 fn test_capsule_with_zero_sized_type() {
1076 Python::attach(|py| {
1077 let cap = PyCapsule::new_with_value(py, (), c"test_capsule_zst").unwrap();
1078 let content = cap.pointer_checked(Some(c"test_capsule_zst")).unwrap();
1079 // SAFETY: Capsule invariant: the returned pointer is the given pointer
1080 assert_eq!(*unsafe { content.cast::<()>().as_ref() }, ());
1081 })
1082 }
1083}