1use crate::ffi_ptr_ext::FfiPtrExt;
2use crate::{
3 ffi, types::any::PyAnyMethods, Borrowed, Bound, IntoPy, PyAny, PyObject, PyTypeInfo, Python,
4 ToPyObject,
5};
6
7#[repr(transparent)]
12pub struct PyNone(PyAny);
13
14pyobject_native_type_named!(PyNone);
15pyobject_native_type_extract!(PyNone);
16
17impl PyNone {
18 #[cfg(feature = "gil-refs")]
21 #[deprecated(
22 since = "0.21.0",
23 note = "`PyNone::get` will be replaced by `PyNone::get_bound` in a future PyO3 version"
24 )]
25 #[inline]
26 pub fn get(py: Python<'_>) -> &PyNone {
27 Self::get_bound(py).into_gil_ref()
28 }
29
30 #[inline]
32 pub fn get_bound(py: Python<'_>) -> Borrowed<'_, '_, PyNone> {
33 unsafe { ffi::Py_None().assume_borrowed(py).downcast_unchecked() }
34 }
35}
36
37unsafe impl PyTypeInfo for PyNone {
38 const NAME: &'static str = "NoneType";
39
40 const MODULE: Option<&'static str> = None;
41
42 fn type_object_raw(_py: Python<'_>) -> *mut ffi::PyTypeObject {
43 unsafe { ffi::Py_TYPE(ffi::Py_None()) }
44 }
45
46 #[inline]
47 fn is_type_of_bound(object: &Bound<'_, PyAny>) -> bool {
48 Self::is_exact_type_of_bound(object)
50 }
51
52 #[inline]
53 fn is_exact_type_of_bound(object: &Bound<'_, PyAny>) -> bool {
54 object.is(&**Self::get_bound(object.py()))
55 }
56}
57
58impl ToPyObject for () {
60 fn to_object(&self, py: Python<'_>) -> PyObject {
61 PyNone::get_bound(py).into_py(py)
62 }
63}
64
65impl IntoPy<PyObject> for () {
66 #[inline]
67 fn into_py(self, py: Python<'_>) -> PyObject {
68 PyNone::get_bound(py).into_py(py)
69 }
70}
71
72#[cfg(test)]
73mod tests {
74 use crate::types::any::PyAnyMethods;
75 use crate::types::{PyDict, PyNone};
76 use crate::{IntoPy, PyObject, PyTypeInfo, Python, ToPyObject};
77 #[test]
78 fn test_none_is_itself() {
79 Python::with_gil(|py| {
80 assert!(PyNone::get_bound(py).is_instance_of::<PyNone>());
81 assert!(PyNone::get_bound(py).is_exact_instance_of::<PyNone>());
82 })
83 }
84
85 #[test]
86 fn test_none_type_object_consistent() {
87 Python::with_gil(|py| {
88 assert!(PyNone::get_bound(py)
89 .get_type()
90 .is(&PyNone::type_object_bound(py)));
91 })
92 }
93
94 #[test]
95 fn test_none_is_none() {
96 Python::with_gil(|py| {
97 assert!(PyNone::get_bound(py)
98 .downcast::<PyNone>()
99 .unwrap()
100 .is_none());
101 })
102 }
103
104 #[test]
105 fn test_unit_to_object_is_none() {
106 Python::with_gil(|py| {
107 assert!(().to_object(py).downcast_bound::<PyNone>(py).is_ok());
108 })
109 }
110
111 #[test]
112 fn test_unit_into_py_is_none() {
113 Python::with_gil(|py| {
114 let obj: PyObject = ().into_py(py);
115 assert!(obj.downcast_bound::<PyNone>(py).is_ok());
116 })
117 }
118
119 #[test]
120 fn test_dict_is_not_none() {
121 Python::with_gil(|py| {
122 assert!(PyDict::new_bound(py).downcast::<PyNone>().is_err());
123 })
124 }
125}