Skip to content

Commit 256e56f

Browse files
authored
add Sealed to callback traits (#5821)
1 parent 023eadb commit 256e56f

File tree

1 file changed

+50
-3
lines changed

1 file changed

+50
-3
lines changed

src/impl_/callback.rs

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,26 @@ use crate::{BoundObject, IntoPyObject, Py, PyAny, Python};
77
use std::ffi::c_int;
88

99
/// A type which can be the return type of a python C-API callback
10-
pub trait PyCallbackOutput: Copy {
10+
pub trait PyCallbackOutput: Copy + py_callback_output::Sealed {
1111
/// The error value to return to python if the callback raised an exception
1212
const ERR_VALUE: Self;
1313
}
1414

15+
/// Seals `PyCallbackOutput` so that types outside PyO3 cannot implement it.
16+
mod py_callback_output {
17+
use std::os::raw::c_int;
18+
19+
use pyo3_ffi::Py_ssize_t;
20+
21+
use crate::ffi::PyObject;
22+
23+
pub trait Sealed {}
24+
25+
impl Sealed for *mut PyObject {}
26+
impl Sealed for c_int {}
27+
impl Sealed for Py_ssize_t {}
28+
}
29+
1530
impl PyCallbackOutput for *mut ffi::PyObject {
1631
const ERR_VALUE: Self = std::ptr::null_mut();
1732
}
@@ -25,10 +40,36 @@ impl PyCallbackOutput for ffi::Py_ssize_t {
2540
}
2641

2742
/// Convert the result of callback function into the appropriate return value.
28-
pub trait IntoPyCallbackOutput<'py, Target> {
43+
pub trait IntoPyCallbackOutput<'py, Target>: into_py_callback_output::Sealed<'py, Target> {
2944
fn convert(self, py: Python<'py>) -> PyResult<Target>;
3045
}
3146

47+
/// Seals `IntoPyCallbackOutput` so that types outside PyO3 cannot implement it.
48+
mod into_py_callback_output {
49+
use pyo3_ffi::Py_hash_t;
50+
51+
use crate::{
52+
ffi,
53+
impl_::callback::{HashCallbackOutput, IntoPyCallbackOutput, WrappingCastTo},
54+
IntoPyObject, Py, PyAny, PyErr,
55+
};
56+
57+
pub trait Sealed<'py, Target> {}
58+
59+
impl<'py, T: IntoPyObject<'py>> Sealed<'py, *mut ffi::PyObject> for T {}
60+
impl<'py, T: IntoPyCallbackOutput<'py, U>, E: Into<PyErr>, U> Sealed<'py, U> for Result<T, E> {}
61+
impl Sealed<'_, Self> for *mut ffi::PyObject {}
62+
impl Sealed<'_, std::ffi::c_int> for () {}
63+
impl Sealed<'_, std::ffi::c_int> for bool {}
64+
impl Sealed<'_, ()> for () {}
65+
impl Sealed<'_, ffi::Py_ssize_t> for usize {}
66+
impl Sealed<'_, bool> for bool {}
67+
impl Sealed<'_, usize> for usize {}
68+
impl<'py, T: IntoPyObject<'py>> Sealed<'py, Py<PyAny>> for T {}
69+
impl Sealed<'_, Py_hash_t> for HashCallbackOutput {}
70+
impl<T: WrappingCastTo<Py_hash_t>> Sealed<'_, HashCallbackOutput> for T {}
71+
}
72+
3273
impl<'py, T, E, U> IntoPyCallbackOutput<'py, U> for Result<T, E>
3374
where
3475
T: IntoPyCallbackOutput<'py, U>,
@@ -119,10 +160,15 @@ where
119160
}
120161
}
121162

122-
pub trait WrappingCastTo<T> {
163+
pub trait WrappingCastTo<T>: wrapping_cast_to::Sealed<T> {
123164
fn wrapping_cast(self) -> T;
124165
}
125166

167+
/// Seals `WrappingCastTo` so that types outside PyO3 cannot implement it.
168+
mod wrapping_cast_to {
169+
pub trait Sealed<T> {}
170+
}
171+
126172
macro_rules! wrapping_cast {
127173
($from:ty, $to:ty) => {
128174
impl WrappingCastTo<$to> for $from {
@@ -131,6 +177,7 @@ macro_rules! wrapping_cast {
131177
self as $to
132178
}
133179
}
180+
impl wrapping_cast_to::Sealed<$to> for $from {}
134181
};
135182
}
136183
wrapping_cast!(u8, Py_hash_t);

0 commit comments

Comments
 (0)