1use crate::{strings::convert, update_counts};
5use std::{mem::ManuallyDrop, rc::Rc};
6
7#[cfg(not(feature = "fail-support"))]
8#[allow(improper_ctypes)]
9extern "C" {
10 fn __quantum__rt__fail(str: *const std::ffi::CString);
11}
12
13#[cfg(feature = "fail-support")]
14use crate::__quantum__rt__fail;
15
16#[derive(Debug, Clone)]
17pub struct QirArray {
18 pub(crate) elem_size: usize,
19 pub(crate) data: Vec<u8>,
20}
21
22#[unsafe(no_mangle)]
23pub extern "C" fn __quantum__rt__array_create_1d(elem_size: u32, count: u64) -> *const QirArray {
24 let elem_size = elem_size
25 .try_into()
26 .expect("The `elem_size` argument should fit in the `usize` type for this platform.");
27 let count: usize = count
28 .try_into()
29 .expect("The `count` argument should fit in the `usize` type for this platform.");
30 let data = vec![0_u8; elem_size * count];
31 Rc::into_raw(Rc::new(QirArray { elem_size, data }))
32}
33
34#[unsafe(no_mangle)]
35pub unsafe extern "C" fn __quantum__rt__array_copy(
36 arr: *const QirArray,
37 force: bool,
38) -> *const QirArray {
39 unsafe {
40 let rc = ManuallyDrop::new(Rc::from_raw(arr));
43 if force || Rc::weak_count(&rc) > 0 {
44 let copy = rc.as_ref().clone();
45 Rc::into_raw(Rc::new(copy))
46 } else {
47 let _ = Rc::into_raw(Rc::clone(&rc));
48 arr
49 }
50 }
51}
52
53#[unsafe(no_mangle)]
54pub unsafe extern "C" fn __quantum__rt__array_concatenate(
55 arr1: *const QirArray,
56 arr2: *const QirArray,
57) -> *const QirArray {
58 unsafe {
59 let array1 = &*arr1;
60 let array2 = &*arr2;
61 if array1.elem_size != array2.elem_size {
62 __quantum__rt__fail(convert(&format!(
63 "Cannot concatenate arrays with differing element sizes: {} vs {}",
64 array1.elem_size, array2.elem_size
65 )));
66 }
67
68 let mut new_array = QirArray {
69 elem_size: array1.elem_size,
70 data: Vec::new(),
71 };
72 new_array.data.resize(array1.data.len(), 0_u8);
73 new_array.data.copy_from_slice(array1.data.as_slice());
74
75 let mut copy = vec![0; array2.data.len()];
76 copy.copy_from_slice(array2.data.as_slice());
77
78 new_array.data.append(&mut copy);
79 Rc::into_raw(Rc::new(new_array))
80 }
81}
82
83#[unsafe(no_mangle)]
84pub unsafe extern "C" fn __quantum__rt__array_get_size_1d(arr: *const QirArray) -> u64 {
85 unsafe {
86 let array = &*arr;
87 let len = array.data.len() / array.elem_size;
88 len.try_into()
89 .expect("Length of array should always fit in a 64-bit integer.")
90 }
91}
92
93#[unsafe(no_mangle)]
94pub unsafe extern "C" fn __quantum__rt__array_get_element_ptr_1d(
95 arr: *const QirArray,
96 index: u64,
97) -> *mut i8 {
98 unsafe {
99 let array = &*arr;
100 let index: usize = index
101 .try_into()
102 .expect("Indices into an array should fit into the `usize` ");
103 array.data.as_ptr().add(array.elem_size * index) as *mut i8
104 }
105}
106
107#[unsafe(no_mangle)]
108pub unsafe extern "C" fn __quantum__rt__array_update_reference_count(
109 arr: *const QirArray,
110 update: i32,
111) {
112 unsafe {
113 update_counts(arr, update, false);
114 }
115}
116
117#[unsafe(no_mangle)]
118pub unsafe extern "C" fn __quantum__rt__array_update_alias_count(
119 arr: *const QirArray,
120 update: i32,
121) {
122 unsafe {
123 update_counts(arr, update, true);
124 }
125}
126
127#[cfg(test)]
128mod tests {
129 use std::{convert::TryInto, mem::size_of};
130
131 use super::*;
132
133 #[test]
134 fn test_array_creation_simple() {
135 let arr = __quantum__rt__array_create_1d(1, 3);
136 unsafe {
137 assert_eq!(__quantum__rt__array_get_size_1d(arr), 3);
138 __quantum__rt__array_update_reference_count(arr, -1);
141 }
142 }
143
144 #[test]
145 fn test_array_item_zero_init() {
146 let arr = __quantum__rt__array_create_1d(1, 3);
147 unsafe {
148 assert_eq!(__quantum__rt__array_get_size_1d(arr), 3);
149 assert_eq!(*__quantum__rt__array_get_element_ptr_1d(arr, 0), 0);
151 assert_eq!(*__quantum__rt__array_get_element_ptr_1d(arr, 1), 0);
152 assert_eq!(*__quantum__rt__array_get_element_ptr_1d(arr, 2), 0);
153 __quantum__rt__array_update_reference_count(arr, -1);
154 }
155 }
156
157 #[test]
158 fn test_array_item_updates() {
159 let arr = __quantum__rt__array_create_1d(1, 3);
160 unsafe {
161 assert_eq!(__quantum__rt__array_get_size_1d(arr), 3);
162 let first = __quantum__rt__array_get_element_ptr_1d(arr, 0);
164 assert_eq!(*__quantum__rt__array_get_element_ptr_1d(arr, 0), 0);
165 *first = 42;
166 assert_eq!(*__quantum__rt__array_get_element_ptr_1d(arr, 0), 42);
167 let second = __quantum__rt__array_get_element_ptr_1d(arr, 1);
168 assert_eq!(*__quantum__rt__array_get_element_ptr_1d(arr, 1), 0);
169 *second = 31;
170 assert_eq!(*__quantum__rt__array_get_element_ptr_1d(arr, 1), 31);
171 let third = __quantum__rt__array_get_element_ptr_1d(arr, 2);
172 assert_eq!(*__quantum__rt__array_get_element_ptr_1d(arr, 2), 0);
173 *third = 20;
174 assert_eq!(*__quantum__rt__array_get_element_ptr_1d(arr, 2), 20);
175 __quantum__rt__array_update_reference_count(arr, -1);
176 }
177 }
178
179 #[test]
180 fn test_array_copy() {
181 let arr = __quantum__rt__array_create_1d(1, 3);
182 unsafe {
183 assert_eq!(__quantum__rt__array_get_size_1d(arr), 3);
184 let first = __quantum__rt__array_get_element_ptr_1d(arr, 0);
185 assert_eq!(*__quantum__rt__array_get_element_ptr_1d(arr, 0), 0);
186 *first = 42;
187 assert_eq!(*__quantum__rt__array_get_element_ptr_1d(arr, 0), 42);
188 let second = __quantum__rt__array_get_element_ptr_1d(arr, 1);
189 assert_eq!(*__quantum__rt__array_get_element_ptr_1d(arr, 1), 0);
190 *second = 31;
191 assert_eq!(*__quantum__rt__array_get_element_ptr_1d(arr, 1), 31);
192 let arr2 = __quantum__rt__array_copy(arr, true);
194 assert_eq!(__quantum__rt__array_get_size_1d(arr2), 3);
195 assert_eq!(*__quantum__rt__array_get_element_ptr_1d(arr2, 0), 42);
196 assert_eq!(*__quantum__rt__array_get_element_ptr_1d(arr2, 1), 31);
197 let third = __quantum__rt__array_get_element_ptr_1d(arr, 2);
200 assert_eq!(*__quantum__rt__array_get_element_ptr_1d(arr, 2), 0);
201 *third = 20;
202 assert_eq!(*__quantum__rt__array_get_element_ptr_1d(arr, 2), 20);
203 assert_eq!(*__quantum__rt__array_get_element_ptr_1d(arr2, 2), 0);
204 __quantum__rt__array_update_reference_count(arr, -1);
207 assert_eq!(*__quantum__rt__array_get_element_ptr_1d(arr2, 0), 42);
208 assert_eq!(*__quantum__rt__array_get_element_ptr_1d(arr2, 1), 31);
209 __quantum__rt__array_update_reference_count(arr2, -1);
210 }
211 }
212
213 #[test]
214 fn test_array_concat() {
215 let arr = __quantum__rt__array_create_1d(1, 3);
216 unsafe {
217 assert_eq!(__quantum__rt__array_get_size_1d(arr), 3);
218 let first = __quantum__rt__array_get_element_ptr_1d(arr, 0);
219 assert_eq!(*__quantum__rt__array_get_element_ptr_1d(arr, 0), 0);
220 *first = 42;
221 assert_eq!(*__quantum__rt__array_get_element_ptr_1d(arr, 0), 42);
222 let second = __quantum__rt__array_get_element_ptr_1d(arr, 1);
223 assert_eq!(*__quantum__rt__array_get_element_ptr_1d(arr, 1), 0);
224 *second = 31;
225 assert_eq!(*__quantum__rt__array_get_element_ptr_1d(arr, 1), 31);
226 let arr2 = __quantum__rt__array_copy(arr, true);
228 assert_eq!(__quantum__rt__array_get_size_1d(arr2), 3);
229 assert_eq!(*__quantum__rt__array_get_element_ptr_1d(arr2, 0), 42);
230 assert_eq!(*__quantum__rt__array_get_element_ptr_1d(arr2, 1), 31);
231 let arr3 = __quantum__rt__array_concatenate(arr, arr2);
233 assert_eq!(__quantum__rt__array_get_size_1d(arr3), 6);
234 assert_eq!(*__quantum__rt__array_get_element_ptr_1d(arr3, 0), 42);
235 assert_eq!(*__quantum__rt__array_get_element_ptr_1d(arr3, 1), 31);
236 assert_eq!(*__quantum__rt__array_get_element_ptr_1d(arr3, 2), 0);
237 assert_eq!(*__quantum__rt__array_get_element_ptr_1d(arr3, 3), 42);
238 assert_eq!(*__quantum__rt__array_get_element_ptr_1d(arr3, 4), 31);
239 assert_eq!(*__quantum__rt__array_get_element_ptr_1d(arr3, 5), 0);
240 __quantum__rt__array_update_reference_count(arr, -1);
243 __quantum__rt__array_update_reference_count(arr2, -1);
244 assert_eq!(*__quantum__rt__array_get_element_ptr_1d(arr3, 0), 42);
245 assert_eq!(*__quantum__rt__array_get_element_ptr_1d(arr3, 1), 31);
246 assert_eq!(*__quantum__rt__array_get_element_ptr_1d(arr3, 2), 0);
247 assert_eq!(*__quantum__rt__array_get_element_ptr_1d(arr3, 3), 42);
248 assert_eq!(*__quantum__rt__array_get_element_ptr_1d(arr3, 4), 31);
249 assert_eq!(*__quantum__rt__array_get_element_ptr_1d(arr3, 5), 0);
250 __quantum__rt__array_update_reference_count(arr3, -1);
251 }
252 }
253
254 #[allow(clippy::cast_ptr_alignment)]
255 #[test]
256 fn test_array_creation_large_size() {
257 struct Data {
259 first: i64,
260 second: i64,
261 third: i64,
262 }
263 let arr = __quantum__rt__array_create_1d(size_of::<Data>().try_into().unwrap(), 3);
264 unsafe {
265 assert_eq!(__quantum__rt__array_get_size_1d(arr), 3);
266 let first = __quantum__rt__array_get_element_ptr_1d(arr, 0).cast::<Data>();
267 *first = Data {
268 first: 1,
269 second: 2,
270 third: 3,
271 };
272 let second = __quantum__rt__array_get_element_ptr_1d(arr, 1).cast::<Data>();
273 *second = Data {
274 first: 10,
275 second: 20,
276 third: 30,
277 };
278 let third = __quantum__rt__array_get_element_ptr_1d(arr, 2).cast::<Data>();
279 *third = Data {
280 first: 100,
281 second: 200,
282 third: 300,
283 };
284 assert_eq!(
285 (*(__quantum__rt__array_get_element_ptr_1d(arr, 0).cast::<Data>())).first,
286 1
287 );
288 assert_eq!(
289 (*(__quantum__rt__array_get_element_ptr_1d(arr, 0).cast::<Data>())).second,
290 2
291 );
292 assert_eq!(
293 (*(__quantum__rt__array_get_element_ptr_1d(arr, 0).cast::<Data>())).third,
294 3
295 );
296 assert_eq!(
297 (*(__quantum__rt__array_get_element_ptr_1d(arr, 1).cast::<Data>())).first,
298 10
299 );
300 assert_eq!(
301 (*(__quantum__rt__array_get_element_ptr_1d(arr, 1).cast::<Data>())).second,
302 20
303 );
304 assert_eq!(
305 (*(__quantum__rt__array_get_element_ptr_1d(arr, 1).cast::<Data>())).third,
306 30
307 );
308 assert_eq!(
309 (*(__quantum__rt__array_get_element_ptr_1d(arr, 2).cast::<Data>())).first,
310 100
311 );
312 assert_eq!(
313 (*(__quantum__rt__array_get_element_ptr_1d(arr, 2).cast::<Data>())).second,
314 200
315 );
316 assert_eq!(
317 (*(__quantum__rt__array_get_element_ptr_1d(arr, 2).cast::<Data>())).third,
318 300
319 );
320 __quantum__rt__array_update_reference_count(arr, -1);
321 }
322 }
323}