saft/
program.rs

1use num_enum::TryFromPrimitiveError;
2use saft_sdf::Opcode;
3use std::collections::hash_map::DefaultHasher;
4use std::hash::Hash;
5use std::hash::Hasher;
6
7type UnknownOpcodeError = TryFromPrimitiveError<Opcode>;
8
9pub fn constants_hash(constants: &[f32]) -> u64 {
10    let mut s = DefaultHasher::new();
11    for &c in constants {
12        let v: u32 = c.to_bits();
13        v.hash(&mut s);
14    }
15
16    s.finish()
17}
18
19pub fn opcodes_hash(opcodes: &[Opcode]) -> u64 {
20    let mut s = DefaultHasher::new();
21    opcodes.hash(&mut s);
22    s.finish()
23}
24
25/// Represents a signed distance field function as a program with a constant pool and opcodes.
26#[derive(Debug, Clone, Default, PartialEq)]
27#[cfg_attr(feature = "with_serde", derive(serde::Serialize, serde::Deserialize))]
28#[cfg_attr(feature = "with_speedy", derive(speedy::Writable, speedy::Readable))]
29#[cfg_attr(feature = "with_arbitrary", derive(arbitrary::Arbitrary))]
30pub struct Program {
31    pub constants: Vec<f32>,
32    pub opcodes: Vec<Opcode>,
33}
34
35impl Program {
36    #[must_use]
37    pub fn with_constants(&self, constants: Vec<f32>) -> Self {
38        Self {
39            constants,
40            opcodes: self.opcodes.clone(),
41        }
42    }
43
44    pub fn constant_hash(&self) -> u64 {
45        constants_hash(&self.constants)
46    }
47
48    pub fn program_hash(&self) -> u64 {
49        opcodes_hash(&self.opcodes)
50    }
51
52    pub fn full_hash(&self) -> u64 {
53        self.program_hash() ^ self.constant_hash()
54    }
55
56    #[cfg(feature = "with_bincode")]
57    pub fn as_bytes(&self) -> Result<Vec<u8>, std::boxed::Box<bincode::ErrorKind>> {
58        bincode::serialize(self)
59    }
60
61    #[cfg(feature = "with_bincode")]
62    pub fn from_bytes(bytes: &[u8]) -> Result<Self, std::boxed::Box<bincode::ErrorKind>> {
63        bincode::deserialize(bytes)
64    }
65
66    pub fn from_raw(opcodes: &[u32], constants: &[f32]) -> Result<Self, UnknownOpcodeError> {
67        // We use collect to convert from a Vec<Result<..>> to a Result<Vec<..>>. Neat!
68        let opcodes = opcodes
69            .iter()
70            .map(|opcode| Opcode::try_from(*opcode))
71            .collect::<Result<Vec<Opcode>, _>>()?;
72        Ok(Self {
73            opcodes,
74            constants: constants.to_vec(),
75        })
76    }
77
78    pub fn as_raw(&self) -> (Vec<u32>, Vec<f32>) {
79        let opcodes = self
80            .opcodes
81            .iter()
82            .map(|&opcode| opcode.into())
83            .collect::<Vec<u32>>();
84        (opcodes, self.constants.clone())
85    }
86
87    pub(crate) fn constant_push_vec2(&mut self, v: impl Into<[f32; 2]>) {
88        self.constants.extend(v.into());
89    }
90
91    pub(crate) fn constant_push_vec3(&mut self, v: impl Into<[f32; 3]>) {
92        self.constants.extend(v.into());
93    }
94
95    pub(crate) fn constant_push_vec4(&mut self, v: impl Into<[f32; 4]>) {
96        self.constants.extend(v.into());
97    }
98
99    pub fn disassemble(&self) -> String {
100        // Moved it to the compiler file, fits better there.
101        crate::compiler::disassemble(&self.opcodes, &self.constants)
102            .unwrap_or_else(|e| format!("(failed to disassemble: {:?}", e))
103    }
104}