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
use serde::{Deserialize, Serialize};
use std::fmt;

/// Represents a reference to a qubit.
#[repr(transparent)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct QubitRef(u64);

impl fmt::Display for QubitRef {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

impl Into<String> for QubitRef {
    fn into(self) -> String {
        format!("{}", self.0)
    }
}

impl QubitRef {
    /// Converts the foreign representation of a qubit reference to the
    /// type-safe Rust representation.
    pub fn from_foreign(qubit: u64) -> Option<QubitRef> {
        if qubit == 0 {
            None
        } else {
            Some(QubitRef(qubit as u64))
        }
    }

    /// Converts the type-safe Rust representation of a qubit reference to the
    /// foreign representation.
    pub fn to_foreign(self) -> u64 {
        assert_ne!(self.0, 0);
        self.0 as u64
    }

    /// Converts the type-safe Rust representation of a qubit reference to the
    /// foreign representation.
    pub fn option_to_foreign(qubit: Option<QubitRef>) -> u64 {
        if let Some(x) = qubit {
            x.0 as u64
        } else {
            0
        }
    }
}

/// Struct used to generate new qubit references.
///
/// Qubit references start at 1; 0 is reserved for representing errors/invalid
/// handles on the foreign language interface. The current implementation just
/// counts references up from 1 when a qubit is allocated, i.e. it does not
/// reuse references.
pub struct QubitRefGenerator {
    counter: std::ops::RangeFrom<u64>,
}

impl Default for QubitRefGenerator {
    fn default() -> Self {
        Self::new()
    }
}

impl QubitRefGenerator {
    /// Constructs a new reference generator.
    pub fn new() -> QubitRefGenerator {
        QubitRefGenerator { counter: (1..) }
    }

    /// "Allocates" a number of qubit references.
    pub fn allocate(&mut self, num_qubits: usize) -> Vec<QubitRef> {
        (&mut self.counter).take(num_qubits).map(QubitRef).collect()
    }

    /// "Frees" a number of qubit references.
    ///
    /// Note that this is no-op in the current implementation; freed qubits are
    /// never reused. This function is defined only in case we want to change
    /// that for some reason.
    pub fn free(&mut self, _qubits: impl IntoIterator<Item = QubitRef>) {
        // Intentionally no-op
    }
}

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

    #[test]
    fn construct_generator() {
        let mut q1 = QubitRefGenerator::default();
        let mut q2 = QubitRefGenerator::new();
        assert_eq!(q1.allocate(2), q2.allocate(2));
    }

    #[test]
    fn alloc_free() {
        let mut q = QubitRefGenerator::default();
        let qrefs = q.allocate(1);
        assert_eq!(qrefs.len(), 1);
        q.free(vec![QubitRef::from_foreign(4).unwrap()]);
        let qrefs = q.allocate(1);
        assert_eq!(qrefs[0], QubitRef::from_foreign(2).unwrap());
    }

    #[test]
    fn convert_qrefs() {
        let mut q = QubitRefGenerator::new();

        let qr = QubitRef::from_foreign(0);
        assert_eq!(qr, None);

        let qr = QubitRef::from_foreign(1).unwrap();
        assert_eq!(qr, (q.allocate(1))[0]);

        assert_eq!(42, QubitRef::from_foreign(42).unwrap().to_foreign());

        assert_eq!(0, QubitRef::option_to_foreign(None));
        assert_eq!(
            42,
            QubitRef::option_to_foreign(Some(QubitRef::from_foreign(42).unwrap()))
        );
    }

    #[test]
    #[should_panic]
    fn convert_zero() {
        let _ = QubitRef(0).to_foreign();
    }

    #[test]
    fn display_qref() {
        let qubits = QubitRefGenerator::default().allocate(1);
        assert_eq!(qubits[0].to_string(), "1");
        let s: String = qubits[0].into();
        assert_eq!(s, "1".to_string());
    }

}