#[non_exhaustive]
#[derive(Debug, Clone)]
pub enum Value {
U32(u32),
I32(i32),
U64(u64),
Bool(bool),
Bytes(Vec<u8>),
Float(f64),
Array(Vec<Value>),
}
impl PartialEq for Value {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::U32(a), Self::U32(b)) => a == b,
(Self::I32(a), Self::I32(b)) => a == b,
(Self::U64(a), Self::U64(b)) => a == b,
(Self::Bool(a), Self::Bool(b)) => a == b,
(Self::Bytes(a), Self::Bytes(b)) => a == b,
(Self::Float(a), Self::Float(b)) => a.to_bits() == b.to_bits(),
(Self::Array(a), Self::Array(b)) => a == b,
_ => false,
}
}
}
impl Eq for Value {}
impl Value {
#[must_use]
pub fn truthy(&self) -> bool {
match self {
Self::Array(values) => !values.is_empty(),
Self::Float(value) => value.to_bits() != 0,
_ => self.try_as_u32().unwrap_or(1) != 0,
}
}
#[must_use]
pub fn to_bytes(&self) -> Vec<u8> {
match self {
Self::U32(value) => value.to_le_bytes().to_vec(),
Self::I32(value) => value.to_le_bytes().to_vec(),
Self::U64(value) => value.to_le_bytes().to_vec(),
Self::Bool(value) => u32::from(*value).to_le_bytes().to_vec(),
Self::Bytes(bytes) => bytes.clone(),
Self::Float(value) => value.to_le_bytes().to_vec(),
Self::Array(values) => values.iter().flat_map(Self::to_bytes).collect(),
}
}
#[must_use]
pub fn to_bytes_width(&self, declared_width: usize) -> Vec<u8> {
let mut bytes = self.to_bytes();
if declared_width == 0 {
return bytes;
}
bytes.resize(declared_width, 0);
bytes.truncate(declared_width);
bytes
}
#[must_use]
pub fn try_as_u32(&self) -> Option<u32> {
match self {
Self::U32(value) => Some(*value),
Self::I32(value) => u32::try_from(*value).ok(),
Self::U64(value) => u32::try_from(*value).ok(),
Self::Bool(value) => Some(u32::from(*value)),
Self::Bytes(bytes) => (bytes.len() <= 4).then(|| read_u32_prefix(bytes)),
Self::Float(value) => Some(*value as u32),
Self::Array(_) => None,
}
}
#[must_use]
pub fn as_u32(&self) -> u32 {
self.try_as_u32().unwrap_or(0)
}
#[must_use]
pub fn try_as_u64(&self) -> Option<u64> {
match self {
Self::U32(value) => Some(u64::from(*value)),
Self::I32(value) => u64::try_from(*value).ok(),
Self::U64(value) => Some(*value),
Self::Bool(value) => Some(u64::from(*value)),
Self::Bytes(bytes) => (bytes.len() <= 8).then(|| read_u64_prefix(bytes)),
Self::Float(value) => Some(*value as u64),
Self::Array(_) => None,
}
}
#[must_use]
pub fn as_u64(&self) -> u64 {
self.try_as_u64().unwrap_or(0)
}
#[must_use]
pub fn wide_bytes(&self) -> Vec<u8> {
self.to_bytes()
}
#[must_use]
pub fn zero_for(ty: vyre::ir::DataType) -> Self {
Self::try_zero_for(ty).unwrap_or_else(|| Self::Bytes(Vec::new()))
}
#[must_use]
pub fn try_zero_for(ty: vyre::ir::DataType) -> Option<Self> {
match ty {
vyre::ir::DataType::U32 => Some(Self::U32(0)),
vyre::ir::DataType::I32 => Some(Self::I32(0)),
vyre::ir::DataType::U64 => Some(Self::U64(0)),
vyre::ir::DataType::Bool => Some(Self::Bool(false)),
vyre::ir::DataType::Bytes => Some(Self::Bytes(Vec::new())),
vyre::ir::DataType::Vec2U32 => Some(Self::Bytes(vec![0; 8])),
vyre::ir::DataType::Vec4U32 => Some(Self::Bytes(vec![0; 16])),
_ => None,
}
}
pub fn from_element_bytes(ty: vyre::ir::DataType, bytes: &[u8]) -> Result<Self, String> {
match ty {
vyre::ir::DataType::U32 => {
if bytes.len() < 4 {
return Err("u32 requires 4 bytes".to_string());
}
Ok(Self::U32(u32::from_le_bytes([
bytes[0], bytes[1], bytes[2], bytes[3],
])))
}
vyre::ir::DataType::I32 => {
if bytes.len() < 4 {
return Err("i32 requires 4 bytes".to_string());
}
Ok(Self::I32(i32::from_le_bytes([
bytes[0], bytes[1], bytes[2], bytes[3],
])))
}
vyre::ir::DataType::U64 => {
if bytes.len() < 8 {
return Err("u64 requires 8 bytes".to_string());
}
Ok(Self::U64(u64::from_le_bytes([
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
])))
}
vyre::ir::DataType::Bool => {
if bytes.len() < 4 {
return Err("bool requires 4 bytes".to_string());
}
Ok(Self::Bool(
u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]) != 0,
))
}
vyre::ir::DataType::Vec2U32 => {
if bytes.len() < 8 {
return Err("vec2u32 requires 8 bytes".to_string());
}
Ok(Self::Bytes(bytes[..8].to_vec()))
}
vyre::ir::DataType::Vec4U32 => {
if bytes.len() < 16 {
return Err("vec4u32 requires 16 bytes".to_string());
}
Ok(Self::Bytes(bytes[..16].to_vec()))
}
vyre::ir::DataType::F32 => {
if bytes.len() < 4 {
return Err("f32 requires 4 bytes".to_string());
}
Ok(Self::Float(f64::from(f32::from_le_bytes([
bytes[0], bytes[1], bytes[2], bytes[3],
]))))
}
vyre::ir::DataType::Bytes => Ok(Self::Bytes(bytes.to_vec())),
_ => Ok(Self::Bytes(bytes.to_vec())),
}
}
}
fn read_u32_prefix(bytes: &[u8]) -> u32 {
let mut padded = [0u8; 4];
let len = bytes.len().min(4);
padded[..len].copy_from_slice(&bytes[..len]);
u32::from_le_bytes(padded)
}
fn read_u64_prefix(bytes: &[u8]) -> u64 {
let mut padded = [0u8; 8];
let len = bytes.len().min(8);
padded[..len].copy_from_slice(&bytes[..len]);
u64::from_le_bytes(padded)
}