1use std::{any::Any, collections::BTreeSet, sync::Arc};
4
5use sim_kernel::{
6 Args, Callable, Class, ClassId, ClassRef, Cx, Error, Object, ObjectCompat, ReadConstructorRef,
7 Result, ShapeRef, Symbol, TableRef, Value,
8};
9
10use crate::ClassDescriptor;
11
12pub trait ClassConstructor: Send + Sync + 'static {
14 fn construct(&self, cx: &mut Cx, args: Args) -> Result<Value>;
15}
16
17impl<F> ClassConstructor for F
18where
19 F: Fn(&mut Cx, Args) -> Result<Value> + Send + Sync + 'static,
20{
21 fn construct(&self, cx: &mut Cx, args: Args) -> Result<Value> {
22 self(cx, args)
23 }
24}
25
26#[derive(Clone, Debug, PartialEq, Eq)]
28pub struct SubclassEvidence {
29 pub visited_nodes: usize,
30 pub performed_work: usize,
31}
32
33#[derive(Clone, Debug, PartialEq, Eq)]
35pub enum SubclassQuery {
36 Answer {
37 is_subclass: bool,
38 evidence: SubclassEvidence,
39 },
40 NodeBudgetExhausted {
41 limit: usize,
42 required: usize,
43 evidence: SubclassEvidence,
44 },
45 WorkBudgetExhausted {
46 limit: usize,
47 evidence: SubclassEvidence,
48 },
49}
50
51pub struct DescriptorClass {
53 descriptor: ClassDescriptor,
54 constructor: Arc<dyn ClassConstructor>,
55 subclass_nodes: usize,
56 subclass_work: usize,
57}
58
59impl DescriptorClass {
60 pub fn new(
61 descriptor: ClassDescriptor,
62 constructor: impl ClassConstructor,
63 subclass_nodes: usize,
64 subclass_work: usize,
65 ) -> Self {
66 Self {
67 descriptor,
68 constructor: Arc::new(constructor),
69 subclass_nodes,
70 subclass_work,
71 }
72 }
73
74 pub fn descriptor(&self) -> &ClassDescriptor {
75 &self.descriptor
76 }
77
78 pub fn query_subclass(
80 &self,
81 cx: &mut Cx,
82 expected: ClassRef,
83 node_limit: usize,
84 work_limit: usize,
85 ) -> Result<SubclassQuery> {
86 let Some(expected) = expected.object().as_class() else {
87 return Ok(SubclassQuery::Answer {
88 is_subclass: false,
89 evidence: SubclassEvidence {
90 visited_nodes: 0,
91 performed_work: 0,
92 },
93 });
94 };
95 let mut stack = vec![self.parents(cx)?];
96 let mut seen = BTreeSet::from([self.id()]);
97 let mut evidence = SubclassEvidence {
98 visited_nodes: 1,
99 performed_work: 0,
100 };
101 if self.id() == expected.id() {
102 return Ok(SubclassQuery::Answer {
103 is_subclass: true,
104 evidence,
105 });
106 }
107
108 while let Some(parents) = stack.last_mut() {
109 let Some(parent) = parents.pop() else {
110 stack.pop();
111 continue;
112 };
113 if evidence.performed_work == work_limit {
114 return Ok(SubclassQuery::WorkBudgetExhausted {
115 limit: work_limit,
116 evidence,
117 });
118 }
119 evidence.performed_work += 1;
120 let Some(parent) = parent.object().as_class() else {
121 continue;
122 };
123 if !seen.insert(parent.id()) {
124 continue;
125 }
126 let required = evidence.visited_nodes + 1;
127 if required > node_limit {
128 return Ok(SubclassQuery::NodeBudgetExhausted {
129 limit: node_limit,
130 required,
131 evidence,
132 });
133 }
134 evidence.visited_nodes = required;
135 if parent.id() == expected.id() {
136 return Ok(SubclassQuery::Answer {
137 is_subclass: true,
138 evidence,
139 });
140 }
141 stack.push(parent.parents(cx)?);
142 }
143 Ok(SubclassQuery::Answer {
144 is_subclass: false,
145 evidence,
146 })
147 }
148}
149
150impl Object for DescriptorClass {
151 fn display(&self, _cx: &mut Cx) -> Result<String> {
152 Ok(format!("#<class {}>", self.descriptor.identity().symbol()))
153 }
154
155 fn as_any(&self) -> &dyn Any {
156 self
157 }
158}
159
160impl ObjectCompat for DescriptorClass {
161 fn class(&self, cx: &mut Cx) -> Result<ClassRef> {
162 cx.resolve_class(&Symbol::qualified("core", "Class"))
163 }
164 fn as_callable(&self) -> Option<&dyn Callable> {
165 Some(self)
166 }
167 fn as_class(&self) -> Option<&dyn Class> {
168 Some(self)
169 }
170}
171
172impl Callable for DescriptorClass {
173 fn call(&self, cx: &mut Cx, args: Args) -> Result<Value> {
174 self.constructor.construct(cx, args)
175 }
176 fn browse_args_shape(&self, _cx: &mut Cx) -> Result<Option<ShapeRef>> {
177 Ok(Some(self.descriptor.constructor_shape().clone()))
178 }
179 fn browse_result_shape(&self, _cx: &mut Cx) -> Result<Option<ShapeRef>> {
180 Ok(Some(self.descriptor.instance_shape().clone()))
181 }
182}
183
184impl Class for DescriptorClass {
185 fn id(&self) -> ClassId {
186 self.descriptor.identity().id()
187 }
188 fn symbol(&self) -> Symbol {
189 self.descriptor.identity().symbol().clone()
190 }
191 fn parents(&self, _cx: &mut Cx) -> Result<Vec<ClassRef>> {
192 Ok(self
193 .descriptor
194 .parents()
195 .iter()
196 .filter_map(|parent| parent.resolved_class().cloned())
197 .collect())
198 }
199 fn is_subclass_of(&self, cx: &mut Cx, expected: ClassRef) -> Result<bool> {
200 match self.query_subclass(cx, expected, self.subclass_nodes, self.subclass_work)? {
201 SubclassQuery::Answer { is_subclass, .. } => Ok(is_subclass),
202 evidence => Err(Error::Lib(format!(
203 "bounded class lineage exhausted: {evidence:?}"
204 ))),
205 }
206 }
207 fn constructor_shape(&self, _cx: &mut Cx) -> Result<ShapeRef> {
208 Ok(self.descriptor.constructor_shape().clone())
209 }
210 fn instance_shape(&self, _cx: &mut Cx) -> Result<ShapeRef> {
211 Ok(self.descriptor.instance_shape().clone())
212 }
213 fn read_constructor(&self, _cx: &mut Cx) -> Result<Option<ReadConstructorRef>> {
214 Ok(self
215 .descriptor
216 .read_construction()
217 .map(|read| read.constructor.clone()))
218 }
219 fn members(&self, cx: &mut Cx) -> Result<TableRef> {
220 cx.factory().table(
221 self.descriptor
222 .members()
223 .iter()
224 .map(|member| (member.name.clone(), member.shape.clone()))
225 .collect(),
226 )
227 }
228}