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    unsafe {
33        let mut remaining = update;
34        while remaining != 0 {
35            let rc = ManuallyDrop::new(Rc::from_raw(raw_rc));
36            if remaining > 0 {
37                if is_alias {
38                    // Create and leak new downgraded instances to increment the weak count on the contained item.
39                    mem::forget(Rc::downgrade(&rc));
40                } else {
41                    Rc::increment_strong_count(raw_rc);
42                }
43
44                remaining -= 1;
45            } else {
46                if is_alias {
47                    // Create and drop downgraded instances to decrement the weak count on contained item.
48                    let w = Weak::into_raw(Rc::downgrade(&rc));
49
50                    // Need to drop two for a net decrement, since above line increments.
51                    drop(Weak::from_raw(w));
52                    drop(Weak::from_raw(w));
53                } else {
54                    Rc::decrement_strong_count(raw_rc);
55                }
56
57                remaining += 1;
58            }
59        }
60    }
61}
62
63#[derive(Debug, Copy, Clone)]
64#[repr(i8)]
65pub enum Pauli {
66    I = 0,
67    X = 1,
68    Z = 2,
69    Y = 3,
70}
71
72#[unsafe(no_mangle)]
73pub extern "C" fn __quantum__rt__memory_allocate(size: u64) -> *mut u8 {
74    (vec![
75        0_u8;
76        size.try_into()
77            .expect("Memory size is too large for `usize` type on this platform.")
78    ])
79    .leak()
80    .as_mut_ptr()
81}
82
83#[cfg(feature = "fail-support")]
84#[unsafe(no_mangle)]
85pub unsafe extern "C" fn __quantum__rt__fail(str: *const CString) {
86    unsafe {
87        __quantum__rt__message(str);
88        panic!("{}", (*str).to_str().expect("Unable to convert string"));
89    }
90}
91
92#[cfg(feature = "message-support")]
93#[unsafe(no_mangle)]
94pub unsafe extern "C" fn __quantum__rt__message(str: *const CString) {
95    unsafe {
96        record_output_str(&format!(
97            "INFO\t{}",
98            (*str)
99                .to_str()
100                .expect("Unable to convert input string")
101                .escape_default()
102        ))
103        .expect("Failed to write message output");
104    }
105}
106
107#[cfg(test)]
108mod tests {
109    use super::*;
110
111    #[test]
112    fn test_memory_allocate() {
113        let size = 10;
114        let mem = __quantum__rt__memory_allocate(size as u64);
115        unsafe {
116            for val in Vec::from_raw_parts(mem, size, size) {
117                assert_eq!(val, 0);
118            }
119        }
120    }
121
122    #[ignore = "Test triggers a panic during unwinding"]
123    #[test]
124    #[should_panic(expected = "FAIL")]
125    fn test_fail() {
126        let str = CString::new("FAIL").unwrap();
127        unsafe {
128            __quantum__rt__fail(&raw const str);
129        }
130    }
131
132    #[test]
133    fn test_message() {
134        let str = CString::new("Message").unwrap();
135        unsafe {
136            __quantum__rt__message(&raw const str);
137        }
138        // message should not consume string, so check that it's value is still correct.
139        assert_eq!(str.to_str().unwrap(), "Message");
140    }
141}