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#[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 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 crate::compiler::disassemble(&self.opcodes, &self.constants)
102 .unwrap_or_else(|e| format!("(failed to disassemble: {:?}", e))
103 }
104}