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;
7
8/// Value type.
9#[derive(Clone, Copy, Debug, PartialEq, Eq)]
10pub enum Type {
11    /// Quantum bit.
12    ///
13    /// Qubits are linear types.
14    Qubit,
15    /// Quantum registers.
16    ///
17    /// A quantum register is an array of slots that can hold qubits.
18    /// Slots of a quantum register can either be empty or filled with a qubit.
19    ///
20    /// Quantum registers are linear types.
21    ///
22    /// The length of the register is not known at compile time, but fixed at runtime.
23    QubitRegister,
24    /// Integers.
25    ///
26    /// The type does not distinguish between signed and unsigned integers.
27    /// Instead it is up to the operation to interpret the integer as signed or unsigned.
28    /// Signed integers are represented using two's complement.
29    ///
30    /// Integers of bitwidth 1 can be used as classical bits or boolean values.
31    Int {
32        /// Bitwidth of the integer.
33        bits: u8,
34    },
35    /// Integer array.
36    ///
37    /// The length of the array is not known at compile time, but fixed at runtime.
38    ///
39    /// Arrays of integers of bitwidth 1 can be used as classical bit arrays.
40    IntArray {
41        /// Bitwidth of the integers.
42        bits: u8,
43    },
44    /// Floating point numbers.
45    Float {
46        /// Precision of the floating point number.
47        precision: FloatPrecision,
48    },
49    /// Array of floating point numbers.
50    ///
51    /// The length of the array is not known at compile time, but fixed at runtime.
52    FloatArray {
53        /// Precision of the floating point numbers.
54        precision: FloatPrecision,
55    },
56}
57
58impl Type {
59    /// Create a new integer type.
60    pub fn int(bits: u8) -> Self {
61        Self::Int { bits }
62    }
63
64    /// Create a new boolean type.
65    pub fn bool() -> Self {
66        Self::Int { bits: 1 }
67    }
68
69    /// Create a new integer array type.
70    pub fn int_array(bits: u8) -> Self {
71        Self::IntArray { bits }
72    }
73
74    /// Create a new floating point type.
75    pub fn float(precision: FloatPrecision) -> Self {
76        Self::Float { precision }
77    }
78
79    /// Create a new floating point array type.
80    pub fn float_array(precision: FloatPrecision) -> Self {
81        Self::FloatArray { precision }
82    }
83
84    /// Parse a type from a capnp reader.
85    pub(crate) fn read_capnp(reader: jeff_capnp::type_::Reader<'_>) -> Self {
86        use jeff_capnp::type_::Which;
87        match reader
88            .which()
89            .expect("Type id was not in the schema. Schema should have been verified.")
90        {
91            Which::Qubit(_) => Self::Qubit,
92            Which::Qureg(_) => Self::QubitRegister,
93            Which::Int(bits) => Self::Int { bits },
94            Which::IntArray(bits) => Self::IntArray { bits },
95            Which::Float(prec) => Self::Float {
96                precision: FloatPrecision::from_capnp(prec.expect(
97                    "FloatPrecision id was not in the schema. Schema should have been verified.",
98                )),
99            },
100            Which::FloatArray(prec) => Self::FloatArray {
101                precision: FloatPrecision::from_capnp(prec.expect(
102                    "FloatPrecision id was not in the schema. Schema should have been verified.",
103                )),
104            },
105        }
106    }
107
108    /// Build a capnp type from this type.
109    #[allow(unused)]
110    pub(crate) fn build_capnp(&self, mut builder: jeff_capnp::type_::Builder) {
111        match self {
112            Self::Qubit => builder.set_qubit(()),
113            Self::QubitRegister => builder.set_qureg(()),
114            Self::Int { bits } => builder.set_int(*bits),
115            Self::IntArray { bits } => builder.set_int_array(*bits),
116            Self::Float { precision } => builder.set_float(precision.as_capnp()),
117            Self::FloatArray { precision } => builder.set_float_array(precision.as_capnp()),
118        }
119    }
120}
121
122/// Precision of floating point number.
123#[derive(Clone, Copy, Debug, PartialEq, Eq)]
124pub enum FloatPrecision {
125    /// 32-bit floating point number.
126    Float32,
127    /// 64-bit floating point number.
128    Float64,
129}
130
131impl FloatPrecision {
132    /// Parse a float precision from a capnp reader.
133    pub(crate) fn from_capnp(reader: jeff_capnp::FloatPrecision) -> Self {
134        match reader {
135            jeff_capnp::FloatPrecision::Float32 => Self::Float32,
136            jeff_capnp::FloatPrecision::Float64 => Self::Float64,
137        }
138    }
139
140    /// Returns the capnp representation of this float precision.
141    pub(crate) fn as_capnp(&self) -> jeff_capnp::FloatPrecision {
142        match self {
143            Self::Float32 => jeff_capnp::FloatPrecision::Float32,
144            Self::Float64 => jeff_capnp::FloatPrecision::Float64,
145        }
146    }
147
148    /// Returns the bitwidth of the floating point number.
149    pub fn bits(self) -> u8 {
150        match self {
151            Self::Float32 => 32,
152            Self::Float64 => 64,
153        }
154    }
155}