sim_lib_numbers_tensor/implementation/
domain.rs1use std::sync::Arc;
5
6use sim_kernel::{
7 AbiVersion, DefaultFactory, Dependency, Export, Expr, Factory, Lib, LibManifest, LibTarget,
8 Linker, NumberDomain, Object, Result, Symbol, Value, Version,
9};
10use sim_lib_numbers_core::{
11 DomainNumberValueShape, NumberDomainTableSpec, domains, number_domain_table,
12};
13use sim_shape::shape_value;
14
15use super::{
16 citizen::{register_tensor_value_class, tensor_value_class_symbol},
17 function::{
18 TensorFunction, index_symbol, map_symbol, mat_symbol, reshape_symbol, scalar_symbol,
19 slice_symbol, tensor_symbol, vec_symbol,
20 },
21};
22
23pub fn number_domain() -> Symbol {
25 domains::tensor()
26}
27
28fn literal_class_symbol() -> Symbol {
29 domains::literal_class("tensor")
30}
31
32fn literal_instance_shape_symbol() -> Symbol {
33 Symbol::qualified(literal_class_symbol().to_string(), "instance-shape")
34}
35
36fn value_shape_symbol() -> Symbol {
37 sim_lib_numbers_core::value_shape_symbol(&number_domain())
38}
39
40#[sim_citizen_derive::non_citizen(
41 reason = "numbers/tensor number-domain marker; reconstruct by loading the tensor number lib",
42 kind = "marker"
43)]
44struct TensorNumberDomain;
45
46impl NumberDomain for TensorNumberDomain {
47 fn symbol(&self) -> Symbol {
48 number_domain()
49 }
50
51 fn parse_priority(&self) -> i32 {
52 -200
53 }
54
55 fn parse_literal(&self, _cx: &mut sim_kernel::Cx, _text: &str) -> Result<Option<Value>> {
56 Ok(None)
57 }
58
59 fn encode_literal(
60 &self,
61 _cx: &mut sim_kernel::Cx,
62 _value: Value,
63 ) -> Result<Option<sim_kernel::NumberLiteral>> {
64 Ok(None)
65 }
66}
67
68impl Object for TensorNumberDomain {
69 fn display(&self, _cx: &mut sim_kernel::Cx) -> Result<String> {
70 Ok("#<number-domain numbers/tensor>".to_owned())
71 }
72
73 fn as_any(&self) -> &dyn std::any::Any {
74 self
75 }
76}
77
78impl sim_kernel::ObjectCompat for TensorNumberDomain {
79 fn class(&self, cx: &mut sim_kernel::Cx) -> Result<sim_kernel::ClassRef> {
80 sim_lib_numbers_core::number_domain_class_stub(cx)
81 }
82 fn as_expr(&self, _cx: &mut sim_kernel::Cx) -> Result<Expr> {
83 Ok(Expr::Symbol(number_domain()))
84 }
85 fn as_table(&self, cx: &mut sim_kernel::Cx) -> Result<Value> {
86 let literal_class = cx
87 .registry()
88 .class_by_symbol(&literal_class_symbol())
89 .cloned()
90 .unwrap_or(cx.factory().symbol(literal_class_symbol())?);
91 let instance_shape = cx
92 .registry()
93 .shape_by_symbol(&literal_instance_shape_symbol())
94 .cloned()
95 .unwrap_or(cx.factory().symbol(literal_instance_shape_symbol())?);
96 let value_shape = cx
97 .registry()
98 .shape_by_symbol(&value_shape_symbol())
99 .cloned()
100 .unwrap_or(cx.factory().symbol(value_shape_symbol())?);
101 number_domain_table(
102 cx,
103 NumberDomainTableSpec::new(
104 number_domain(),
105 "tensor",
106 "value-only",
107 -200,
108 literal_class,
109 instance_shape,
110 value_shape,
111 ),
112 )
113 }
114 fn as_number_domain(&self) -> Option<&dyn NumberDomain> {
115 Some(self)
116 }
117}
118
119struct TensorLiteralShape;
120
121impl sim_shape::Shape for TensorLiteralShape {
122 fn check_value(
123 &self,
124 _cx: &mut sim_kernel::Cx,
125 _value: Value,
126 ) -> Result<sim_shape::ShapeMatch> {
127 Ok(sim_shape::ShapeMatch::reject(
128 "numbers/tensor has no parsed literal surface".to_owned(),
129 ))
130 }
131
132 fn check_expr(&self, _cx: &mut sim_kernel::Cx, _expr: &Expr) -> Result<sim_shape::ShapeMatch> {
133 Ok(sim_shape::ShapeMatch::reject(
134 "numbers/tensor has no parsed literal surface".to_owned(),
135 ))
136 }
137
138 fn describe(&self, _cx: &mut sim_kernel::Cx) -> Result<sim_shape::ShapeDoc> {
139 Ok(sim_shape::ShapeDoc::new("TensorLiteral")
140 .with_detail("placeholder literal shape for the numbers/tensor domain")
141 .with_detail("tensor values are constructed by functions rather than parsed literals"))
142 }
143}
144
145#[sim_citizen_derive::non_citizen(
146 reason = "numbers/tensor literal class marker; tensor values use the numbers/Tensor citizen descriptor",
147 kind = "marker"
148)]
149struct TensorLiteralClass;
150
151impl Object for TensorLiteralClass {
152 fn display(&self, _cx: &mut sim_kernel::Cx) -> Result<String> {
153 Ok(format!("#<class {}>", literal_class_symbol()))
154 }
155
156 fn as_any(&self) -> &dyn std::any::Any {
157 self
158 }
159}
160
161impl sim_kernel::ObjectCompat for TensorLiteralClass {
162 fn class(&self, cx: &mut sim_kernel::Cx) -> Result<sim_kernel::ClassRef> {
163 if let Some(value) = cx
164 .registry()
165 .class_by_symbol(&Symbol::qualified("core", "Class"))
166 {
167 return Ok(value.clone());
168 }
169 DefaultFactory.class_stub(
170 sim_kernel::CORE_CLASS_CLASS_ID,
171 Symbol::qualified("core", "Class"),
172 )
173 }
174 fn as_expr(&self, _cx: &mut sim_kernel::Cx) -> Result<Expr> {
175 Ok(Expr::Symbol(literal_class_symbol()))
176 }
177}
178
179pub struct TensorNumbersLib;
187
188impl TensorNumbersLib {
189 pub fn new() -> Self {
193 Self
194 }
195}
196
197impl Default for TensorNumbersLib {
198 fn default() -> Self {
199 Self::new()
200 }
201}
202
203impl Lib for TensorNumbersLib {
204 fn manifest(&self) -> LibManifest {
205 LibManifest {
206 id: number_domain(),
207 version: Version(env!("CARGO_PKG_VERSION").to_owned()),
208 abi: AbiVersion { major: 0, minor: 1 },
209 target: LibTarget::HostRegistered,
210 requires: Vec::<Dependency>::new(),
211 capabilities: Vec::new(),
212 exports: vec![
213 Export::NumberDomain {
214 symbol: number_domain(),
215 number_domain_id: None,
216 },
217 Export::Class {
218 symbol: literal_class_symbol(),
219 class_id: None,
220 },
221 Export::Class {
222 symbol: tensor_value_class_symbol(),
223 class_id: None,
224 },
225 Export::Shape {
226 symbol: literal_instance_shape_symbol(),
227 shape_id: None,
228 },
229 Export::Shape {
230 symbol: value_shape_symbol(),
231 shape_id: None,
232 },
233 export_function(tensor_symbol()),
234 export_function(scalar_symbol()),
235 export_function(vec_symbol()),
236 export_function(mat_symbol()),
237 export_function(index_symbol()),
238 export_function(reshape_symbol()),
239 export_function(slice_symbol()),
240 export_function(map_symbol()),
241 ],
242 }
243 }
244
245 fn load(&self, _cx: &mut sim_kernel::LoadCx, linker: &mut Linker<'_>) -> Result<()> {
246 linker.number_domain_value(
247 number_domain(),
248 DefaultFactory
249 .opaque(Arc::new(TensorNumberDomain))
250 .expect("tensor domain should be boxable"),
251 )?;
252 linker.class_value(
253 literal_class_symbol(),
254 DefaultFactory
255 .opaque(Arc::new(TensorLiteralClass))
256 .expect("tensor literal class should be boxable"),
257 )?;
258 register_tensor_value_class(linker)?;
259 linker.shape_value(
260 literal_instance_shape_symbol(),
261 shape_value(
262 literal_instance_shape_symbol(),
263 Arc::new(TensorLiteralShape),
264 ),
265 )?;
266 linker.shape_value(
267 value_shape_symbol(),
268 shape_value(
269 value_shape_symbol(),
270 Arc::new(DomainNumberValueShape::new(
271 number_domain(),
272 "TensorValue",
273 [
274 "number value in the numbers/tensor domain",
275 "accepts tensor-shaped collections of scalar number cells",
276 ],
277 )),
278 ),
279 )?;
280
281 for symbol in [
282 tensor_symbol(),
283 scalar_symbol(),
284 vec_symbol(),
285 mat_symbol(),
286 index_symbol(),
287 reshape_symbol(),
288 slice_symbol(),
289 map_symbol(),
290 ] {
291 linker.function_value(
292 symbol.clone(),
293 DefaultFactory
294 .opaque(Arc::new(TensorFunction { symbol }))
295 .expect("tensor function should be boxable"),
296 )?;
297 }
298 Ok(())
299 }
300}
301
302fn export_function(symbol: Symbol) -> Export {
303 Export::Function {
304 symbol,
305 function_id: None,
306 }
307}