1use crate::{
4 builtins::{PyBaseObject, PyType, PyTypeRef},
5 function::PyMethodDef,
6 identifier,
7 object::Py,
8 types::{hash_not_implemented, PyTypeFlags, PyTypeSlots},
9 vm::Context,
10};
11use rustpython_common::static_cell;
12
13pub trait StaticType {
14 fn static_cell() -> &'static static_cell::StaticCell<PyTypeRef>;
16 fn static_metaclass() -> &'static Py<PyType> {
17 PyType::static_type()
18 }
19 fn static_baseclass() -> &'static Py<PyType> {
20 PyBaseObject::static_type()
21 }
22 fn static_type() -> &'static Py<PyType> {
23 Self::static_cell()
24 .get()
25 .expect("static type has not been initialized. e.g. the native types defined in different module may be used before importing library.")
26 }
27 fn init_manually(typ: PyTypeRef) -> &'static Py<PyType> {
28 let cell = Self::static_cell();
29 cell.set(typ)
30 .unwrap_or_else(|_| panic!("double initialization from init_manually"));
31 cell.get().unwrap()
32 }
33 fn init_builtin_type() -> &'static Py<PyType>
34 where
35 Self: PyClassImpl,
36 {
37 let typ = Self::create_static_type();
38 let cell = Self::static_cell();
39 cell.set(typ)
40 .unwrap_or_else(|_| panic!("double initialization of {}", Self::NAME));
41 cell.get().unwrap()
42 }
43 fn create_static_type() -> PyTypeRef
44 where
45 Self: PyClassImpl,
46 {
47 PyType::new_static(
48 Self::static_baseclass().to_owned(),
49 Default::default(),
50 Self::make_slots(),
51 Self::static_metaclass().to_owned(),
52 )
53 .unwrap()
54 }
55}
56
57pub trait PyClassDef {
58 const NAME: &'static str;
59 const MODULE_NAME: Option<&'static str>;
60 const TP_NAME: &'static str;
61 const DOC: Option<&'static str> = None;
62 const BASICSIZE: usize;
63 const UNHASHABLE: bool = false;
64
65 type Base: PyClassDef;
68}
69
70pub trait PyClassImpl: PyClassDef {
71 const TP_FLAGS: PyTypeFlags = PyTypeFlags::DEFAULT;
72
73 fn extend_class(ctx: &Context, class: &'static Py<PyType>)
74 where
75 Self: Sized,
76 {
77 #[cfg(debug_assertions)]
78 {
79 assert!(class.slots.flags.is_created_with_flags());
80 }
81
82 let _ = ctx.intern_str(Self::NAME); if Self::TP_FLAGS.has_feature(PyTypeFlags::HAS_DICT) {
85 let __dict__ = identifier!(ctx, __dict__);
86 class.set_attr(
87 __dict__,
88 ctx.new_getset(
89 "__dict__",
90 class,
91 crate::builtins::object::object_get_dict,
92 crate::builtins::object::object_set_dict,
93 )
94 .into(),
95 );
96 }
97 Self::impl_extend_class(ctx, class);
98 if let Some(doc) = Self::DOC {
99 class.set_attr(identifier!(ctx, __doc__), ctx.new_str(doc).into());
100 }
101 if let Some(module_name) = Self::MODULE_NAME {
102 class.set_attr(
103 identifier!(ctx, __module__),
104 ctx.new_str(module_name).into(),
105 );
106 }
107
108 if class.slots.new.load().is_some() {
109 let bound_new = Context::genesis().slot_new_wrapper.build_bound_method(
110 ctx,
111 class.to_owned().into(),
112 class,
113 );
114 class.set_attr(identifier!(ctx, __new__), bound_new.into());
115 }
116
117 if class.slots.hash.load().map_or(0, |h| h as usize) == hash_not_implemented as usize {
118 class.set_attr(ctx.names.__hash__, ctx.none.clone().into());
119 }
120
121 class.extend_methods(class.slots.methods, ctx);
122 }
123
124 fn make_class(ctx: &Context) -> PyTypeRef
125 where
126 Self: StaticType + Sized,
127 {
128 (*Self::static_cell().get_or_init(|| {
129 let typ = Self::create_static_type();
130 Self::extend_class(ctx, unsafe {
131 let r: &Py<PyType> = &typ;
133 let r: &'static Py<PyType> = std::mem::transmute(r);
134 r
135 });
136 typ
137 }))
138 .to_owned()
139 }
140
141 fn impl_extend_class(ctx: &Context, class: &'static Py<PyType>);
142 const METHOD_DEFS: &'static [PyMethodDef];
143 fn extend_slots(slots: &mut PyTypeSlots);
144
145 fn make_slots() -> PyTypeSlots {
146 let mut slots = PyTypeSlots {
147 flags: Self::TP_FLAGS,
148 name: Self::TP_NAME,
149 basicsize: Self::BASICSIZE,
150 doc: Self::DOC,
151 methods: Self::METHOD_DEFS,
152 ..Default::default()
153 };
154
155 if Self::UNHASHABLE {
156 slots.hash.store(Some(hash_not_implemented));
157 }
158
159 Self::extend_slots(&mut slots);
160 slots
161 }
162}