rustpython_vm/builtins/
singletons.rs1use super::{PyStrRef, PyType, PyTypeRef};
2use crate::{
3 Context, Py, PyObjectRef, PyPayload, PyResult, VirtualMachine,
4 class::PyClassImpl,
5 common::hash::PyHash,
6 convert::ToPyObject,
7 function::{FuncArgs, PyComparisonValue},
8 protocol::PyNumberMethods,
9 types::{AsNumber, Comparable, Constructor, Hashable, PyComparisonOp, Representable},
10};
11
12#[pyclass(module = false, name = "NoneType")]
13#[derive(Debug)]
14pub struct PyNone;
15
16impl PyPayload for PyNone {
17 #[inline]
18 fn class(ctx: &Context) -> &'static Py<PyType> {
19 ctx.types.none_type
20 }
21}
22
23impl ToPyObject for () {
26 fn to_pyobject(self, vm: &VirtualMachine) -> PyObjectRef {
27 vm.ctx.none()
28 }
29}
30
31impl<T: ToPyObject> ToPyObject for Option<T> {
32 fn to_pyobject(self, vm: &VirtualMachine) -> PyObjectRef {
33 match self {
34 Some(x) => x.to_pyobject(vm),
35 None => vm.ctx.none(),
36 }
37 }
38}
39
40impl Constructor for PyNone {
41 type Args = ();
42
43 fn slot_new(_cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
44 let _: () = args.bind(vm)?;
45 Ok(vm.ctx.none.clone().into())
46 }
47
48 fn py_new(_cls: &Py<PyType>, _args: Self::Args, _vm: &VirtualMachine) -> PyResult<Self> {
49 unreachable!("None is a singleton")
50 }
51}
52
53#[pyclass(with(Constructor, AsNumber, Comparable, Hashable, Representable))]
54impl PyNone {}
55
56impl Representable for PyNone {
57 #[inline]
58 fn repr(_zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<PyStrRef> {
59 Ok(vm.ctx.names.None.to_owned())
60 }
61
62 #[cold]
63 fn repr_str(_zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<String> {
64 unreachable!("use repr instead")
65 }
66}
67
68impl AsNumber for PyNone {
69 fn as_number() -> &'static PyNumberMethods {
70 static AS_NUMBER: PyNumberMethods = PyNumberMethods {
71 boolean: Some(|_number, _vm| Ok(false)),
72 ..PyNumberMethods::NOT_IMPLEMENTED
73 };
74 &AS_NUMBER
75 }
76}
77
78impl Comparable for PyNone {
79 fn cmp(
80 zelf: &Py<Self>,
81 other: &crate::PyObject,
82 op: PyComparisonOp,
83 _vm: &VirtualMachine,
84 ) -> PyResult<PyComparisonValue> {
85 Ok(op
86 .identical_optimization(zelf, other)
87 .map(PyComparisonValue::Implemented)
88 .unwrap_or(PyComparisonValue::NotImplemented))
89 }
90}
91
92impl Hashable for PyNone {
93 fn hash(_zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<PyHash> {
94 Ok(0xFCA86420)
95 }
96}
97
98#[pyclass(module = false, name = "NotImplementedType")]
99#[derive(Debug)]
100pub struct PyNotImplemented;
101
102impl PyPayload for PyNotImplemented {
103 #[inline]
104 fn class(ctx: &Context) -> &'static Py<PyType> {
105 ctx.types.not_implemented_type
106 }
107}
108
109impl Constructor for PyNotImplemented {
110 type Args = ();
111
112 fn slot_new(_cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
113 let _: () = args.bind(vm)?;
114 Ok(vm.ctx.not_implemented.clone().into())
115 }
116
117 fn py_new(_cls: &Py<PyType>, _args: Self::Args, _vm: &VirtualMachine) -> PyResult<Self> {
118 unreachable!("PyNotImplemented is a singleton")
119 }
120}
121
122#[pyclass(with(Constructor, AsNumber, Representable), flags(IMMUTABLETYPE))]
123impl PyNotImplemented {
124 #[pymethod]
125 fn __reduce__(&self, vm: &VirtualMachine) -> PyStrRef {
126 vm.ctx.names.NotImplemented.to_owned()
127 }
128}
129
130impl AsNumber for PyNotImplemented {
131 fn as_number() -> &'static PyNumberMethods {
132 static AS_NUMBER: PyNumberMethods = PyNumberMethods {
133 boolean: Some(|_number, vm| {
134 Err(vm.new_type_error("NotImplemented should not be used in a boolean context"))
135 }),
136 ..PyNumberMethods::NOT_IMPLEMENTED
137 };
138 &AS_NUMBER
139 }
140}
141
142impl Representable for PyNotImplemented {
143 #[inline]
144 fn repr(_zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<PyStrRef> {
145 Ok(vm.ctx.names.NotImplemented.to_owned())
146 }
147
148 #[cold]
149 fn repr_str(_zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<String> {
150 unreachable!("use repr instead")
151 }
152}
153
154pub fn init(context: &'static Context) {
155 PyNone::extend_class(context, context.types.none_type);
156 PyNotImplemented::extend_class(context, context.types.not_implemented_type);
157}