1use std::sync::Arc;
4
5use sim_kernel::{
6 AbiVersion, Args, CORE_CLASS_CLASS_ID, CORE_FUNCTION_CLASS_ID, Callable, Class, ClassId,
7 ClassRef, Cx, DefaultFactory, Export, Expr, Factory, Lib, LibManifest, LibTarget, Linker,
8 Object, ObjectCompat, ObjectEncode, ObjectEncoding, ReadConstructor, ReadConstructorRef, Ref,
9 Result, ShapeRef, Symbol, TableRef, Value, Version,
10};
11
12use crate::{
13 FidelityBadge, LanguageProfile, fidelity_badge_class_symbol, language_profile_class_symbol,
14};
15
16const PROFILE_CLASS_ID: ClassId = ClassId(6100);
17const FIDELITY_BADGE_CLASS_ID: ClassId = ClassId(6101);
18
19#[derive(Clone)]
21pub struct LanguageProfileValue {
22 profile: LanguageProfile,
23}
24
25impl LanguageProfileValue {
26 pub fn new(profile: LanguageProfile) -> Self {
28 Self { profile }
29 }
30
31 pub fn profile(&self) -> &LanguageProfile {
33 &self.profile
34 }
35}
36
37impl Object for LanguageProfileValue {
38 fn display(&self, _cx: &mut Cx) -> Result<String> {
39 Ok(format!("#<standard-profile {}>", self.profile.symbol))
40 }
41
42 fn as_any(&self) -> &dyn std::any::Any {
43 self
44 }
45}
46
47impl ObjectCompat for LanguageProfileValue {
48 fn class(&self, cx: &mut Cx) -> Result<ClassRef> {
49 class_value_or_stub(cx, PROFILE_CLASS_ID, language_profile_class_symbol())
50 }
51
52 fn as_expr(&self, _cx: &mut Cx) -> Result<Expr> {
53 Ok(Expr::Call {
54 operator: Box::new(Expr::Symbol(language_profile_class_symbol())),
55 args: self.profile.to_constructor_args(),
56 })
57 }
58
59 fn as_object_encoder(&self) -> Option<&dyn ObjectEncode> {
60 Some(self)
61 }
62}
63
64impl ObjectEncode for LanguageProfileValue {
65 fn object_encoding(&self, _cx: &mut Cx) -> Result<ObjectEncoding> {
66 Ok(ObjectEncoding::Constructor {
67 class: language_profile_class_symbol(),
68 args: self.profile.to_constructor_args(),
69 })
70 }
71}
72
73impl sim_citizen::Citizen for LanguageProfileValue {
74 fn citizen_symbol() -> Symbol {
75 language_profile_class_symbol()
76 }
77
78 fn citizen_version() -> u32 {
79 0
80 }
81
82 fn citizen_arity() -> usize {
83 10
84 }
85
86 fn citizen_fields() -> &'static [&'static str] {
87 &[
88 "symbol",
89 "reader",
90 "lowering",
91 "eval_policy",
92 "organs",
93 "numeric_tower",
94 "capabilities",
95 "unsupported_forms",
96 "conformance_tests",
97 "fidelity_badges",
98 ]
99 }
100}
101
102#[derive(Clone)]
104pub struct FidelityBadgeValue {
105 badge: FidelityBadge,
106}
107
108impl FidelityBadgeValue {
109 pub fn new(badge: FidelityBadge) -> Self {
111 Self { badge }
112 }
113
114 pub fn badge(&self) -> &FidelityBadge {
116 &self.badge
117 }
118}
119
120impl Object for FidelityBadgeValue {
121 fn display(&self, _cx: &mut Cx) -> Result<String> {
122 Ok(format!("#<standard-fidelity {}>", self.badge.badge))
123 }
124
125 fn as_any(&self) -> &dyn std::any::Any {
126 self
127 }
128}
129
130impl ObjectCompat for FidelityBadgeValue {
131 fn class(&self, cx: &mut Cx) -> Result<ClassRef> {
132 class_value_or_stub(cx, FIDELITY_BADGE_CLASS_ID, fidelity_badge_class_symbol())
133 }
134
135 fn as_expr(&self, _cx: &mut Cx) -> Result<Expr> {
136 Ok(Expr::Call {
137 operator: Box::new(Expr::Symbol(fidelity_badge_class_symbol())),
138 args: self.badge.to_constructor_args(),
139 })
140 }
141
142 fn as_object_encoder(&self) -> Option<&dyn ObjectEncode> {
143 Some(self)
144 }
145}
146
147impl ObjectEncode for FidelityBadgeValue {
148 fn object_encoding(&self, _cx: &mut Cx) -> Result<ObjectEncoding> {
149 Ok(ObjectEncoding::Constructor {
150 class: fidelity_badge_class_symbol(),
151 args: self.badge.to_constructor_args(),
152 })
153 }
154}
155
156impl sim_citizen::Citizen for FidelityBadgeValue {
157 fn citizen_symbol() -> Symbol {
158 fidelity_badge_class_symbol()
159 }
160
161 fn citizen_version() -> u32 {
162 0
163 }
164
165 fn citizen_arity() -> usize {
166 4
167 }
168
169 fn citizen_fields() -> &'static [&'static str] {
170 &["subject", "badge", "level", "evidence"]
171 }
172}
173
174pub fn install_standard_core_classes(cx: &mut Cx) -> Result<()> {
181 sim_lib_core::install_once(cx, &StandardCoreClassesLib).map(|_| ())
182}
183
184pub fn standard_core_classes_lib_symbol() -> Symbol {
186 Symbol::qualified("standard", "classes")
187}
188
189struct StandardCoreClassesLib;
190
191impl Lib for StandardCoreClassesLib {
192 fn manifest(&self) -> LibManifest {
193 LibManifest {
194 id: standard_core_classes_lib_symbol(),
195 version: Version(env!("CARGO_PKG_VERSION").to_owned()),
196 abi: AbiVersion { major: 0, minor: 1 },
197 target: LibTarget::HostRegistered,
198 requires: Vec::new(),
199 capabilities: Vec::new(),
200 exports: [StandardClassKind::Profile, StandardClassKind::FidelityBadge]
201 .into_iter()
202 .map(|kind| Export::Class {
203 symbol: kind.symbol(),
204 class_id: Some(kind.id()),
205 })
206 .collect(),
207 }
208 }
209
210 fn load(&self, _cx: &mut sim_kernel::LoadCx, linker: &mut Linker<'_>) -> Result<()> {
211 register_standard_class(linker, StandardClassKind::Profile)?;
212 register_standard_class(linker, StandardClassKind::FidelityBadge)
213 }
214}
215
216#[derive(Clone, Copy)]
217enum StandardClassKind {
218 Profile,
219 FidelityBadge,
220}
221
222impl StandardClassKind {
223 fn id(self) -> ClassId {
224 match self {
225 Self::Profile => PROFILE_CLASS_ID,
226 Self::FidelityBadge => FIDELITY_BADGE_CLASS_ID,
227 }
228 }
229
230 fn symbol(self) -> Symbol {
231 match self {
232 Self::Profile => language_profile_class_symbol(),
233 Self::FidelityBadge => fidelity_badge_class_symbol(),
234 }
235 }
236
237 fn display_name(self) -> &'static str {
238 match self {
239 Self::Profile => "standard/Profile",
240 Self::FidelityBadge => "standard/FidelityBadge",
241 }
242 }
243}
244
245#[derive(Clone)]
246struct StandardClass {
247 kind: StandardClassKind,
248}
249
250impl Object for StandardClass {
251 fn display(&self, _cx: &mut Cx) -> Result<String> {
252 Ok(format!("#<class {}>", self.kind.display_name()))
253 }
254
255 fn as_any(&self) -> &dyn std::any::Any {
256 self
257 }
258}
259
260impl ObjectCompat for StandardClass {
261 fn class(&self, cx: &mut Cx) -> Result<ClassRef> {
262 class_value_or_stub(cx, CORE_CLASS_CLASS_ID, Symbol::qualified("core", "Class"))
263 }
264
265 fn as_expr(&self, _cx: &mut Cx) -> Result<Expr> {
266 Ok(Expr::Symbol(self.kind.symbol()))
267 }
268
269 fn as_callable(&self) -> Option<&dyn Callable> {
270 Some(self)
271 }
272
273 fn as_class(&self) -> Option<&dyn Class> {
274 Some(self)
275 }
276}
277
278impl Callable for StandardClass {
279 fn call(&self, cx: &mut Cx, args: Args) -> Result<Value> {
280 construct_standard_value(cx, self.kind, args.into_vec())
281 }
282}
283
284impl Class for StandardClass {
285 fn id(&self) -> ClassId {
286 self.kind.id()
287 }
288
289 fn symbol(&self) -> Symbol {
290 self.kind.symbol()
291 }
292
293 fn constructor_shape(&self, cx: &mut Cx) -> Result<ShapeRef> {
294 cx.factory().nil()
295 }
296
297 fn instance_shape(&self, cx: &mut Cx) -> Result<ShapeRef> {
298 cx.factory().nil()
299 }
300
301 fn read_constructor(&self, _cx: &mut Cx) -> Result<Option<ReadConstructorRef>> {
302 Ok(Some(DefaultFactory.opaque(Arc::new(
303 StandardReadConstructor { kind: self.kind },
304 ))?))
305 }
306
307 fn members(&self, cx: &mut Cx) -> Result<TableRef> {
308 cx.factory().table(Vec::new())
309 }
310}
311
312#[derive(Clone)]
313struct StandardReadConstructor {
314 kind: StandardClassKind,
315}
316
317impl Object for StandardReadConstructor {
318 fn display(&self, _cx: &mut Cx) -> Result<String> {
319 Ok(format!("#<read-constructor {}>", self.kind.display_name()))
320 }
321
322 fn as_any(&self) -> &dyn std::any::Any {
323 self
324 }
325}
326
327impl ObjectCompat for StandardReadConstructor {
328 fn class(&self, cx: &mut Cx) -> Result<ClassRef> {
329 class_value_or_stub(
330 cx,
331 CORE_FUNCTION_CLASS_ID,
332 Symbol::qualified("core", "Function"),
333 )
334 }
335
336 fn as_read_constructor(&self) -> Option<&dyn ReadConstructor> {
337 Some(self)
338 }
339}
340
341impl ReadConstructor for StandardReadConstructor {
342 fn symbol(&self) -> Symbol {
343 self.kind.symbol()
344 }
345
346 fn args_shape(&self, cx: &mut Cx) -> Result<ShapeRef> {
347 cx.factory().nil()
348 }
349
350 fn construct_read(&self, cx: &mut Cx, args: Vec<Value>) -> Result<Value> {
351 construct_standard_value(cx, self.kind, args)
352 }
353}
354
355fn construct_standard_value(
356 cx: &mut Cx,
357 kind: StandardClassKind,
358 args: Vec<Value>,
359) -> Result<Value> {
360 let exprs = value_exprs(cx, args)?;
361 match kind {
362 StandardClassKind::Profile => cx.factory().opaque(Arc::new(LanguageProfileValue::new(
363 LanguageProfile::from_constructor_args(exprs)?,
364 ))),
365 StandardClassKind::FidelityBadge => cx.factory().opaque(Arc::new(FidelityBadgeValue::new(
366 FidelityBadge::from_constructor_args(exprs)?,
367 ))),
368 }
369}
370
371fn value_exprs(cx: &mut Cx, args: Vec<Value>) -> Result<Vec<Expr>> {
372 let mut exprs = Vec::with_capacity(args.len());
373 for value in args {
374 exprs.push(value.object().as_expr(cx)?);
375 }
376 Ok(exprs)
377}
378
379fn register_standard_class(linker: &mut Linker<'_>, kind: StandardClassKind) -> Result<()> {
380 let class = DefaultFactory
381 .opaque(Arc::new(StandardClass { kind }))
382 .expect("standard class should be boxable");
383 linker.class_value(kind.symbol(), class)?;
384 Ok(())
385}
386
387fn install_language_profile_citizen(linker: &mut Linker<'_>) -> Result<()> {
388 register_standard_class(linker, StandardClassKind::Profile)
389}
390
391fn install_fidelity_badge_citizen(linker: &mut Linker<'_>) -> Result<()> {
392 register_standard_class(linker, StandardClassKind::FidelityBadge)
393}
394
395fn conformance_language_profile_citizen(cx: &mut Cx) -> Result<()> {
396 let profile = LanguageProfile::new(Symbol::qualified("standard-citizen", "profile"));
397 let value = cx
398 .factory()
399 .opaque(Arc::new(LanguageProfileValue::new(profile)))?;
400 sim_citizen::check_value_fixture(cx, value)
401}
402
403fn conformance_fidelity_badge_citizen(cx: &mut Cx) -> Result<()> {
404 let badge = FidelityBadge::new(
405 Ref::Symbol(Symbol::qualified("standard-citizen", "subject")),
406 Symbol::qualified("standard-citizen", "badge"),
407 2,
408 Ref::Symbol(Symbol::qualified("standard-citizen", "evidence")),
409 );
410 let value = cx
411 .factory()
412 .opaque(Arc::new(FidelityBadgeValue::new(badge)))?;
413 sim_citizen::check_value_fixture(cx, value)
414}
415
416sim_citizen::inventory::submit! {
417 sim_citizen::CitizenInfo {
418 symbol: "standard/Profile",
419 version: 0,
420 crate_name: env!("CARGO_PKG_NAME"),
421 arity: 10,
422 install: install_language_profile_citizen,
423 conformance: conformance_language_profile_citizen,
424 }
425}
426
427sim_citizen::inventory::submit! {
428 sim_citizen::CitizenInfo {
429 symbol: "standard/FidelityBadge",
430 version: 0,
431 crate_name: env!("CARGO_PKG_NAME"),
432 arity: 4,
433 install: install_fidelity_badge_citizen,
434 conformance: conformance_fidelity_badge_citizen,
435 }
436}
437
438fn class_value_or_stub(cx: &mut Cx, id: ClassId, symbol: Symbol) -> Result<Value> {
439 if let Some(value) = cx.registry().class_by_symbol(&symbol) {
440 return Ok(value.clone());
441 }
442 cx.factory().class_stub(id, symbol)
443}