zust-vm-spirv 0.9.3

SPIR-V code generation backend for the Zust scripting language.
Documentation
use anyhow::{Result, bail};
use dynamic::{Dynamic, Type};

use crate::context::{SpirvCompiler, SpirvTy, Value};

impl SpirvCompiler {
    pub(crate) fn const_zero(&mut self, ty: Type) -> Result<Value> {
        let value = if ty.is_float() {
            if ty.is_f64() { Dynamic::F64(0.0) } else { Dynamic::F32(0.0) }
        } else if ty.is_uint() {
            Dynamic::U32(0)
        } else {
            Dynamic::I32(0)
        };
        self.const_dynamic(value).and_then(|v| self.convert(v, ty))
    }

    pub(crate) fn const_u32(&mut self, value: u32) -> u32 {
        self.const_dynamic(Dynamic::U32(value)).expect("u32 constants are supported").id
    }

    pub(crate) fn get_const_u32(&self, value: &Value) -> Option<u32> {
        self.consts.iter().find_map(|(c, id)| if *id == value.id { c.as_uint().map(|v| v as u32).or_else(|| c.as_int().and_then(|v| if v >= 0 { Some(v as u32) } else { None })) } else { None })
    }

    pub(crate) fn const_value(&self, id: u32) -> Option<Dynamic> {
        self.consts.iter().find_map(|(value, const_id)| (*const_id == id).then(|| value.clone()))
    }

    pub(crate) fn const_dynamic(&mut self, value: Dynamic) -> Result<Value> {
        let ty = value.get_type();
        if let Some((_, id)) = self.consts.iter().find(|(v, _)| v == &value && v.get_type() == ty) {
            return Ok(Value { id: *id, ty: value.get_type() });
        }
        let ty_id = self.get_type(SpirvTy::Value(ty.clone()));
        let id = match value.clone() {
            Dynamic::Bool(true) => self.builder.constant_true(ty_id),
            Dynamic::Bool(false) => self.builder.constant_false(ty_id),
            Dynamic::F32(v) => self.builder.constant_bit32(ty_id, v.to_bits()),
            Dynamic::F64(v) => self.builder.constant_bit64(ty_id, v.to_bits()),
            Dynamic::I8(v) => self.builder.constant_bit32(ty_id, v as i32 as u32),
            Dynamic::I16(v) => self.builder.constant_bit32(ty_id, v as i32 as u32),
            Dynamic::I32(v) => self.builder.constant_bit32(ty_id, v as u32),
            Dynamic::I64(v) => self.builder.constant_bit64(ty_id, v as u64),
            Dynamic::U8(v) => self.builder.constant_bit32(ty_id, v as u32),
            Dynamic::U16(v) => self.builder.constant_bit32(ty_id, v as u32),
            Dynamic::U32(v) => self.builder.constant_bit32(ty_id, v),
            Dynamic::U64(v) => self.builder.constant_bit64(ty_id, v),
            other => bail!("unsupported SPIR-V constant: {other:?}"),
        };
        self.consts.push((value, id));
        Ok(Value { id, ty })
    }
}