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