quil_rs/program/
calibration_set.rs

1use crate::instruction::CalibrationSignature;
2
3/// A [`CalibrationSet`] is a collection of calibration instructions that respect how
4/// calibrations work in a Quil program.
5///
6/// During calibration expansion, Calibrations are matched to instructions using their unique
7/// [`CalibrationSignature`]. This means only one calibration can be matched to a particular
8/// instruction. While the Quil specification doesn't explicitly define the behavior of
9/// signature conflicts, [`CalibrationSet`] takes the liberty of only allowing one calibration
10/// per [`CalibrationSignature`].
11///
12/// Calibrations maintain insertion order
13#[derive(Clone, Debug, PartialEq)]
14pub struct CalibrationSet<T> {
15    // The amount of calibrations in a program tends to be small enough that a Vec is more
16    // performant than a typical set.
17    // Sets also have trait bounds that `Instruction`s don't meet, which hampers utility.
18    data: Vec<T>,
19}
20
21impl<T> Default for CalibrationSet<T>
22where
23    T: CalibrationSignature,
24{
25    fn default() -> Self {
26        Self::new()
27    }
28}
29
30impl<T> IntoIterator for CalibrationSet<T> {
31    type IntoIter = std::vec::IntoIter<Self::Item>;
32    type Item = T;
33
34    fn into_iter(self) -> Self::IntoIter {
35        self.data.into_iter()
36    }
37}
38
39impl<T> From<Vec<T>> for CalibrationSet<T>
40where
41    T: CalibrationSignature,
42{
43    fn from(data: Vec<T>) -> Self {
44        let mut set = Self::with_capacity(data.len());
45        for element in data {
46            set.replace(element);
47        }
48        set
49    }
50}
51
52impl<T> CalibrationSet<T>
53where
54    T: CalibrationSignature,
55{
56    /// Creates an empty [`ProgramCalibrationSet`].
57    pub fn new() -> Self {
58        Self { data: Vec::new() }
59    }
60
61    /// Creates a [`InnerCalibrationSet`] with the specified capacity.
62    pub fn with_capacity(capacity: usize) -> Self {
63        Self {
64            data: Vec::with_capacity(capacity),
65        }
66    }
67
68    /// Returns the capacity of the [`ProgramCalibrationSet`].
69    pub fn capacity(&self) -> usize {
70        self.data.capacity()
71    }
72
73    /// Returns the length of the [`ProgramCalibrationSet`].
74    pub fn len(&self) -> usize {
75        self.data.len()
76    }
77
78    /// Returns whether the [`ProgramCalibrationSet`] is empty.
79    pub fn is_empty(&self) -> bool {
80        self.len() == 0
81    }
82
83    /// Returns an iterator of references to the values in the set.
84    pub fn iter(&self) -> std::slice::Iter<'_, T> {
85        self.data.iter()
86    }
87
88    /// Get a reference to a value that has a matching signature, if it exists.
89    pub fn get(&self, signature: &<T as CalibrationSignature>::Signature<'_>) -> Option<&T> {
90        if let Some(index) = self.signature_position(signature) {
91            Some(&self.data[index])
92        } else {
93            None
94        }
95    }
96
97    /// Adds a value to the set, replacing and returning an existing value with a matching
98    /// [`CalibrationSignature`], if it exists.
99    pub fn replace(&mut self, value: T) -> Option<T> {
100        let position = self.signature_position(&value.signature());
101        if let Some(index) = position {
102            let replaced = std::mem::replace(&mut self.data[index], value);
103            Some(replaced)
104        } else {
105            self.data.push(value);
106            None
107        }
108    }
109
110    /// Removes a value from the set. Returns whether the value was present in the set.
111    pub fn remove(&mut self, signature: &<T as CalibrationSignature>::Signature<'_>) -> bool {
112        if let Some(index) = self.signature_position(signature) {
113            self.data.remove(index);
114            true
115        } else {
116            false
117        }
118    }
119
120    /// Returns the index of an element whose [`CalibrationSignature`] matches the given value, if one exists.
121    fn signature_position(
122        &self,
123        signature: &<T as CalibrationSignature>::Signature<'_>,
124    ) -> Option<usize> {
125        for (i, element) in self.data.iter().enumerate() {
126            if element.has_signature(signature) {
127                return Some(i);
128            }
129        }
130
131        None
132        //self.data
133        //    .iter()
134        //    .position(move |element| { signature == element.signature() })
135    }
136}
137
138impl<T> Extend<T> for CalibrationSet<T>
139where
140    T: CalibrationSignature,
141{
142    fn extend<I>(&mut self, iter: I)
143    where
144        I: IntoIterator<Item = T>,
145    {
146        for value in iter {
147            self.replace(value);
148        }
149    }
150}
151
152#[cfg(test)]
153mod tests {
154    use super::*;
155    use crate::instruction::CalibrationSignature;
156
157    #[derive(Clone, Debug, PartialEq)]
158    struct TestCalibration {
159        signature: String,
160        /// Optional byte, can be used to differentiate between two TestCalibrations with the same
161        /// signature.
162        data: Option<u8>,
163    }
164
165    impl TestCalibration {
166        fn new(signature: &str, data: Option<u8>) -> Self {
167            Self {
168                signature: signature.to_string(),
169                data,
170            }
171        }
172    }
173
174    impl CalibrationSignature for TestCalibration {
175        type Signature<'a> = &'a str;
176
177        fn signature(&self) -> Self::Signature<'_> {
178            self.signature.as_str()
179        }
180
181        fn has_signature(&self, signature: &Self::Signature<'_>) -> bool {
182            self.signature == *signature
183        }
184    }
185
186    #[test]
187    fn test_replace() {
188        let mut set = CalibrationSet::new();
189        let calib = TestCalibration::new("Signature", None);
190        set.replace(calib.clone());
191        assert_eq!(set.len(), 1);
192        assert!(set.iter().all(|item| item == &calib));
193
194        let calib2 = TestCalibration::new("Signature", Some(42));
195        let replaced = set
196            .replace(calib2.clone())
197            .expect("The original calibration should have been replaced.");
198        assert_eq!(replaced, calib);
199        assert_eq!(set.len(), 1);
200        assert!(set.iter().all(|item| item == &calib2));
201    }
202
203    #[test]
204    fn test_remove_signature() {
205        let mut set = CalibrationSet::new();
206        let calib = TestCalibration::new("Original", None);
207        set.replace(calib.clone());
208        assert!(set.remove(&calib.signature()));
209        assert!(set.is_empty());
210    }
211
212    #[test]
213    fn test_order_sensitive_equality() {
214        let mut set1 = CalibrationSet::new();
215        let mut set2 = CalibrationSet::new();
216        let calib1 = TestCalibration::new("1", None);
217        let calib2 = TestCalibration::new("2", None);
218        set1.extend(vec![calib1.clone(), calib2.clone()]);
219        set2.extend(vec![calib2, calib1]); // Reverse order
220        assert_ne!(set1, set2)
221    }
222
223    #[test]
224    fn test_maintains_insert_order() {
225        let calibs = vec![
226            TestCalibration::new("1", None),
227            TestCalibration::new("2", None),
228            TestCalibration::new("3", None),
229        ];
230        let set = CalibrationSet::from(calibs.clone());
231        let calibs_from_set: Vec<TestCalibration> = set.into_iter().collect();
232        assert_eq!(calibs_from_set, calibs);
233    }
234
235    #[test]
236    fn test_with_capacity() {
237        let capacity = 10;
238        let set: CalibrationSet<TestCalibration> = CalibrationSet::with_capacity(capacity);
239        assert_eq!(set.capacity(), capacity);
240    }
241}