concinnity_core/behavior/
value.rs1use crate::components::BehaviorLiteral;
5use crate::ecs::{Entity, TraceVal};
6
7#[derive(Clone, Copy, Debug, PartialEq)]
9pub enum Val {
10 Bool(bool),
12 Int(i32),
14 Float(f32),
16 Vec3([f32; 3]),
18 Entity(Entity),
20}
21
22impl Val {
23 pub(crate) fn as_bool(self) -> Option<bool> {
24 match self {
25 Val::Bool(b) => Some(b),
26 _ => None,
27 }
28 }
29
30 pub(crate) fn as_entity(self) -> Option<Entity> {
31 match self {
32 Val::Entity(e) => Some(e),
33 _ => None,
34 }
35 }
36
37 pub(crate) fn as_vec3(self) -> Option<[f32; 3]> {
38 match self {
39 Val::Vec3(v) => Some(v),
40 _ => None,
41 }
42 }
43
44 pub fn as_f32(self) -> Option<f32> {
46 match self {
47 Val::Int(i) => Some(i as f32),
48 Val::Float(f) => Some(f),
49 _ => None,
50 }
51 }
52
53 pub fn from_literal(lit: &BehaviorLiteral) -> Val {
55 match *lit {
56 BehaviorLiteral::Bool(b) => Val::Bool(b),
57 BehaviorLiteral::Int(i) => Val::Int(i),
58 BehaviorLiteral::Float(f) => Val::Float(f),
59 BehaviorLiteral::Vec3(v) => Val::Vec3(v),
60 }
61 }
62
63 pub fn to_literal(self) -> BehaviorLiteral {
66 match self {
67 Val::Bool(b) => BehaviorLiteral::Bool(b),
68 Val::Int(i) => BehaviorLiteral::Int(i),
69 Val::Float(f) => BehaviorLiteral::Float(f),
70 Val::Vec3(v) => BehaviorLiteral::Vec3(v),
71 Val::Entity(_) => BehaviorLiteral::Int(0),
72 }
73 }
74
75 pub fn to_trace(self) -> TraceVal {
77 match self {
78 Val::Bool(b) => TraceVal::Bool(b),
79 Val::Int(i) => TraceVal::Int(i),
80 Val::Float(f) => TraceVal::Float(f),
81 Val::Vec3(v) => TraceVal::Vec3(v),
82 Val::Entity(e) => TraceVal::Entity(e.to_bits()),
83 }
84 }
85
86 pub fn same_type(self, other: Val) -> bool {
89 core::mem::discriminant(&self) == core::mem::discriminant(&other)
90 }
91}
92
93#[derive(Clone, Copy, Debug)]
95pub enum Arith {
96 Add,
98 Sub,
100 Mul,
102 Div,
104}
105
106#[derive(Clone, Copy, Debug)]
108pub enum Cmp {
109 Eq,
111 Ne,
113 Lt,
115 Le,
117 Gt,
119 Ge,
121}
122
123#[cfg(test)]
124mod tests {
125 use super::*;
126 use core::num::NonZeroU32;
127
128 fn entity() -> Entity {
129 Entity::new(7, NonZeroU32::MIN)
130 }
131
132 #[test]
135 fn each_reader_answers_only_for_its_own_shape() {
136 assert_eq!(Val::Bool(true).as_bool(), Some(true));
137 assert_eq!(Val::Int(1).as_bool(), None);
138
139 assert_eq!(Val::Entity(entity()).as_entity(), Some(entity()));
140 assert_eq!(Val::Int(1).as_entity(), None);
141
142 assert_eq!(Val::Vec3([1.0; 3]).as_vec3(), Some([1.0; 3]));
143 assert_eq!(Val::Int(1).as_vec3(), None);
144 }
145
146 #[test]
149 fn the_scalar_reading_covers_both_numeric_shapes() {
150 assert_eq!(Val::Int(3).as_f32(), Some(3.0));
151 assert_eq!(Val::Float(0.5).as_f32(), Some(0.5));
152 assert_eq!(Val::Bool(true).as_f32(), None);
153 assert_eq!(Val::Vec3([1.0; 3]).as_f32(), None);
154 assert_eq!(Val::Entity(entity()).as_f32(), None);
155 }
156
157 #[test]
158 fn a_literal_round_trips_through_its_runtime_value() {
159 for lit in [
160 BehaviorLiteral::Bool(true),
161 BehaviorLiteral::Int(-2),
162 BehaviorLiteral::Float(1.5),
163 BehaviorLiteral::Vec3([1.0, 2.0, 3.0]),
164 ] {
165 assert_eq!(Val::from_literal(&lit).to_literal(), lit);
166 }
167 }
168
169 #[test]
173 fn an_entity_persists_as_the_declared_away_default() {
174 assert_eq!(Val::Entity(entity()).to_literal(), BehaviorLiteral::Int(0));
175 }
176
177 #[test]
178 fn every_value_has_a_trace_form() {
179 assert_eq!(Val::Bool(true).to_trace(), TraceVal::Bool(true));
180 assert_eq!(Val::Int(-2).to_trace(), TraceVal::Int(-2));
181 assert_eq!(Val::Float(1.5).to_trace(), TraceVal::Float(1.5));
182 assert_eq!(
183 Val::Vec3([1.0, 2.0, 3.0]).to_trace(),
184 TraceVal::Vec3([1.0, 2.0, 3.0])
185 );
186 assert_eq!(
187 Val::Entity(entity()).to_trace(),
188 TraceVal::Entity(entity().to_bits())
189 );
190 }
191
192 #[test]
195 fn same_type_compares_shape_rather_than_value() {
196 assert!(Val::Int(1).same_type(Val::Int(9)));
197 assert!(!Val::Int(1).same_type(Val::Float(1.0)));
198 assert!(!Val::Bool(true).same_type(Val::Int(1)));
199 }
200}