bloqade_lanes_bytecode_core/bytecode/
value.rs

1use super::encode::DecodeError;
2
3// 4-bit type tag constants
4pub 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}