quil_rs/program/
calibration_set.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
use crate::instruction::CalibrationSignature;

/// A [`CalibrationSet`] is a collection of calibration instructions that respect how
/// calibrations work in a Quil program.
///
/// During calibration expansion, Calibrations are matched to instructions using their unique
/// [`CalibrationSignature`]. This means only one calibration can be matched to a particular
/// instruction. While the Quil specification doesn't explicitly define the behavior of
/// signature conflicts, [`CalibrationSet`] takes the liberty of only allowing one calibration
/// per [`CalibrationSignature`].
///
/// Calibrations maintain insertion order
#[derive(Clone, Debug, PartialEq)]
pub struct CalibrationSet<T> {
    // The amount of calibrations in a program tends to be small enough that a Vec is more
    // performant than a typical set.
    // Sets also have trait bounds that `Instruction`s don't meet, which hampers utility.
    data: Vec<T>,
}

impl<T> Default for CalibrationSet<T>
where
    T: CalibrationSignature,
{
    fn default() -> Self {
        Self::new()
    }
}

impl<T> IntoIterator for CalibrationSet<T> {
    type IntoIter = std::vec::IntoIter<Self::Item>;
    type Item = T;

    fn into_iter(self) -> Self::IntoIter {
        self.data.into_iter()
    }
}

impl<T> From<Vec<T>> for CalibrationSet<T>
where
    T: CalibrationSignature,
{
    fn from(data: Vec<T>) -> Self {
        let mut set = Self::with_capacity(data.len());
        for element in data {
            set.replace(element);
        }
        set
    }
}

impl<T> CalibrationSet<T>
where
    T: CalibrationSignature,
{
    /// Creates an empty [`ProgramCalibrationSet`].
    pub fn new() -> Self {
        Self { data: Vec::new() }
    }

    /// Creates a [`InnerCalibrationSet`] with the specified capacity.
    pub fn with_capacity(capacity: usize) -> Self {
        Self {
            data: Vec::with_capacity(capacity),
        }
    }

    /// Returns the capacity of the [`ProgramCalibrationSet`].
    pub fn capacity(&self) -> usize {
        self.data.capacity()
    }

    /// Returns the length of the [`ProgramCalibrationSet`].
    pub fn len(&self) -> usize {
        self.data.len()
    }

    /// Returns whether the [`ProgramCalibrationSet`] is empty.
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns an iterator of references to the values in the set.
    pub fn iter(&self) -> std::slice::Iter<'_, T> {
        self.data.iter()
    }

    /// Get a reference to a value that has a matching signature, if it exists.
    pub fn get(&self, signature: &<T as CalibrationSignature>::Signature<'_>) -> Option<&T> {
        if let Some(index) = self.signature_position(signature) {
            Some(&self.data[index])
        } else {
            None
        }
    }

    /// Adds a value to the set, replacing and returning an existing value with a matching
    /// [`CalibrationSignature`], if it exists.
    pub fn replace(&mut self, value: T) -> Option<T> {
        let position = self.signature_position(&value.signature());
        if let Some(index) = position {
            let replaced = std::mem::replace(&mut self.data[index], value);
            Some(replaced)
        } else {
            self.data.push(value);
            None
        }
    }

    /// Removes a value from the set. Returns whether the value was present in the set.
    pub fn remove(&mut self, signature: &<T as CalibrationSignature>::Signature<'_>) -> bool {
        if let Some(index) = self.signature_position(signature) {
            self.data.remove(index);
            true
        } else {
            false
        }
    }

    /// Returns the index of an element whose [`CalibrationSignature`] matches the given value, if one exists.
    fn signature_position(
        &self,
        signature: &<T as CalibrationSignature>::Signature<'_>,
    ) -> Option<usize> {
        for (i, element) in self.data.iter().enumerate() {
            if element.has_signature(signature) {
                return Some(i);
            }
        }

        None
        //self.data
        //    .iter()
        //    .position(move |element| { signature == element.signature() })
    }
}

impl<T> Extend<T> for CalibrationSet<T>
where
    T: CalibrationSignature,
{
    fn extend<I>(&mut self, iter: I)
    where
        I: IntoIterator<Item = T>,
    {
        for value in iter {
            self.replace(value);
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::instruction::CalibrationSignature;

    #[derive(Clone, Debug, PartialEq)]
    struct TestCalibration {
        signature: String,
        /// Optional byte, can be used to differentiate between two TestCalibrations with the same
        /// signature.
        data: Option<u8>,
    }

    impl TestCalibration {
        fn new(signature: &str, data: Option<u8>) -> Self {
            Self {
                signature: signature.to_string(),
                data,
            }
        }
    }

    impl CalibrationSignature for TestCalibration {
        type Signature<'a> = &'a str;

        fn signature(&self) -> Self::Signature<'_> {
            self.signature.as_str()
        }

        fn has_signature(&self, signature: &Self::Signature<'_>) -> bool {
            self.signature == *signature
        }
    }

    #[test]
    fn test_replace() {
        let mut set = CalibrationSet::new();
        let calib = TestCalibration::new("Signature", None);
        set.replace(calib.clone());
        assert_eq!(set.len(), 1);
        assert!(set.iter().all(|item| item == &calib));

        let calib2 = TestCalibration::new("Signature", Some(42));
        let replaced = set
            .replace(calib2.clone())
            .expect("The original calibration should have been replaced.");
        assert_eq!(replaced, calib);
        assert_eq!(set.len(), 1);
        assert!(set.iter().all(|item| item == &calib2));
    }

    #[test]
    fn test_remove_signature() {
        let mut set = CalibrationSet::new();
        let calib = TestCalibration::new("Original", None);
        set.replace(calib.clone());
        assert!(set.remove(&calib.signature()));
        assert!(set.is_empty());
    }

    #[test]
    fn test_order_sensitive_equality() {
        let mut set1 = CalibrationSet::new();
        let mut set2 = CalibrationSet::new();
        let calib1 = TestCalibration::new("1", None);
        let calib2 = TestCalibration::new("2", None);
        set1.extend(vec![calib1.clone(), calib2.clone()]);
        set2.extend(vec![calib2, calib1]); // Reverse order
        assert_ne!(set1, set2)
    }

    #[test]
    fn test_maintains_insert_order() {
        let calibs = vec![
            TestCalibration::new("1", None),
            TestCalibration::new("2", None),
            TestCalibration::new("3", None),
        ];
        let set = CalibrationSet::from(calibs.clone());
        let calibs_from_set: Vec<TestCalibration> = set.into_iter().collect();
        assert_eq!(calibs_from_set, calibs);
    }

    #[test]
    fn test_with_capacity() {
        let capacity = 10;
        let set: CalibrationSet<TestCalibration> = CalibrationSet::with_capacity(capacity);
        assert_eq!(set.capacity(), capacity);
    }
}