bloqade_lanes_bytecode_core/bytecode/
value.rs1use super::encode::DecodeError;
2
3pub const TAG_FLOAT: u8 = 0x0;
5pub const TAG_INT: u8 = 0x1;
6pub const TAG_ARRAY_REF: u8 = 0x2;
7pub const TAG_LOCATION: u8 = 0x3;
8pub const TAG_LANE: u8 = 0x4;
9pub const TAG_ZONE: u8 = 0x5;
10pub const TAG_MEASURE_FUTURE: u8 = 0x6;
11pub const TAG_DETECTOR_REF: u8 = 0x7;
12pub const TAG_OBSERVABLE_REF: u8 = 0x8;
13
14#[derive(Debug, Clone, Copy, PartialEq)]
15pub enum CpuValue {
16 Float(f64),
17 Int(i64),
18}
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub enum ArrayValue {
22 ArrayRef(u32),
23}
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub enum DeviceValue {
27 Location(u32),
28 Lane(u64),
29 Zone(u32),
30 MeasureFuture(u32),
31 DetectorRef(u32),
32 ObservableRef(u32),
33}
34
35#[derive(Debug, Clone, Copy, PartialEq)]
36pub enum Value {
37 Cpu(CpuValue),
38 Array(ArrayValue),
39 Device(DeviceValue),
40}
41
42impl Value {
43 pub fn type_tag(&self) -> u8 {
44 match self {
45 Value::Cpu(CpuValue::Float(_)) => TAG_FLOAT,
46 Value::Cpu(CpuValue::Int(_)) => TAG_INT,
47 Value::Array(ArrayValue::ArrayRef(_)) => TAG_ARRAY_REF,
48 Value::Device(DeviceValue::Location(_)) => TAG_LOCATION,
49 Value::Device(DeviceValue::Lane(_)) => TAG_LANE,
50 Value::Device(DeviceValue::Zone(_)) => TAG_ZONE,
51 Value::Device(DeviceValue::MeasureFuture(_)) => TAG_MEASURE_FUTURE,
52 Value::Device(DeviceValue::DetectorRef(_)) => TAG_DETECTOR_REF,
53 Value::Device(DeviceValue::ObservableRef(_)) => TAG_OBSERVABLE_REF,
54 }
55 }
56
57 pub fn raw_bits(&self) -> u64 {
58 match self {
59 Value::Cpu(CpuValue::Float(f)) => f.to_bits(),
60 Value::Cpu(CpuValue::Int(v)) => *v as u64,
61 Value::Array(ArrayValue::ArrayRef(v)) => *v as u64,
62 Value::Device(DeviceValue::Location(v)) => *v as u64,
63 Value::Device(DeviceValue::Lane(v)) => *v,
64 Value::Device(DeviceValue::Zone(v)) => *v as u64,
65 Value::Device(DeviceValue::MeasureFuture(v)) => *v as u64,
66 Value::Device(DeviceValue::DetectorRef(v)) => *v as u64,
67 Value::Device(DeviceValue::ObservableRef(v)) => *v as u64,
68 }
69 }
70
71 pub fn from_tag_and_bits(tag: u8, bits: u64) -> Result<Self, DecodeError> {
72 match tag {
73 TAG_FLOAT => Ok(Value::Cpu(CpuValue::Float(f64::from_bits(bits)))),
74 TAG_INT => Ok(Value::Cpu(CpuValue::Int(bits as i64))),
75 TAG_ARRAY_REF => Ok(Value::Array(ArrayValue::ArrayRef(bits as u32))),
76 TAG_LOCATION => Ok(Value::Device(DeviceValue::Location(bits as u32))),
77 TAG_LANE => Ok(Value::Device(DeviceValue::Lane(bits))),
78 TAG_ZONE => Ok(Value::Device(DeviceValue::Zone(bits as u32))),
79 TAG_MEASURE_FUTURE => Ok(Value::Device(DeviceValue::MeasureFuture(bits as u32))),
80 TAG_DETECTOR_REF => Ok(Value::Device(DeviceValue::DetectorRef(bits as u32))),
81 TAG_OBSERVABLE_REF => Ok(Value::Device(DeviceValue::ObservableRef(bits as u32))),
82 _ => Err(DecodeError::InvalidOperand {
83 opcode: 0,
84 message: format!("unknown type tag: 0x{:x}", tag),
85 }),
86 }
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93
94 #[test]
95 fn test_type_tag_round_trip() {
96 let values = vec![
97 Value::Cpu(CpuValue::Float(1.5)),
98 Value::Cpu(CpuValue::Int(42)),
99 Value::Array(ArrayValue::ArrayRef(7)),
100 Value::Device(DeviceValue::Location(100)),
101 Value::Device(DeviceValue::Lane(200)),
102 Value::Device(DeviceValue::Zone(300)),
103 Value::Device(DeviceValue::MeasureFuture(400)),
104 Value::Device(DeviceValue::DetectorRef(500)),
105 Value::Device(DeviceValue::ObservableRef(600)),
106 ];
107
108 for val in values {
109 let tag = val.type_tag();
110 let bits = val.raw_bits();
111 let reconstructed = Value::from_tag_and_bits(tag, bits).unwrap();
112 assert_eq!(val, reconstructed);
113 }
114 }
115
116 #[test]
117 fn test_raw_bits_float() {
118 let v = Value::Cpu(CpuValue::Float(1.0));
119 assert_eq!(v.raw_bits(), 1.0_f64.to_bits());
120 }
121
122 #[test]
123 fn test_raw_bits_int() {
124 let v = Value::Cpu(CpuValue::Int(-1));
125 assert_eq!(v.raw_bits(), 0xFFFF_FFFF_FFFF_FFFF);
126 }
127
128 #[test]
129 fn test_from_tag_and_bits_each_variant() {
130 assert_eq!(
131 Value::from_tag_and_bits(TAG_FLOAT, 1.0_f64.to_bits()).unwrap(),
132 Value::Cpu(CpuValue::Float(1.0))
133 );
134 assert_eq!(
135 Value::from_tag_and_bits(TAG_INT, 42).unwrap(),
136 Value::Cpu(CpuValue::Int(42))
137 );
138 assert_eq!(
139 Value::from_tag_and_bits(TAG_ARRAY_REF, 5).unwrap(),
140 Value::Array(ArrayValue::ArrayRef(5))
141 );
142 assert_eq!(
143 Value::from_tag_and_bits(TAG_LOCATION, 10).unwrap(),
144 Value::Device(DeviceValue::Location(10))
145 );
146 assert_eq!(
147 Value::from_tag_and_bits(TAG_LANE, 20).unwrap(),
148 Value::Device(DeviceValue::Lane(20))
149 );
150 assert_eq!(
151 Value::from_tag_and_bits(TAG_ZONE, 30).unwrap(),
152 Value::Device(DeviceValue::Zone(30))
153 );
154 assert_eq!(
155 Value::from_tag_and_bits(TAG_MEASURE_FUTURE, 40).unwrap(),
156 Value::Device(DeviceValue::MeasureFuture(40))
157 );
158 assert_eq!(
159 Value::from_tag_and_bits(TAG_DETECTOR_REF, 50).unwrap(),
160 Value::Device(DeviceValue::DetectorRef(50))
161 );
162 assert_eq!(
163 Value::from_tag_and_bits(TAG_OBSERVABLE_REF, 60).unwrap(),
164 Value::Device(DeviceValue::ObservableRef(60))
165 );
166 }
167
168 #[test]
169 fn test_unknown_tag_produces_error() {
170 assert!(Value::from_tag_and_bits(0xF, 0).is_err());
171 }
172}