From 4c53833e74233f3075e2b6dbd61dabf80b2a4930 Mon Sep 17 00:00:00 2001 From: Luiz Eduardo Amaral Date: Mon, 16 Feb 2026 23:28:36 -0300 Subject: [PATCH] add Sealed to callback traits --- src/impl_/callback.rs | 53 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/src/impl_/callback.rs b/src/impl_/callback.rs index 7ce01560aee..268c6cf2b8a 100644 --- a/src/impl_/callback.rs +++ b/src/impl_/callback.rs @@ -7,11 +7,26 @@ use crate::{BoundObject, IntoPyObject, Py, PyAny, Python}; use std::ffi::c_int; /// A type which can be the return type of a python C-API callback -pub trait PyCallbackOutput: Copy { +pub trait PyCallbackOutput: Copy + py_callback_output::Sealed { /// The error value to return to python if the callback raised an exception const ERR_VALUE: Self; } +/// Seals `PyCallbackOutput` so that types outside PyO3 cannot implement it. +mod py_callback_output { + use std::os::raw::c_int; + + use pyo3_ffi::Py_ssize_t; + + use crate::ffi::PyObject; + + pub trait Sealed {} + + impl Sealed for *mut PyObject {} + impl Sealed for c_int {} + impl Sealed for Py_ssize_t {} +} + impl PyCallbackOutput for *mut ffi::PyObject { const ERR_VALUE: Self = std::ptr::null_mut(); } @@ -25,10 +40,36 @@ impl PyCallbackOutput for ffi::Py_ssize_t { } /// Convert the result of callback function into the appropriate return value. -pub trait IntoPyCallbackOutput<'py, Target> { +pub trait IntoPyCallbackOutput<'py, Target>: into_py_callback_output::Sealed<'py, Target> { fn convert(self, py: Python<'py>) -> PyResult; } +/// Seals `IntoPyCallbackOutput` so that types outside PyO3 cannot implement it. +mod into_py_callback_output { + use pyo3_ffi::Py_hash_t; + + use crate::{ + ffi, + impl_::callback::{HashCallbackOutput, IntoPyCallbackOutput, WrappingCastTo}, + IntoPyObject, Py, PyAny, PyErr, + }; + + pub trait Sealed<'py, Target> {} + + impl<'py, T: IntoPyObject<'py>> Sealed<'py, *mut ffi::PyObject> for T {} + impl<'py, T: IntoPyCallbackOutput<'py, U>, E: Into, U> Sealed<'py, U> for Result {} + impl Sealed<'_, Self> for *mut ffi::PyObject {} + impl Sealed<'_, std::ffi::c_int> for () {} + impl Sealed<'_, std::ffi::c_int> for bool {} + impl Sealed<'_, ()> for () {} + impl Sealed<'_, ffi::Py_ssize_t> for usize {} + impl Sealed<'_, bool> for bool {} + impl Sealed<'_, usize> for usize {} + impl<'py, T: IntoPyObject<'py>> Sealed<'py, Py> for T {} + impl Sealed<'_, Py_hash_t> for HashCallbackOutput {} + impl> Sealed<'_, HashCallbackOutput> for T {} +} + impl<'py, T, E, U> IntoPyCallbackOutput<'py, U> for Result where T: IntoPyCallbackOutput<'py, U>, @@ -119,10 +160,15 @@ where } } -pub trait WrappingCastTo { +pub trait WrappingCastTo: wrapping_cast_to::Sealed { fn wrapping_cast(self) -> T; } +/// Seals `WrappingCastTo` so that types outside PyO3 cannot implement it. +mod wrapping_cast_to { + pub trait Sealed {} +} + macro_rules! wrapping_cast { ($from:ty, $to:ty) => { impl WrappingCastTo<$to> for $from { @@ -131,6 +177,7 @@ macro_rules! wrapping_cast { self as $to } } + impl wrapping_cast_to::Sealed<$to> for $from {} }; } wrapping_cast!(u8, Py_hash_t);