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