1use std::sync::Arc;
24
25#[crate::polydat_node(category = Conversions)]
30fn __u64_to_u128(n: u64) -> u128 {
31 n as u128
32}
33
34#[crate::polydat_node(category = Conversions)]
35fn __u64_to_i128(n: u64) -> i128 {
36 n as i128
37}
38
39#[crate::polydat_node(category = Conversions)]
40fn __i64_to_i128(n: i64) -> i128 {
41 n as i128
42}
43
44#[crate::polydat_node(category = Conversions)]
45fn __u128_to_f64(n: u128) -> f64 {
46 n as f64
47}
48
49#[crate::polydat_node(category = Conversions)]
50fn __i128_to_f64(n: i128) -> f64 {
51 n as f64
52}
53
54#[crate::polydat_node(category = Conversions)]
60fn __u8_to_u128(n: u8) -> u128 {
61 n as u128
62}
63
64#[crate::polydat_node(category = Conversions)]
65fn __u8_to_i128(n: u8) -> i128 {
66 n as i128
67}
68
69#[crate::polydat_node(category = Conversions)]
70fn __u16_to_u128(n: u16) -> u128 {
71 n as u128
72}
73
74#[crate::polydat_node(category = Conversions)]
75fn __u16_to_i128(n: u16) -> i128 {
76 n as i128
77}
78
79#[crate::polydat_node(category = Conversions)]
80fn __u32_to_u128(n: u32) -> u128 {
81 n as u128
82}
83
84#[crate::polydat_node(category = Conversions)]
85fn __u32_to_i128(n: u32) -> i128 {
86 n as i128
87}
88
89#[crate::polydat_node(category = Conversions)]
90fn __i8_to_i128(n: i8) -> i128 {
91 n as i128
92}
93
94#[crate::polydat_node(category = Conversions)]
95fn __i16_to_i128(n: i16) -> i128 {
96 n as i128
97}
98
99#[crate::polydat_node(category = Conversions)]
100fn __i32_to_i128(n: i32) -> i128 {
101 n as i128
102}
103
104#[crate::polydat_node(category = Conversions)]
105fn __bool_to_u128(b: bool) -> u128 {
106 b as u128
107}
108
109#[crate::polydat_node(category = Conversions)]
110fn __bool_to_i128(b: bool) -> i128 {
111 b as i128
112}
113
114#[crate::polydat_node(category = Conversions)]
115fn __u128_to_bool(n: u128) -> bool {
116 n != 0
117}
118
119#[crate::polydat_node(category = Conversions)]
120fn __i128_to_bool(n: i128) -> bool {
121 n != 0
122}
123
124#[crate::polydat_node(category = Conversions)]
129fn __u128_to_u64(n: u128) -> u64 {
130 if n > u64::MAX as u128 {
131 panic!("__u128_to_u64: value {n} exceeds u64::MAX ({})", u64::MAX);
132 }
133 n as u64
134}
135
136#[crate::polydat_node(category = Conversions)]
137fn __i128_to_i64(n: i128) -> i64 {
138 if n < i64::MIN as i128 || n > i64::MAX as i128 {
139 panic!(
140 "__i128_to_i64: value {n} out of i64 range [{}, {}]",
141 i64::MIN,
142 i64::MAX
143 );
144 }
145 n as i64
146}
147
148#[crate::polydat_node(category = Conversions)]
149fn __i64_to_u128(n: i64) -> u128 {
150 if n < 0 {
151 panic!("__i64_to_u128: negative value {n} cannot be represented as u128");
152 }
153 n as u128
154}
155
156#[crate::polydat_node(category = Conversions)]
157fn __u128_to_i128(n: u128) -> i128 {
158 if n > i128::MAX as u128 {
159 panic!(
160 "__u128_to_i128: value {n} exceeds i128::MAX ({})",
161 i128::MAX
162 );
163 }
164 n as i128
165}
166
167#[crate::polydat_node(category = Conversions)]
168fn __i128_to_u128(n: i128) -> u128 {
169 if n < 0 {
170 panic!("__i128_to_u128: negative value {n} cannot be represented as u128");
171 }
172 n as u128
173}
174
175#[crate::polydat_node(category = Conversions)]
176fn __f64_to_u128(f: f64) -> u128 {
177 if !f.is_finite() {
178 panic!("__f64_to_u128: non-finite value {f} cannot be represented as u128");
179 }
180 let n = f.trunc();
181 if n < 0.0 || n > u128::MAX as f64 {
182 panic!("__f64_to_u128: value {f} out of u128 range");
183 }
184 n as u128
185}
186
187#[crate::polydat_node(category = Conversions)]
188fn __f64_to_i128(f: f64) -> i128 {
189 if !f.is_finite() {
190 panic!("__f64_to_i128: non-finite value {f} cannot be represented as i128");
191 }
192 let n = f.trunc();
193 if n < i128::MIN as f64 || n > i128::MAX as f64 {
194 panic!("__f64_to_i128: value {f} out of i128 range");
195 }
196 n as i128
197}
198
199#[crate::polydat_node(category = Conversions)]
204fn __u128_to_string(n: u128) -> String {
205 n.to_string()
206}
207
208#[crate::polydat_node(category = Conversions)]
209fn __i128_to_string(n: i128) -> String {
210 n.to_string()
211}
212
213#[crate::polydat_node(category = Conversions)]
214fn __str_to_u128(input: &str) -> u128 {
215 let raw = input.trim();
216 raw.parse::<u128>()
217 .unwrap_or_else(|e| panic!("__str_to_u128: cannot parse {raw:?} as u128: {e}"))
218}
219
220#[crate::polydat_node(category = Conversions)]
221fn __str_to_i128(input: &str) -> i128 {
222 let raw = input.trim();
223 raw.parse::<i128>()
224 .unwrap_or_else(|e| panic!("__str_to_i128: cannot parse {raw:?} as i128: {e}"))
225}
226
227#[crate::polydat_node(category = Conversions)]
232fn __u128_to_bytes(n: u128) -> Vec<u8> {
233 n.to_le_bytes().to_vec()
234}
235
236#[crate::polydat_node(category = Conversions)]
237fn __i128_to_bytes(n: i128) -> Vec<u8> {
238 n.to_le_bytes().to_vec()
239}
240
241#[crate::polydat_node(category = Conversions)]
242fn __bytes_to_u128(b: &[u8]) -> u128 {
243 if b.len() != 16 {
244 panic!(
245 "__bytes_to_u128: expected exactly 16 bytes for u128, got {}",
246 b.len()
247 );
248 }
249 u128::from_le_bytes(b.try_into().unwrap())
250}
251
252#[crate::polydat_node(category = Conversions)]
253fn __bytes_to_i128(b: &[u8]) -> i128 {
254 if b.len() != 16 {
255 panic!(
256 "__bytes_to_i128: expected exactly 16 bytes for i128, got {}",
257 b.len()
258 );
259 }
260 i128::from_le_bytes(b.try_into().unwrap())
261}
262
263#[crate::polydat_node(category = Conversions)]
269fn __u128_to_json(n: u128) -> Arc<serde_json::Value> {
270 Arc::new(serde_json::Value::String(n.to_string()))
271}
272
273#[crate::polydat_node(category = Conversions)]
274fn __i128_to_json(n: i128) -> Arc<serde_json::Value> {
275 Arc::new(serde_json::Value::String(n.to_string()))
276}
277
278#[crate::polydat_node(category = Conversions)]
279fn __json_to_u128(j: &serde_json::Value) -> u128 {
280 match j {
281 serde_json::Value::String(s) => s
282 .trim()
283 .parse::<u128>()
284 .unwrap_or_else(|e| panic!("__json_to_u128: cannot parse {s:?} as u128: {e}")),
285 serde_json::Value::Number(n) => n
286 .as_u64()
287 .map(|u| u as u128)
288 .unwrap_or_else(|| panic!("__json_to_u128: JSON number {n} is not a u64")),
289 other => panic!("__json_to_u128: JSON value {other} is not a string or number"),
290 }
291}
292
293#[crate::polydat_node(category = Conversions)]
294fn __json_to_i128(j: &serde_json::Value) -> i128 {
295 match j {
296 serde_json::Value::String(s) => s
297 .trim()
298 .parse::<i128>()
299 .unwrap_or_else(|e| panic!("__json_to_i128: cannot parse {s:?} as i128: {e}")),
300 serde_json::Value::Number(n) => n
301 .as_i64()
302 .map(|i| i as i128)
303 .or_else(|| n.as_u64().map(|u| u as i128))
304 .unwrap_or_else(|| panic!("__json_to_i128: JSON number {n} is not an integer")),
305 other => panic!("__json_to_i128: JSON value {other} is not a string or number"),
306 }
307}
308
309#[cfg(test)]
314mod tests {
315 use super::*;
316 use crate::ast::{Bits128, PolydatNode, Value};
317
318 fn u128v(v: u128) -> Value {
319 Value::U128(Bits128::from_u128(v))
320 }
321 fn i128v(v: i128) -> Value {
322 Value::I128(Bits128::from_i128(v))
323 }
324
325 fn check<N: PolydatNode>(node: &N, input: Value, expected: Value) {
326 let mut out = [Value::None];
327 node.eval(&[input], &mut out);
328 assert_eq!(
329 out[0],
330 expected,
331 "{} produced wrong output",
332 node.meta().name
333 );
334 }
335
336 fn check_panics<N: PolydatNode>(node: &N, input: Value, msg_substring: &str) {
337 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
338 let mut out = [Value::None];
339 node.eval(&[input], &mut out);
340 }));
341 match result {
342 Ok(_) => panic!("{} did not panic as expected", node.meta().name),
343 Err(payload) => {
344 let s = payload
345 .downcast_ref::<String>()
346 .cloned()
347 .or_else(|| payload.downcast_ref::<&str>().map(|s| s.to_string()))
348 .unwrap_or_default();
349 assert!(
350 s.contains(msg_substring),
351 "{} panicked but message didn't contain {msg_substring:?}: {s}",
352 node.meta().name
353 );
354 }
355 }
356 }
357
358 const BIG: u128 = 0xDEAD_BEEF_CAFE_BABE_0123_4567_89AB_CDEF;
359
360 #[test]
361 fn limb_round_trip_preserves_all_bits() {
362 assert_eq!(Bits128::from_u128(BIG).as_u128(), BIG);
363 assert_eq!(Bits128::from_i128(-1).as_i128(), -1);
364 assert_eq!(Bits128::from_i128(i128::MIN).as_i128(), i128::MIN);
365 }
366
367 #[test]
368 fn widenings_and_narrowings() {
369 check(
370 &U64ToU128::new(),
371 Value::U64(u64::MAX),
372 u128v(u64::MAX as u128),
373 );
374 check(
375 &U64ToI128::new(),
376 Value::U64(u64::MAX),
377 i128v(u64::MAX as i128),
378 );
379 check(&I64ToI128::new(), Value::I64(-5), i128v(-5));
380 check(&U128ToU64::new(), u128v(42), Value::U64(42));
381 check_panics(
382 &U128ToU64::new(),
383 u128v(u64::MAX as u128 + 1),
384 "exceeds u64::MAX",
385 );
386 check(&I128ToI64::new(), i128v(-5), Value::I64(-5));
387 check_panics(
388 &I128ToI64::new(),
389 i128v(i64::MAX as i128 + 1),
390 "out of i64 range",
391 );
392 check_panics(&I64ToU128::new(), Value::I64(-1), "negative");
393 check_panics(&I128ToU128::new(), i128v(-1), "negative");
394 check(&U128ToI128::new(), u128v(42), i128v(42));
395 }
396
397 #[test]
398 fn string_and_json_round_trip() {
399 check(
400 &U128ToString::new(),
401 u128v(BIG),
402 Value::Str(BIG.to_string().into()),
403 );
404 check(
405 &StrToU128::new(),
406 Value::Str(BIG.to_string().into()),
407 u128v(BIG),
408 );
409 check(&I128ToString::new(), i128v(-7), Value::Str("-7".into()));
410 check(&StrToI128::new(), Value::Str(" -7 ".into()), i128v(-7));
411 check(
413 &U128ToJson::new(),
414 u128v(BIG),
415 Value::Json(Arc::new(serde_json::Value::String(BIG.to_string()))),
416 );
417 check(
418 &JsonToU128::new(),
419 Value::Json(Arc::new(serde_json::Value::String(BIG.to_string()))),
420 u128v(BIG),
421 );
422 check(
424 &JsonToI128::new(),
425 Value::Json(Arc::new(serde_json::Value::from(-5_i64))),
426 i128v(-5),
427 );
428 }
429
430 #[test]
431 fn bytes_round_trip() {
432 let bytes = BIG.to_le_bytes().to_vec();
433 check(
434 &U128ToBytes::new(),
435 u128v(BIG),
436 Value::Bytes(bytes.clone().into()),
437 );
438 check(&BytesToU128::new(), Value::Bytes(bytes.into()), u128v(BIG));
439 check_panics(
440 &BytesToU128::new(),
441 Value::Bytes(vec![0; 8].into()),
442 "expected exactly 16 bytes",
443 );
444 }
445
446 #[test]
447 fn display_and_json_projection_render_signed() {
448 assert_eq!(i128v(-5).to_display_string(), "-5");
451 assert_eq!(
452 i128v(-5).to_json_value(),
453 serde_json::Value::String("-5".to_string())
454 );
455 assert_eq!(u128v(BIG).to_display_string(), BIG.to_string());
456 }
457}