1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
use super::PyObject;
use crate::conversion::ToPyObject;
use crate::err::PyResult;
use crate::ffi;
use crate::python::Python;

/// Represents a Python `bool`.
pub struct PyBool(PyObject);

pyobject_newtype!(PyBool, PyBool_Check, PyBool_Type);

impl PyBool {
    /// Depending on `val`, returns `py.True()` or `py.False()`.
    #[inline]
    pub fn get(py: Python, val: bool) -> PyBool {
        if val {
            py.True()
        } else {
            py.False()
        }
    }

    /// Gets whether this boolean is `true`.
    #[inline]
    pub fn is_true(&self) -> bool {
        self.0.as_ptr() == unsafe { crate::ffi::Py_True() }
    }
}

/// Converts a rust `bool` to a Python `bool`.
impl ToPyObject for bool {
    type ObjectType = PyBool;

    #[inline]
    fn to_py_object(&self, py: Python) -> PyBool {
        PyBool::get(py, *self)
    }

    #[inline]
    fn with_borrowed_ptr<F, R>(&self, _py: Python, f: F) -> R
    where
        F: FnOnce(*mut ffi::PyObject) -> R,
    {
        // Avoid unnecessary Py_INCREF/Py_DECREF pair
        f(unsafe {
            if *self {
                ffi::Py_True()
            } else {
                ffi::Py_False()
            }
        })
    }
}

extract!(obj to bool;
    /// Converts a Python `bool` to a rust `bool`.
    ///
    /// Fails with `TypeError` if the input is not a Python `bool`.
    py => {
        Ok(obj.cast_as::<PyBool>(py)?.is_true())
    }
);

#[cfg(test)]
mod test {
    use crate::conversion::ToPyObject;
    use crate::python::{Python, PythonObject};

    #[test]
    fn test_true() {
        let gil = Python::acquire_gil();
        let py = gil.python();
        assert!(py.True().is_true());
        assert_eq!(true, py.True().as_object().extract(py).unwrap());
        assert!(true.to_py_object(py).as_object() == py.True().as_object());
    }

    #[test]
    fn test_false() {
        let gil = Python::acquire_gil();
        let py = gil.python();
        assert!(!py.False().is_true());
        assert_eq!(false, py.False().as_object().extract(py).unwrap());
        assert!(false.to_py_object(py).as_object() == py.False().as_object());
    }
}