qir_stdlib/
lib.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3#![deny(clippy::all, clippy::pedantic)]
4#![allow(clippy::missing_safety_doc)]
5#![allow(clippy::missing_panics_doc)]
6
7//! # Rust Implementation for Quantum Intermediate Representation
8//! This library implements the classical runtime functions described in the [QIR specification](https://github.com/qir-alliance/qir-spec).
9
10// FUTURE: We should add microbenchmarks to verify behavior of these APIs and have a baseline on how changes affect
11// peformance of the APIs.
12
13pub mod arrays;
14pub mod bigints;
15pub mod callables;
16pub mod math;
17pub mod output_recording;
18pub mod range_support;
19pub mod strings;
20pub mod tuples;
21
22use std::{
23    ffi::CString,
24    mem::{self, ManuallyDrop},
25    rc::{Rc, Weak},
26};
27
28use output_recording::record_output_str;
29
30/// Utility used for managing refcounted items.
31unsafe fn update_counts<T>(raw_rc: *const T, update: i32, is_alias: bool) {
32    let mut remaining = update;
33    while remaining != 0 {
34        let rc = ManuallyDrop::new(Rc::from_raw(raw_rc));
35        if remaining > 0 {
36            if is_alias {
37                // Create and leak new downgraded instances to increment the weak count on the contained item.
38                mem::forget(Rc::downgrade(&rc));
39            } else {
40                Rc::increment_strong_count(raw_rc);
41            }
42
43            remaining -= 1;
44        } else {
45            if is_alias {
46                // Create and drop downgraded instances to decrement the weak count on contained item.
47                let w = Weak::into_raw(Rc::downgrade(&rc));
48
49                // Need to drop two for a net decrement, since above line increments.
50                drop(Weak::from_raw(w));
51                drop(Weak::from_raw(w));
52            } else {
53                Rc::decrement_strong_count(raw_rc);
54            }
55
56            remaining += 1;
57        }
58    }
59}
60
61#[derive(Debug, Copy, Clone)]
62#[repr(i8)]
63pub enum Pauli {
64    I = 0,
65    X = 1,
66    Z = 2,
67    Y = 3,
68}
69
70#[no_mangle]
71pub extern "C" fn __quantum__rt__memory_allocate(size: u64) -> *mut u8 {
72    (vec![
73        0_u8;
74        size.try_into()
75            .expect("Memory size is too large for `usize` type on this platform.")
76    ])
77    .leak()
78    .as_mut_ptr()
79}
80
81#[cfg(feature = "fail-support")]
82#[no_mangle]
83pub unsafe extern "C" fn __quantum__rt__fail(str: *const CString) {
84    __quantum__rt__message(str);
85    panic!("{}", (*str).to_str().expect("Unable to convert string"));
86}
87
88#[cfg(feature = "message-support")]
89#[no_mangle]
90pub unsafe extern "C" fn __quantum__rt__message(str: *const CString) {
91    record_output_str(&format!(
92        "INFO\t{}",
93        (*str)
94            .to_str()
95            .expect("Unable to convert input string")
96            .escape_default()
97    ))
98    .expect("Failed to write message output");
99}
100
101#[cfg(test)]
102mod tests {
103    use super::*;
104
105    #[test]
106    fn test_memory_allocate() {
107        let size = 10;
108        let mem = __quantum__rt__memory_allocate(size as u64);
109        unsafe {
110            for val in Vec::from_raw_parts(mem, size, size) {
111                assert_eq!(val, 0);
112            }
113        }
114    }
115
116    #[ignore = "Test triggers a panic during unwinding"]
117    #[test]
118    #[should_panic(expected = "FAIL")]
119    fn test_fail() {
120        let str = CString::new("FAIL").unwrap();
121        unsafe {
122            __quantum__rt__fail(&str);
123        }
124    }
125
126    #[test]
127    fn test_message() {
128        let str = CString::new("Message").unwrap();
129        unsafe {
130            __quantum__rt__message(&str);
131        }
132        // message should not consume string, so check that it's value is still correct.
133        assert_eq!(str.to_str().unwrap(), "Message");
134    }
135}