1use crate::ffi_ptr_ext::FfiPtrExt;
2#[cfg(feature = "experimental-inspect")]
3use crate::inspect::{PyStaticConstant, PyStaticExpr};
4use crate::{ffi, types::any::PyAnyMethods, Borrowed, Bound, PyAny, PyTypeInfo, Python};
5
6#[repr(transparent)]
11pub struct PyNone(PyAny);
12
13pyobject_native_type_named!(PyNone);
14
15impl PyNone {
16 #[inline]
18 pub fn get(py: Python<'_>) -> Borrowed<'_, '_, PyNone> {
19 unsafe {
21 ffi::Py_None()
22 .assume_borrowed_unchecked(py)
23 .cast_unchecked()
24 }
25 }
26}
27
28unsafe impl PyTypeInfo for PyNone {
29 const NAME: &'static str = "NoneType";
30 const MODULE: Option<&'static str> = None;
31
32 #[cfg(feature = "experimental-inspect")]
33 const TYPE_HINT: PyStaticExpr = PyStaticExpr::Constant {
34 value: PyStaticConstant::None,
35 };
36
37 fn type_object_raw(_py: Python<'_>) -> *mut ffi::PyTypeObject {
38 unsafe { ffi::Py_TYPE(ffi::Py_None()) }
39 }
40
41 #[inline]
42 fn is_type_of(object: &Bound<'_, PyAny>) -> bool {
43 Self::is_exact_type_of(object)
45 }
46
47 #[inline]
48 fn is_exact_type_of(object: &Bound<'_, PyAny>) -> bool {
49 object.is(&**Self::get(object.py()))
50 }
51}
52
53#[cfg(test)]
54mod tests {
55 use crate::types::any::PyAnyMethods;
56 use crate::types::{PyDict, PyNone};
57 use crate::{PyTypeInfo, Python};
58
59 #[test]
60 fn test_none_is_itself() {
61 Python::attach(|py| {
62 assert!(PyNone::get(py).is_instance_of::<PyNone>());
63 assert!(PyNone::get(py).is_exact_instance_of::<PyNone>());
64 })
65 }
66
67 #[test]
68 fn test_none_type_object_consistent() {
69 Python::attach(|py| {
70 assert!(PyNone::get(py).get_type().is(PyNone::type_object(py)));
71 })
72 }
73
74 #[test]
75 fn test_none_is_none() {
76 Python::attach(|py| {
77 assert!(PyNone::get(py).cast::<PyNone>().unwrap().is_none());
78 })
79 }
80
81 #[test]
82 fn test_dict_is_not_none() {
83 Python::attach(|py| {
84 assert!(PyDict::new(py).cast::<PyNone>().is_err());
85 })
86 }
87}