use std::sync::Arc;
#[crate::polydat_node(category = Conversions)]
fn __u8_to_u64(n: u8) -> u64 { n as u64 }
#[crate::polydat_node(category = Conversions)]
fn __u8_to_u32(n: u8) -> u32 { n as u32 }
#[crate::polydat_node(category = Conversions)]
fn __u8_to_u16(n: u8) -> u16 { n as u16 }
#[crate::polydat_node(category = Conversions)]
fn __u8_to_f64(n: u8) -> f64 { n as f64 }
#[crate::polydat_node(category = Conversions)]
fn __u16_to_u64(n: u16) -> u64 { n as u64 }
#[crate::polydat_node(category = Conversions)]
fn __u16_to_u32(n: u16) -> u32 { n as u32 }
#[crate::polydat_node(category = Conversions)]
fn __u16_to_f64(n: u16) -> f64 { n as f64 }
#[crate::polydat_node(category = Conversions)]
fn __i8_to_i64(n: i8) -> i64 { n as i64 }
#[crate::polydat_node(category = Conversions)]
fn __i8_to_i32(n: i8) -> i32 { n as i32 }
#[crate::polydat_node(category = Conversions)]
fn __i8_to_i16(n: i8) -> i16 { n as i16 }
#[crate::polydat_node(category = Conversions)]
fn __i8_to_f64(n: i8) -> f64 { n as f64 }
#[crate::polydat_node(category = Conversions)]
fn __i16_to_i64(n: i16) -> i64 { n as i64 }
#[crate::polydat_node(category = Conversions)]
fn __i16_to_i32(n: i16) -> i32 { n as i32 }
#[crate::polydat_node(category = Conversions)]
fn __i16_to_f64(n: i16) -> f64 { n as f64 }
#[crate::polydat_node(category = Conversions)]
fn __f16_to_f32(f: half::f16) -> f32 { f.to_f32() }
#[crate::polydat_node(category = Conversions)]
fn __f16_to_f64(f: half::f16) -> f64 { f.to_f64() }
#[crate::polydat_node(category = Conversions)]
fn __u8_to_i16(n: u8) -> i16 { n as i16 }
#[crate::polydat_node(category = Conversions)]
fn __u8_to_i32(n: u8) -> i32 { n as i32 }
#[crate::polydat_node(category = Conversions)]
fn __u8_to_i64(n: u8) -> i64 { n as i64 }
#[crate::polydat_node(category = Conversions)]
fn __u8_to_f32(n: u8) -> f32 { n as f32 }
#[crate::polydat_node(category = Conversions)]
fn __u16_to_i32(n: u16) -> i32 { n as i32 }
#[crate::polydat_node(category = Conversions)]
fn __u16_to_i64(n: u16) -> i64 { n as i64 }
#[crate::polydat_node(category = Conversions)]
fn __u16_to_f32(n: u16) -> f32 { n as f32 }
#[crate::polydat_node(category = Conversions)]
fn __i8_to_f32(n: i8) -> f32 { n as f32 }
#[crate::polydat_node(category = Conversions)]
fn __i16_to_f32(n: i16) -> f32 { n as f32 }
#[crate::polydat_node(category = Conversions)]
fn __u8_to_f16(n: u8) -> half::f16 { half::f16::from_f32(n as f32) }
#[crate::polydat_node(category = Conversions)]
fn __i8_to_f16(n: i8) -> half::f16 { half::f16::from_f32(n as f32) }
#[crate::polydat_node(category = Conversions)]
fn __u64_to_u8(n: u64) -> u8 {
if n > u8::MAX as u64 {
panic!("__u64_to_u8: value {n} exceeds u8::MAX ({})", u8::MAX);
}
n as u8
}
#[crate::polydat_node(category = Conversions)]
fn __u32_to_u8(n: u32) -> u8 {
if n > u8::MAX as u32 {
panic!("__u32_to_u8: value {n} exceeds u8::MAX ({})", u8::MAX);
}
n as u8
}
#[crate::polydat_node(category = Conversions)]
fn __u16_to_u8(n: u16) -> u8 {
if n > u8::MAX as u16 {
panic!("__u16_to_u8: value {n} exceeds u8::MAX ({})", u8::MAX);
}
n as u8
}
#[crate::polydat_node(category = Conversions)]
fn __i64_to_u8(n: i64) -> u8 {
if n < 0 || n > u8::MAX as i64 {
panic!("__i64_to_u8: value {n} out of u8 range [0, {}]", u8::MAX);
}
n as u8
}
#[crate::polydat_node(category = Conversions)]
fn __f64_to_u8(f: f64) -> u8 {
if !f.is_finite() {
panic!("__f64_to_u8: non-finite value {f} cannot be represented as u8");
}
let n = f.trunc();
if n < 0.0 || n > u8::MAX as f64 {
panic!("__f64_to_u8: value {f} out of u8 range [0, {}]", u8::MAX);
}
n as u8
}
#[crate::polydat_node(category = Conversions)]
fn __u64_to_u16(n: u64) -> u16 {
if n > u16::MAX as u64 {
panic!("__u64_to_u16: value {n} exceeds u16::MAX ({})", u16::MAX);
}
n as u16
}
#[crate::polydat_node(category = Conversions)]
fn __u32_to_u16(n: u32) -> u16 {
if n > u16::MAX as u32 {
panic!("__u32_to_u16: value {n} exceeds u16::MAX ({})", u16::MAX);
}
n as u16
}
#[crate::polydat_node(category = Conversions)]
fn __i64_to_u16(n: i64) -> u16 {
if n < 0 || n > u16::MAX as i64 {
panic!("__i64_to_u16: value {n} out of u16 range [0, {}]", u16::MAX);
}
n as u16
}
#[crate::polydat_node(category = Conversions)]
fn __f64_to_u16(f: f64) -> u16 {
if !f.is_finite() {
panic!("__f64_to_u16: non-finite value {f} cannot be represented as u16");
}
let n = f.trunc();
if n < 0.0 || n > u16::MAX as f64 {
panic!("__f64_to_u16: value {f} out of u16 range [0, {}]", u16::MAX);
}
n as u16
}
#[crate::polydat_node(category = Conversions)]
fn __i64_to_i8(n: i64) -> i8 {
if n < i8::MIN as i64 || n > i8::MAX as i64 {
panic!("__i64_to_i8: value {n} out of i8 range [{}, {}]", i8::MIN, i8::MAX);
}
n as i8
}
#[crate::polydat_node(category = Conversions)]
fn __i32_to_i8(n: i32) -> i8 {
if n < i8::MIN as i32 || n > i8::MAX as i32 {
panic!("__i32_to_i8: value {n} out of i8 range [{}, {}]", i8::MIN, i8::MAX);
}
n as i8
}
#[crate::polydat_node(category = Conversions)]
fn __u64_to_i8(n: u64) -> i8 {
if n > i8::MAX as u64 {
panic!("__u64_to_i8: value {n} exceeds i8::MAX ({})", i8::MAX);
}
n as i8
}
#[crate::polydat_node(category = Conversions)]
fn __f64_to_i8(f: f64) -> i8 {
if !f.is_finite() {
panic!("__f64_to_i8: non-finite value {f} cannot be represented as i8");
}
let n = f.trunc();
if n < i8::MIN as f64 || n > i8::MAX as f64 {
panic!("__f64_to_i8: value {f} out of i8 range [{}, {}]", i8::MIN, i8::MAX);
}
n as i8
}
#[crate::polydat_node(category = Conversions)]
fn __i64_to_i16(n: i64) -> i16 {
if n < i16::MIN as i64 || n > i16::MAX as i64 {
panic!("__i64_to_i16: value {n} out of i16 range [{}, {}]", i16::MIN, i16::MAX);
}
n as i16
}
#[crate::polydat_node(category = Conversions)]
fn __i32_to_i16(n: i32) -> i16 {
if n < i16::MIN as i32 || n > i16::MAX as i32 {
panic!("__i32_to_i16: value {n} out of i16 range [{}, {}]", i16::MIN, i16::MAX);
}
n as i16
}
#[crate::polydat_node(category = Conversions)]
fn __u64_to_i16(n: u64) -> i16 {
if n > i16::MAX as u64 {
panic!("__u64_to_i16: value {n} exceeds i16::MAX ({})", i16::MAX);
}
n as i16
}
#[crate::polydat_node(category = Conversions)]
fn __f64_to_i16(f: f64) -> i16 {
if !f.is_finite() {
panic!("__f64_to_i16: non-finite value {f} cannot be represented as i16");
}
let n = f.trunc();
if n < i16::MIN as f64 || n > i16::MAX as f64 {
panic!("__f64_to_i16: value {f} out of i16 range [{}, {}]", i16::MIN, i16::MAX);
}
n as i16
}
#[crate::polydat_node(category = Conversions)]
fn __f64_to_f16(f: f64) -> half::f16 { half::f16::from_f64(f) }
#[crate::polydat_node(category = Conversions)]
fn __f32_to_f16(f: f32) -> half::f16 { half::f16::from_f32(f) }
#[crate::polydat_node(category = Conversions)]
fn __u64_to_f16(n: u64) -> half::f16 { half::f16::from_f64(n as f64) }
#[crate::polydat_node(category = Conversions)]
fn __bool_to_u8(b: bool) -> u8 { if b { 1 } else { 0 } }
#[crate::polydat_node(category = Conversions)]
fn __bool_to_u16(b: bool) -> u16 { if b { 1 } else { 0 } }
#[crate::polydat_node(category = Conversions)]
fn __bool_to_i8(b: bool) -> i8 { if b { 1 } else { 0 } }
#[crate::polydat_node(category = Conversions)]
fn __bool_to_i16(b: bool) -> i16 { if b { 1 } else { 0 } }
#[crate::polydat_node(category = Conversions)]
fn __bool_to_f16(b: bool) -> half::f16 {
if b { half::f16::ONE } else { half::f16::ZERO }
}
#[crate::polydat_node(category = Conversions)]
fn __u8_to_bool(n: u8) -> bool { n != 0 }
#[crate::polydat_node(category = Conversions)]
fn __u16_to_bool(n: u16) -> bool { n != 0 }
#[crate::polydat_node(category = Conversions)]
fn __i8_to_bool(n: i8) -> bool { n != 0 }
#[crate::polydat_node(category = Conversions)]
fn __i16_to_bool(n: i16) -> bool { n != 0 }
#[crate::polydat_node(category = Conversions)]
fn __f16_to_bool(f: half::f16) -> bool {
f != half::f16::ZERO && f != half::f16::NEG_ZERO && !f.is_nan()
}
#[crate::polydat_node(category = Conversions)]
fn __u8_to_string(n: u8) -> String { n.to_string() }
#[crate::polydat_node(category = Conversions)]
fn __u16_to_string(n: u16) -> String { n.to_string() }
#[crate::polydat_node(category = Conversions)]
fn __i8_to_string(n: i8) -> String { n.to_string() }
#[crate::polydat_node(category = Conversions)]
fn __i16_to_string(n: i16) -> String { n.to_string() }
#[crate::polydat_node(category = Conversions)]
fn __f16_to_string(f: half::f16) -> String { format!("{:?}", f.to_f32()) }
#[crate::polydat_node(category = Conversions)]
fn __str_to_u8(input: &str) -> u8 {
let raw = input.trim();
raw.parse::<u8>()
.unwrap_or_else(|e| panic!("__str_to_u8: cannot parse {raw:?} as u8: {e}"))
}
#[crate::polydat_node(category = Conversions)]
fn __str_to_u16(input: &str) -> u16 {
let raw = input.trim();
raw.parse::<u16>()
.unwrap_or_else(|e| panic!("__str_to_u16: cannot parse {raw:?} as u16: {e}"))
}
#[crate::polydat_node(category = Conversions)]
fn __str_to_i8(input: &str) -> i8 {
let raw = input.trim();
raw.parse::<i8>()
.unwrap_or_else(|e| panic!("__str_to_i8: cannot parse {raw:?} as i8: {e}"))
}
#[crate::polydat_node(category = Conversions)]
fn __str_to_i16(input: &str) -> i16 {
let raw = input.trim();
raw.parse::<i16>()
.unwrap_or_else(|e| panic!("__str_to_i16: cannot parse {raw:?} as i16: {e}"))
}
#[crate::polydat_node(category = Conversions)]
fn __str_to_f16(input: &str) -> half::f16 {
let raw = input.trim();
let f: f32 = raw
.parse()
.unwrap_or_else(|e| panic!("__str_to_f16: cannot parse {raw:?} as f16: {e}"));
half::f16::from_f32(f)
}
#[crate::polydat_node(category = Conversions)]
fn __u8_to_bytes(n: u8) -> Vec<u8> { vec![n] }
#[crate::polydat_node(category = Conversions)]
fn __u16_to_bytes(n: u16) -> Vec<u8> { n.to_le_bytes().to_vec() }
#[crate::polydat_node(category = Conversions)]
fn __i8_to_bytes(n: i8) -> Vec<u8> { n.to_le_bytes().to_vec() }
#[crate::polydat_node(category = Conversions)]
fn __i16_to_bytes(n: i16) -> Vec<u8> { n.to_le_bytes().to_vec() }
#[crate::polydat_node(category = Conversions)]
fn __f16_to_bytes(f: half::f16) -> Vec<u8> { f.to_bits().to_le_bytes().to_vec() }
#[crate::polydat_node(category = Conversions)]
fn __bytes_to_u8(b: &[u8]) -> u8 {
if b.len() != 1 {
panic!("__bytes_to_u8: expected exactly 1 byte for u8, got {}", b.len());
}
b[0]
}
#[crate::polydat_node(category = Conversions)]
fn __bytes_to_u16(b: &[u8]) -> u16 {
if b.len() != 2 {
panic!("__bytes_to_u16: expected exactly 2 bytes for u16, got {}", b.len());
}
u16::from_le_bytes(b.try_into().unwrap())
}
#[crate::polydat_node(category = Conversions)]
fn __bytes_to_i8(b: &[u8]) -> i8 {
if b.len() != 1 {
panic!("__bytes_to_i8: expected exactly 1 byte for i8, got {}", b.len());
}
b[0] as i8
}
#[crate::polydat_node(category = Conversions)]
fn __bytes_to_i16(b: &[u8]) -> i16 {
if b.len() != 2 {
panic!("__bytes_to_i16: expected exactly 2 bytes for i16, got {}", b.len());
}
i16::from_le_bytes(b.try_into().unwrap())
}
#[crate::polydat_node(category = Conversions)]
fn __bytes_to_f16(b: &[u8]) -> half::f16 {
if b.len() != 2 {
panic!("__bytes_to_f16: expected exactly 2 bytes for f16, got {}", b.len());
}
half::f16::from_bits(u16::from_le_bytes(b.try_into().unwrap()))
}
#[crate::polydat_node(category = Conversions)]
fn __u8_to_json(n: u8) -> Arc<serde_json::Value> {
Arc::new(serde_json::Value::from(n as u64))
}
#[crate::polydat_node(category = Conversions)]
fn __u16_to_json(n: u16) -> Arc<serde_json::Value> {
Arc::new(serde_json::Value::from(n as u64))
}
#[crate::polydat_node(category = Conversions)]
fn __i8_to_json(n: i8) -> Arc<serde_json::Value> {
Arc::new(serde_json::Value::from(n as i64))
}
#[crate::polydat_node(category = Conversions)]
fn __i16_to_json(n: i16) -> Arc<serde_json::Value> {
Arc::new(serde_json::Value::from(n as i64))
}
#[crate::polydat_node(category = Conversions)]
fn __f16_to_json(f: half::f16) -> Arc<serde_json::Value> {
let n = serde_json::Number::from_f64(f.to_f64()).unwrap_or_else(|| {
panic!("__f16_to_json: non-finite f16 {f} not representable as JSON number")
});
Arc::new(serde_json::Value::Number(n))
}
#[crate::polydat_node(category = Conversions)]
fn __json_to_u8(j: &serde_json::Value) -> u8 {
let n = j
.as_u64()
.unwrap_or_else(|| panic!("__json_to_u8: JSON value {j} is not a u64"));
if n > u8::MAX as u64 {
panic!("__json_to_u8: value {n} exceeds u8::MAX ({})", u8::MAX);
}
n as u8
}
#[crate::polydat_node(category = Conversions)]
fn __json_to_u16(j: &serde_json::Value) -> u16 {
let n = j
.as_u64()
.unwrap_or_else(|| panic!("__json_to_u16: JSON value {j} is not a u64"));
if n > u16::MAX as u64 {
panic!("__json_to_u16: value {n} exceeds u16::MAX ({})", u16::MAX);
}
n as u16
}
#[crate::polydat_node(category = Conversions)]
fn __json_to_i8(j: &serde_json::Value) -> i8 {
let n = j
.as_i64()
.unwrap_or_else(|| panic!("__json_to_i8: JSON value {j} is not an i64"));
if !(i8::MIN as i64..=i8::MAX as i64).contains(&n) {
panic!("__json_to_i8: value {n} out of i8 range [{}, {}]", i8::MIN, i8::MAX);
}
n as i8
}
#[crate::polydat_node(category = Conversions)]
fn __json_to_i16(j: &serde_json::Value) -> i16 {
let n = j
.as_i64()
.unwrap_or_else(|| panic!("__json_to_i16: JSON value {j} is not an i64"));
if !(i16::MIN as i64..=i16::MAX as i64).contains(&n) {
panic!("__json_to_i16: value {n} out of i16 range [{}, {}]", i16::MIN, i16::MAX);
}
n as i16
}
#[crate::polydat_node(category = Conversions)]
fn __json_to_f16(j: &serde_json::Value) -> half::f16 {
let f = j
.as_f64()
.unwrap_or_else(|| panic!("__json_to_f16: JSON value {j} is not an f64"));
half::f16::from_f64(f)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ast::{PolydatNode, Value};
fn check<N: PolydatNode>(node: &N, input: Value, expected: Value) {
let mut out = [Value::None];
node.eval(&[input], &mut out);
assert_eq!(out[0], expected, "{} produced wrong output", node.meta().name);
}
fn check_panics<N: PolydatNode>(node: &N, input: Value, msg_substring: &str) {
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
let mut out = [Value::None];
node.eval(&[input], &mut out);
}));
match result {
Ok(_) => panic!("{} did not panic as expected", node.meta().name),
Err(payload) => {
let s = payload
.downcast_ref::<String>()
.cloned()
.or_else(|| payload.downcast_ref::<&str>().map(|s| s.to_string()))
.unwrap_or_default();
assert!(
s.contains(msg_substring),
"{} panicked but message didn't contain {msg_substring:?}: {s}",
node.meta().name
);
}
}
}
fn f16_value(f: f32) -> Value {
Value::U64(half::f16::from_f32(f).to_bits() as u64)
}
#[test]
fn narrow_widenings() {
check(&U8ToU64::new(), Value::U64(200), Value::U64(200));
check(&U8ToU16::new(), Value::U64(200), Value::U64(200));
check(&U16ToU64::new(), Value::U64(60_000), Value::U64(60_000));
check(&U8ToF64::new(), Value::U64(7), Value::F64(7.0));
check(&I8ToI64::new(), Value::I64(-100), Value::I64(-100));
check(&I8ToI16::new(), Value::I64(-100), Value::I64(-100));
check(&I16ToI64::new(), Value::I64(-30_000), Value::I64(-30_000));
check(&I16ToF64::new(), Value::I64(-5), Value::F64(-5.0));
check(&F16ToF64::new(), f16_value(1.5), Value::F64(1.5));
check(&F16ToF32::new(), f16_value(1.5), Value::U64(1.5f32.to_bits() as u64));
}
#[test]
fn narrow_narrowings_and_range_panics() {
check(&U64ToU8::new(), Value::U64(255), Value::U64(255));
check_panics(&U64ToU8::new(), Value::U64(256), "exceeds u8::MAX");
check(&U64ToU16::new(), Value::U64(65_535), Value::U64(65_535));
check_panics(&U64ToU16::new(), Value::U64(65_536), "exceeds u16::MAX");
check(&I64ToI8::new(), Value::I64(-128), Value::I64(-128));
check_panics(&I64ToI8::new(), Value::I64(128), "out of i8 range");
check(&I64ToI16::new(), Value::I64(-32_768), Value::I64(-32_768));
check_panics(&I64ToI16::new(), Value::I64(32_768), "out of i16 range");
check_panics(&I64ToU8::new(), Value::I64(-1), "out of u8 range");
check_panics(&F64ToI8::new(), Value::F64(f64::NAN), "non-finite");
check(&F64ToI8::new(), Value::F64(-5.9), Value::I64(-5));
check(&F64ToU16::new(), Value::F64(42.7), Value::U64(42));
check(&F64ToF16::new(), Value::F64(1.5), f16_value(1.5));
}
#[test]
fn narrow_str_parses() {
check(&StrToU8::new(), Value::Str("200".into()), Value::U64(200));
check(&StrToU16::new(), Value::Str(" 60000 ".into()), Value::U64(60_000));
check(&StrToI8::new(), Value::Str("-100".into()), Value::I64(-100));
check(&StrToI16::new(), Value::Str("-30000".into()), Value::I64(-30_000));
check(&StrToF16::new(), Value::Str("1.5".into()), f16_value(1.5));
check_panics(&StrToU8::new(), Value::Str("256".into()), "cannot parse");
check_panics(&StrToI8::new(), Value::Str("xyz".into()), "cannot parse");
}
#[test]
fn narrow_bytes_round_trip() {
check(&U8ToBytes::new(), Value::U64(0xAB), Value::Bytes(vec![0xAB].into()));
check(&BytesToU8::new(), Value::Bytes(vec![0xAB].into()), Value::U64(0xAB));
check_panics(&BytesToU8::new(), Value::Bytes(vec![1, 2].into()), "expected exactly 1 byte");
check(&I16ToBytes::new(), Value::I64(-2), Value::Bytes((-2i16).to_le_bytes().to_vec().into()));
check(&BytesToI16::new(), Value::Bytes((-2i16).to_le_bytes().to_vec().into()), Value::I64(-2));
let f16_bytes = half::f16::from_f32(1.5).to_bits().to_le_bytes().to_vec();
check(&F16ToBytes::new(), f16_value(1.5), Value::Bytes(f16_bytes.clone().into()));
check(&BytesToF16::new(), Value::Bytes(f16_bytes.into()), f16_value(1.5));
}
#[test]
fn narrow_json_and_bool() {
check(&I8ToJson::new(), Value::I64(-5),
Value::Json(Arc::new(serde_json::Value::from(-5_i64))));
check(&JsonToI8::new(),
Value::Json(Arc::new(serde_json::Value::from(-5_i64))), Value::I64(-5));
check_panics(&JsonToU8::new(),
Value::Json(Arc::new(serde_json::Value::from(300_u64))), "exceeds u8::MAX");
check(&BoolToI8::new(), Value::Bool(true), Value::I64(1));
check(&BoolToF16::new(), Value::Bool(true), f16_value(1.0));
check(&I16ToBool::new(), Value::I64(-1), Value::Bool(true));
check(&F16ToBool::new(), f16_value(0.0), Value::Bool(false));
check(&F16ToBool::new(), f16_value(2.5), Value::Bool(true));
}
#[test]
fn narrow_string_renders() {
check(&I8ToString::new(), Value::I64(-7), Value::Str("-7".into()));
check(&U16ToString::new(), Value::U64(60_000), Value::Str("60000".into()));
check(&F16ToString::new(), f16_value(1.0), Value::Str("1.0".into()));
}
}