1#[cfg(feature = "experimental-inspect")]
2use crate::inspect::types::TypeInfo;
3use crate::{ffi, FromPyObject, IntoPy, PyAny, PyObject, PyResult, Python, ToPyObject};
4
5/// Represents a Python `bool`.
6#[repr(transparent)]
7pub struct PyBool(PyAny);
8
9pyobject_native_type!(PyBool, ffi::PyObject, pyobject_native_static_type_object!(ffi::PyBool_Type), #checkfunction=ffi::PyBool_Check);
10
11impl PyBool {
12 /// Depending on `val`, returns `true` or `false`.
13 #[inline]
14 pub fn new(py: Python<'_>, val: bool) -> &PyBool {
15 unsafe { py.from_borrowed_ptr(if val { ffi::Py_True() } else { ffi::Py_False() }) }
16 }
17
18 /// Gets whether this boolean is `true`.
19 #[inline]
20 pub fn is_true(&self) -> bool {
21 self.as_ptr() == unsafe { crate::ffi::Py_True() }
22 }
23}
24
25/// Converts a Rust `bool` to a Python `bool`.
26impl ToPyObject for bool {
27 #[inline]
28 fn to_object(&self, py: Python<'_>) -> PyObject {
29 unsafe {
30 PyObject::from_borrowed_ptr(
31 py,
32 ptr:if *self {
33 ffi::Py_True()
34 } else {
35 ffi::Py_False()
36 },
37 )
38 }
39 }
40}
41
42impl IntoPy<PyObject> for bool {
43 #[inline]
44 fn into_py(self, py: Python<'_>) -> PyObject {
45 PyBool::new(py, self).into()
46 }
47
48 #[cfg(feature = "experimental-inspect")]
49 fn type_output() -> TypeInfo {
50 TypeInfo::builtin("bool")
51 }
52}
53
54/// Converts a Python `bool` to a Rust `bool`.
55///
56/// Fails with `TypeError` if the input is not a Python `bool`.
57impl<'source> FromPyObject<'source> for bool {
58 fn extract(obj: &'source PyAny) -> PyResult<Self> {
59 Ok(obj.downcast::<PyBool>()?.is_true())
60 }
61
62 #[cfg(feature = "experimental-inspect")]
63 fn type_input() -> TypeInfo {
64 Self::type_output()
65 }
66}
67
68#[cfg(test)]
69mod tests {
70 use crate::types::{PyAny, PyBool};
71 use crate::Python;
72 use crate::ToPyObject;
73
74 #[test]
75 fn test_true() {
76 Python::with_gil(|py| {
77 assert!(PyBool::new(py, true).is_true());
78 let t: &PyAny = PyBool::new(py, true).into();
79 assert!(t.extract::<bool>().unwrap());
80 assert!(true.to_object(py).is(PyBool::new(py, true)));
81 });
82 }
83
84 #[test]
85 fn test_false() {
86 Python::with_gil(|py| {
87 assert!(!PyBool::new(py, false).is_true());
88 let t: &PyAny = PyBool::new(py, false).into();
89 assert!(!t.extract::<bool>().unwrap());
90 assert!(false.to_object(py).is(PyBool::new(py, false)));
91 });
92 }
93}
94