Skip to main content

jeff/
types.rs

1//! "Values" represent typed ports in the jeff language.
2//!
3//! Internally, these are coalesced into a single array at the function
4//! definition and each port contains an index into this array.
5
6use crate::capnp::jeff_capnp;
7use derive_more::Display;
8
9/// Value type.
10#[derive(Clone, Copy, Debug, PartialEq, Eq, Display)]
11pub enum Type {
12    /// Quantum bit.
13    ///
14    /// Qubits are linear types.
15    Qubit,
16    /// Quantum registers.
17    ///
18    /// A quantum register is an array of slots that can hold qubits.
19    /// Slots of a quantum register can either be empty or filled with a qubit.
20    ///
21    /// Quantum registers are linear types.
22    ///
23    /// If `length` is `None`, the register has dynamic length.
24    /// If `Some`, the register has static compile-time length.
25    #[display("Qureg[{}]", length.map_or("?".to_string(), |l| l.to_string()))]
26    QubitRegister {
27        /// Optional compile-time length.
28        length: Option<u32>,
29    },
30    /// Integers.
31    ///
32    /// The type does not distinguish between signed and unsigned integers.
33    /// Instead it is up to the operation to interpret the integer as signed or unsigned.
34    /// Signed integers are represented using two's complement.
35    ///
36    /// Integers of bitwidth 1 can be used as classical bits or boolean values.
37    #[display("Int{}", bits)]
38    Int {
39        /// Bitwidth of the integer.
40        bits: u8,
41    },
42    /// Integer array.
43    ///
44    /// Arrays of integers of bitwidth 1 can be used as classical bit arrays.
45    ///
46    /// If `length` is `None`, the array has dynamic length.
47    /// If `Some`, the array has static compile-time length.
48    #[display("IntArray{}[{}]", bits, length.map_or("?".to_string(), |l| l.to_string()))]
49    IntArray {
50        /// Bitwidth of the integers.
51        bits: u8,
52        /// Optional compile-time length.
53        length: Option<u32>,
54    },
55    /// Floating point numbers.
56    #[display("Float{}", precision.bits())]
57    Float {
58        /// Precision of the floating point number.
59        precision: FloatPrecision,
60    },
61    /// Array of floating point numbers.
62    ///
63    /// If `length` is `None`, the array has dynamic length.
64    /// If `Some`, the array has static compile-time length.
65    #[display("FloatArray{}[{}]", precision.bits(), length.map_or("?".to_string(), |l| l.to_string()))]
66    FloatArray {
67        /// Precision of the floating point numbers.
68        precision: FloatPrecision,
69        /// Optional compile-time length.
70        length: Option<u32>,
71    },
72}
73
74impl Type {
75    /// Create a new integer type.
76    pub fn int(bits: u8) -> Self {
77        Self::Int { bits }
78    }
79
80    /// Create a new boolean type.
81    pub fn bool() -> Self {
82        Self::Int { bits: 1 }
83    }
84
85    /// Create a new integer array type.
86    ///
87    /// If `length` is `None`, the array has dynamic length.
88    /// If `Some`, the array has static compile-time length.
89    pub fn int_array(bits: u8, length: Option<u32>) -> Self {
90        Self::IntArray { bits, length }
91    }
92
93    /// Create a new floating point type.
94    pub fn float(precision: FloatPrecision) -> Self {
95        Self::Float { precision }
96    }
97
98    /// Create a new floating point array type.
99    ///
100    /// If `length` is `None`, the array has dynamic length.
101    /// If `Some`, the array has static compile-time length.
102    pub fn float_array(precision: FloatPrecision, length: Option<u32>) -> Self {
103        Self::FloatArray { precision, length }
104    }
105
106    /// Parse a type from a capnp reader.
107    pub(crate) fn read_capnp(reader: jeff_capnp::type_::Reader<'_>) -> Self {
108        use jeff_capnp::type_::Which;
109        match reader
110            .which()
111            .expect("Type id was not in the schema. Schema should have been verified.")
112        {
113            Which::Qubit(_) => Self::Qubit,
114            Which::Qureg(qureg) => Self::QubitRegister {
115                length: match qureg.which().expect(
116                    "Qureg type id was not in the schema. Schema should have been verified.",
117                ) {
118                    jeff_capnp::type_::qureg::Which::Static(length) => Some(length),
119                    jeff_capnp::type_::qureg::Which::Dynamic(_) => None,
120                },
121            },
122            Which::Int(bits) => Self::Int { bits },
123            Which::IntArray(int_array) => Self::IntArray {
124                bits: int_array.get_bitwidth(),
125                length: match int_array.get_length().which().expect(
126                    "IntArray length id was not in the schema. Schema should have been verified.",
127                ) {
128                    jeff_capnp::type_::int_array::length::Which::Static(length) => Some(length),
129                    jeff_capnp::type_::int_array::length::Which::Dynamic(_) => None,
130                },
131            },
132            Which::Float(prec) => Self::Float {
133                precision: FloatPrecision::from_capnp(prec.expect(
134                    "FloatPrecision id was not in the schema. Schema should have been verified.",
135                )),
136            },
137            Which::FloatArray(float_array) => Self::FloatArray {
138                precision: FloatPrecision::from_capnp(float_array.get_precision().expect(
139                    "FloatPrecision id was not in the schema. Schema should have been verified.",
140                )),
141                length: match float_array.get_length().which().expect(
142                    "FloatArray length id was not in the schema. Schema should have been verified.",
143                ) {
144                    jeff_capnp::type_::float_array::length::Which::Static(length) => Some(length),
145                    jeff_capnp::type_::float_array::length::Which::Dynamic(_) => None,
146                },
147            },
148        }
149    }
150
151    /// Build a capnp type from this type.
152    #[allow(unused)]
153    pub(crate) fn build_capnp(&self, mut builder: jeff_capnp::type_::Builder) {
154        match self {
155            Self::Qubit => builder.set_qubit(()),
156            Self::QubitRegister { length } => {
157                let mut qureg = builder.reborrow().init_qureg();
158                match length {
159                    Some(length) => qureg.set_static(*length),
160                    None => qureg.set_dynamic(()),
161                }
162            }
163            Self::Int { bits } => builder.set_int(*bits),
164            Self::IntArray { bits, length } => {
165                let mut int_array = builder.reborrow().init_int_array();
166                int_array.set_bitwidth(*bits);
167                let mut int_array_len = int_array.reborrow().init_length();
168                match length {
169                    Some(length) => int_array_len.set_static(*length),
170                    None => int_array_len.set_dynamic(()),
171                }
172            }
173            Self::Float { precision } => builder.set_float(precision.as_capnp()),
174            Self::FloatArray { precision, length } => {
175                let mut float_array = builder.reborrow().init_float_array();
176                float_array.set_precision(precision.as_capnp());
177                let mut float_array_len = float_array.reborrow().init_length();
178                match length {
179                    Some(length) => float_array_len.set_static(*length),
180                    None => float_array_len.set_dynamic(()),
181                }
182            }
183        }
184    }
185}
186
187/// Precision of floating point number.
188#[derive(Clone, Copy, Debug, PartialEq, Eq, Display)]
189pub enum FloatPrecision {
190    /// 32-bit floating point number.
191    Float32,
192    /// 64-bit floating point number.
193    Float64,
194}
195
196impl FloatPrecision {
197    /// Parse a float precision from a capnp reader.
198    pub(crate) fn from_capnp(reader: jeff_capnp::FloatPrecision) -> Self {
199        match reader {
200            jeff_capnp::FloatPrecision::Float32 => Self::Float32,
201            jeff_capnp::FloatPrecision::Float64 => Self::Float64,
202        }
203    }
204
205    /// Returns the capnp representation of this float precision.
206    pub(crate) fn as_capnp(&self) -> jeff_capnp::FloatPrecision {
207        match self {
208            Self::Float32 => jeff_capnp::FloatPrecision::Float32,
209            Self::Float64 => jeff_capnp::FloatPrecision::Float64,
210        }
211    }
212
213    /// Returns the bitwidth of the floating point number.
214    pub fn bits(self) -> u8 {
215        match self {
216            Self::Float32 => 32,
217            Self::Float64 => 64,
218        }
219    }
220}