sim_lib_numbers_complex/implementation/
value.rs1use std::sync::Arc;
6use std::sync::atomic::{AtomicU32, Ordering};
7
8use sim_citizen::{CitizenField, arity_error, decode_version};
9use sim_kernel::{
10 Args, Callable, Class, ClassId, ClassRef, Cx, DefaultFactory, Error, Expr, Factory,
11 NumberLiteral, NumberValue, Object, ObjectEncode, ObjectEncoding, ReadConstructor,
12 ReadConstructorRef, Result, ShapeRef, Symbol, TableRef, Value,
13};
14use sim_lib_numbers_core::domains;
15
16use super::literal::{number_domain, value_shape_symbol};
17use super::ops::canonical_complex;
18
19pub fn complex_value_class_symbol() -> Symbol {
22 domains::complex_value_class()
23}
24
25#[derive(Clone, Debug, PartialEq)]
27pub struct ComplexValue {
28 real: f64,
30 imag: f64,
32}
33
34impl ComplexValue {
35 pub fn new(real: f64, imag: f64) -> Self {
37 Self { real, imag }
38 }
39
40 fn literal(&self) -> NumberLiteral {
41 NumberLiteral {
42 domain: number_domain(),
43 canonical: canonical_complex(self.real, self.imag),
44 }
45 }
46}
47
48impl Object for ComplexValue {
49 fn display(&self, _cx: &mut Cx) -> Result<String> {
50 Ok(self.literal().canonical)
51 }
52
53 fn as_any(&self) -> &dyn std::any::Any {
54 self
55 }
56}
57
58impl sim_kernel::ObjectCompat for ComplexValue {
59 fn class(&self, cx: &mut Cx) -> Result<ClassRef> {
60 if let Some(value) = cx.registry().class_by_symbol(&complex_value_class_symbol()) {
61 return Ok(value.clone());
62 }
63 DefaultFactory.class_stub(
64 sim_kernel::CORE_NUMBER_CLASS_ID,
65 Symbol::qualified("core", "Number"),
66 )
67 }
68
69 fn as_expr(&self, _cx: &mut Cx) -> Result<Expr> {
70 Ok(Expr::Number(self.literal()))
71 }
72
73 fn as_table(&self, cx: &mut Cx) -> Result<Value> {
74 cx.factory().table(vec![
75 (
76 Symbol::new("kind"),
77 cx.factory().string("complex".to_owned())?,
78 ),
79 (Symbol::new("domain"), cx.factory().symbol(number_domain())?),
80 (
81 Symbol::new("real"),
82 cx.factory()
83 .number_literal(domains::f64(), self.real.to_string())?,
84 ),
85 (
86 Symbol::new("imag"),
87 cx.factory()
88 .number_literal(domains::f64(), self.imag.to_string())?,
89 ),
90 ])
91 }
92
93 fn as_number_value(&self) -> Option<&dyn NumberValue> {
94 Some(self)
95 }
96
97 fn as_object_encoder(&self) -> Option<&dyn ObjectEncode> {
98 Some(self)
99 }
100}
101
102impl NumberValue for ComplexValue {
103 fn number_domain(&self, _cx: &mut Cx) -> Result<Symbol> {
104 Ok(number_domain())
105 }
106
107 fn number_literal(&self, _cx: &mut Cx) -> Result<Option<NumberLiteral>> {
108 Ok(Some(self.literal()))
109 }
110}
111
112impl ObjectEncode for ComplexValue {
113 fn object_encoding(&self, _cx: &mut Cx) -> Result<ObjectEncoding> {
114 Ok(ObjectEncoding::Constructor {
115 class: complex_value_class_symbol(),
116 args: vec![
117 Expr::Symbol(Symbol::new("v1")),
118 self.real.encode_field(),
119 self.imag.encode_field(),
120 ],
121 })
122 }
123}
124
125impl sim_citizen::Citizen for ComplexValue {
126 fn citizen_symbol() -> Symbol {
127 complex_value_class_symbol()
128 }
129
130 fn citizen_version() -> u32 {
131 1
132 }
133
134 fn citizen_arity() -> usize {
135 2
136 }
137
138 fn citizen_fields() -> &'static [&'static str] {
139 &["real", "imag"]
140 }
141}
142
143pub(crate) struct ComplexValueClass {
144 id: AtomicU32,
145}
146
147pub(crate) fn build_complex_value_class() -> Arc<ComplexValueClass> {
148 Arc::new(ComplexValueClass {
149 id: AtomicU32::new(0),
150 })
151}
152
153impl ComplexValueClass {
154 pub(crate) fn set_id(&self, id: ClassId) {
155 self.id.store(id.0, Ordering::Relaxed);
156 }
157}
158
159impl Object for ComplexValueClass {
160 fn display(&self, _cx: &mut Cx) -> Result<String> {
161 Ok(format!("#<class {}>", complex_value_class_symbol()))
162 }
163
164 fn as_any(&self) -> &dyn std::any::Any {
165 self
166 }
167}
168
169impl sim_kernel::ObjectCompat for ComplexValueClass {
170 fn class(&self, cx: &mut Cx) -> Result<ClassRef> {
171 if let Some(value) = cx
172 .registry()
173 .class_by_symbol(&Symbol::qualified("core", "Class"))
174 {
175 return Ok(value.clone());
176 }
177 DefaultFactory.class_stub(
178 sim_kernel::CORE_CLASS_CLASS_ID,
179 Symbol::qualified("core", "Class"),
180 )
181 }
182
183 fn as_expr(&self, _cx: &mut Cx) -> Result<Expr> {
184 Ok(Expr::Symbol(complex_value_class_symbol()))
185 }
186
187 fn as_callable(&self) -> Option<&dyn Callable> {
188 Some(self)
189 }
190
191 fn as_class(&self) -> Option<&dyn Class> {
192 Some(self)
193 }
194
195 fn as_read_constructor(&self) -> Option<&dyn ReadConstructor> {
196 Some(self)
197 }
198}
199
200impl Callable for ComplexValueClass {
201 fn call(&self, cx: &mut Cx, args: Args) -> Result<Value> {
202 let values = args.into_vec();
203 let [version, real, imag] = values.as_slice() else {
204 return Err(arity_error(complex_value_class_symbol(), 3, values.len()));
205 };
206 decode_version(cx, version.clone(), 1, complex_value_class_symbol())?;
207 let real = f64::decode_field_value(cx, real.clone(), "real")?;
208 let imag = f64::decode_field_value(cx, imag.clone(), "imag")?;
209 complex_value(cx, real, imag)
210 }
211}
212
213impl Class for ComplexValueClass {
214 fn id(&self) -> ClassId {
215 ClassId(self.id.load(Ordering::Relaxed))
216 }
217
218 fn symbol(&self) -> Symbol {
219 complex_value_class_symbol()
220 }
221
222 fn constructor_shape(&self, cx: &mut Cx) -> Result<ShapeRef> {
223 cx.factory().nil()
224 }
225
226 fn instance_shape(&self, cx: &mut Cx) -> Result<ShapeRef> {
227 Ok(cx
228 .registry()
229 .shape_by_symbol(&value_shape_symbol())
230 .cloned()
231 .unwrap_or(cx.factory().symbol(value_shape_symbol())?))
232 }
233
234 fn read_constructor(&self, cx: &mut Cx) -> Result<Option<ReadConstructorRef>> {
235 Ok(cx
236 .registry()
237 .class_by_symbol(&complex_value_class_symbol())
238 .cloned())
239 }
240
241 fn members(&self, cx: &mut Cx) -> Result<TableRef> {
242 cx.factory().table(vec![
243 (
244 Symbol::new("version"),
245 cx.factory()
246 .number_literal(Symbol::qualified("citizen", "int"), "1".to_owned())?,
247 ),
248 (
249 Symbol::new("fields"),
250 cx.factory().list(vec![
251 cx.factory().symbol(Symbol::new("real"))?,
252 cx.factory().symbol(Symbol::new("imag"))?,
253 ])?,
254 ),
255 ])
256 }
257}
258
259impl ReadConstructor for ComplexValueClass {
260 fn symbol(&self) -> Symbol {
261 complex_value_class_symbol()
262 }
263
264 fn args_shape(&self, cx: &mut Cx) -> Result<ShapeRef> {
265 cx.factory().nil()
266 }
267
268 fn construct_read(&self, cx: &mut Cx, args: Vec<Value>) -> Result<Value> {
269 if args.len() != 3 {
270 return Err(arity_error(complex_value_class_symbol(), 3, args.len()));
271 }
272 self.call(cx, Args::new(args))
273 }
274}
275
276pub fn complex_value(cx: &mut Cx, real: f64, imag: f64) -> Result<Value> {
279 if !real.is_finite() || !imag.is_finite() {
280 return Err(Error::Eval(
281 "numbers/Complex constructor requires finite f64 parts".to_owned(),
282 ));
283 }
284 cx.factory().opaque(Arc::new(ComplexValue::new(real, imag)))
285}