1use crate::update_counts;
5use crate::Pauli;
6use num_bigint::BigInt;
7use std::{
8 ffi::{CStr, CString},
9 os::raw::{c_char, c_double},
10 rc::Rc,
11};
12
13#[no_mangle]
14pub unsafe extern "C" fn __quantum__rt__string_create(str: *mut c_char) -> *const CString {
15 let cstring = CString::new(CStr::from_ptr(str).to_owned()).expect("Failed to create %String");
16 Rc::into_raw(Rc::new(cstring))
17}
18
19#[no_mangle]
20pub unsafe extern "C" fn __quantum__rt__string_get_data(str: *const CString) -> *const c_char {
21 (*str).as_bytes_with_nul().as_ptr().cast::<c_char>()
22}
23
24#[no_mangle]
25pub unsafe extern "C" fn __quantum__rt__string_get_length(str: *const CString) -> u32 {
26 (*str)
27 .as_bytes()
28 .len()
29 .try_into()
30 .expect("String length is too large for 32-bit integer.")
31}
32
33#[no_mangle]
34pub unsafe extern "C" fn __quantum__rt__string_update_reference_count(
35 str: *const CString,
36 update: i32,
37) {
38 update_counts(str, update, false);
39}
40
41#[no_mangle]
42pub unsafe extern "C" fn __quantum__rt__string_concatenate(
43 s1: *const CString,
44 s2: *const CString,
45) -> *const CString {
46 let mut new_str = (*s1).clone().into_bytes();
47 new_str.extend_from_slice((*s2).to_bytes());
48
49 Rc::into_raw(Rc::new(
50 CString::new(new_str).expect("Unable to convert string"),
51 ))
52}
53
54#[no_mangle]
55pub unsafe extern "C" fn __quantum__rt__string_equal(
56 s1: *const CString,
57 s2: *const CString,
58) -> bool {
59 *s1 == *s2
60}
61
62pub(crate) fn convert<T>(input: &T) -> *const CString
63where
64 T: ToString,
65{
66 unsafe {
67 __quantum__rt__string_create(
68 CString::new(input.to_string())
69 .expect("Unable to allocate string for conversion.")
70 .as_bytes_with_nul()
71 .as_ptr() as *mut c_char,
72 )
73 }
74}
75
76#[no_mangle]
77pub extern "C" fn __quantum__rt__int_to_string(input: i64) -> *const CString {
78 convert(&input)
79}
80
81pub(crate) fn double_to_string(input: c_double) -> String {
82 if (input.floor() - input.ceil()).abs() < c_double::EPSILON {
83 format!("{input:.1}")
86 } else {
87 format!("{input}")
88 }
89}
90
91#[no_mangle]
92pub extern "C" fn __quantum__rt__double_to_string(input: c_double) -> *const CString {
93 convert(&double_to_string(input))
94}
95
96#[no_mangle]
97pub extern "C" fn __quantum__rt__bool_to_string(input: bool) -> *const CString {
98 convert(&input)
99}
100
101#[no_mangle]
102pub extern "C" fn __quantum__rt__pauli_to_string(input: Pauli) -> *const CString {
103 match input {
104 Pauli::I => convert(&"PauliI"),
105 Pauli::X => convert(&"PauliX"),
106 Pauli::Y => convert(&"PauliY"),
107 Pauli::Z => convert(&"PauliZ"),
108 }
109}
110
111#[no_mangle]
112pub unsafe extern "C" fn __quantum__rt__bigint_to_string(input: *const BigInt) -> *const CString {
113 convert(&*input)
114}
115
116#[cfg(test)]
117mod tests {
118 use std::mem::ManuallyDrop;
119
120 use super::*;
121 use crate::bigints::{
122 __quantum__rt__bigint_create_array, __quantum__rt__bigint_create_i64,
123 __quantum__rt__bigint_update_reference_count,
124 };
125
126 #[test]
127 fn test_string_create() {
128 let orig_str = CString::new("Test String").unwrap();
129 let str = unsafe {
130 __quantum__rt__string_create(
131 orig_str.as_bytes_with_nul().as_ptr() as *mut std::ffi::c_char
132 )
133 };
134 assert_eq!(orig_str.to_str().unwrap(), "Test String");
136 drop(orig_str);
137 assert!(!str.is_null());
138 unsafe {
139 assert_eq!(
141 Rc::from_raw(str)
142 .to_str()
143 .expect("Unable to convert input string"),
144 "Test String"
145 );
146 }
147 }
148
149 #[test]
150 fn test_string_get_data() {
151 let str = unsafe {
152 __quantum__rt__string_create(
153 CString::new("Data").unwrap().as_bytes_with_nul().as_ptr() as *mut c_char
154 )
155 };
156 unsafe {
157 assert_eq!(
158 CStr::from_ptr(__quantum__rt__string_get_data(str))
159 .to_str()
160 .unwrap(),
161 "Data"
162 );
163 }
164 unsafe {
165 __quantum__rt__string_update_reference_count(str, -1);
166 }
167 }
168
169 #[test]
170 fn test_string_get_length() {
171 let str = unsafe {
172 __quantum__rt__string_create(
173 CString::new("Data").unwrap().as_bytes_with_nul().as_ptr() as *mut c_char
174 )
175 };
176 assert_eq!(unsafe { __quantum__rt__string_get_length(str) }, 4);
177 unsafe {
178 __quantum__rt__string_update_reference_count(str, -1);
179 }
180 }
181
182 #[test]
183 fn test_string_update_reference_count() {
184 unsafe {
185 let str = __quantum__rt__string_create(
186 CString::new("Data").unwrap().as_bytes_with_nul().as_ptr() as *mut c_char,
187 );
188 let rc = ManuallyDrop::new(Rc::from_raw(str));
189 assert_eq!(Rc::strong_count(&rc), 1);
190 __quantum__rt__string_update_reference_count(str, 2);
191 assert_eq!(Rc::strong_count(&rc), 3);
192 __quantum__rt__string_update_reference_count(str, -2);
193 assert_eq!(Rc::strong_count(&rc), 1);
194 __quantum__rt__string_update_reference_count(str, -1);
195 }
196 }
197
198 #[test]
199 fn test_string_concatenate() {
200 unsafe {
201 let str1 = __quantum__rt__string_create(
202 CString::new("Hello").unwrap().as_bytes_with_nul().as_ptr() as *mut c_char,
203 );
204 let str2 = __quantum__rt__string_create(
205 CString::new(", World!")
206 .unwrap()
207 .as_bytes_with_nul()
208 .as_ptr() as *mut c_char,
209 );
210 let str3 = __quantum__rt__string_concatenate(str1, str2);
211 let rc = ManuallyDrop::new(Rc::from_raw(str3));
213 assert_eq!(Rc::strong_count(&rc), 1);
214 assert_eq!(
215 CStr::from_ptr(__quantum__rt__string_get_data(str3))
216 .to_str()
217 .unwrap(),
218 "Hello, World!"
219 );
220 __quantum__rt__string_update_reference_count(str3, -1);
221 let rc = ManuallyDrop::new(Rc::from_raw(str2));
223 assert_eq!(Rc::strong_count(&rc), 1);
224 assert_eq!(
225 CStr::from_ptr(__quantum__rt__string_get_data(str2))
226 .to_str()
227 .unwrap(),
228 ", World!"
229 );
230 __quantum__rt__string_update_reference_count(str2, -1);
231 let rc = ManuallyDrop::new(Rc::from_raw(str1));
232 assert_eq!(Rc::strong_count(&rc), 1);
233 assert_eq!(
234 CStr::from_ptr(__quantum__rt__string_get_data(str1))
235 .to_str()
236 .unwrap(),
237 "Hello"
238 );
239 __quantum__rt__string_update_reference_count(str1, -1);
240 }
241 }
242
243 #[test]
244 fn test_string_equal() {
245 unsafe {
246 let str1 = __quantum__rt__string_create(
247 CString::new("Data").unwrap().as_bytes_with_nul().as_ptr() as *mut c_char,
248 );
249 let str2 = __quantum__rt__string_create(
250 CString::new("Data").unwrap().as_bytes_with_nul().as_ptr() as *mut c_char,
251 );
252 let str3 = __quantum__rt__string_create(
253 CString::new("Not Data")
254 .unwrap()
255 .as_bytes_with_nul()
256 .as_ptr() as *mut c_char,
257 );
258 assert!(__quantum__rt__string_equal(str1, str2));
259 assert!(!__quantum__rt__string_equal(str1, str3));
260 let rc = ManuallyDrop::new(Rc::from_raw(str3));
262 assert_eq!(Rc::strong_count(&rc), 1);
263 assert_eq!(
264 CStr::from_ptr(__quantum__rt__string_get_data(str3))
265 .to_str()
266 .unwrap(),
267 "Not Data"
268 );
269 __quantum__rt__string_update_reference_count(str3, -1);
270 let rc = ManuallyDrop::new(Rc::from_raw(str2));
271 assert_eq!(Rc::strong_count(&rc), 1);
272 assert_eq!(
273 CStr::from_ptr(__quantum__rt__string_get_data(str2))
274 .to_str()
275 .unwrap(),
276 "Data"
277 );
278 __quantum__rt__string_update_reference_count(str2, -1);
279 let rc = ManuallyDrop::new(Rc::from_raw(str1));
280 assert_eq!(Rc::strong_count(&rc), 1);
281 assert_eq!(
282 CStr::from_ptr(__quantum__rt__string_get_data(str1))
283 .to_str()
284 .unwrap(),
285 "Data"
286 );
287 __quantum__rt__string_update_reference_count(str1, -1);
288 }
289 }
290
291 #[test]
292 fn test_to_string() {
293 let str0 = __quantum__rt__int_to_string(42_i64);
294 unsafe {
295 assert_eq!(
296 CStr::from_ptr(__quantum__rt__string_get_data(str0))
297 .to_str()
298 .unwrap(),
299 "42"
300 );
301 }
302 let str1 = __quantum__rt__double_to_string(4.2_f64);
303 unsafe {
304 assert_eq!(
305 CStr::from_ptr(__quantum__rt__string_get_data(str1))
306 .to_str()
307 .unwrap(),
308 "4.2"
309 );
310 }
311 let str1_1 = __quantum__rt__double_to_string(4.0_f64);
312 unsafe {
313 assert_eq!(
314 CStr::from_ptr(__quantum__rt__string_get_data(str1_1))
315 .to_str()
316 .unwrap(),
317 "4.0"
318 );
319 }
320 let str1_2 = __quantum__rt__double_to_string(0.1_f64);
321 unsafe {
322 assert_eq!(
323 CStr::from_ptr(__quantum__rt__string_get_data(str1_2))
324 .to_str()
325 .unwrap(),
326 "0.1"
327 );
328 }
329 let str1_3 = __quantum__rt__double_to_string(0.100_000_000_01_f64);
330 unsafe {
331 assert_eq!(
332 CStr::from_ptr(__quantum__rt__string_get_data(str1_3))
333 .to_str()
334 .unwrap(),
335 "0.10000000001"
336 );
337 }
338 let str2 = __quantum__rt__bool_to_string(false);
339 unsafe {
340 assert_eq!(
341 CStr::from_ptr(__quantum__rt__string_get_data(str2))
342 .to_str()
343 .unwrap(),
344 "false"
345 );
346 }
347 let str3 = __quantum__rt__pauli_to_string(Pauli::Z);
348 unsafe {
349 assert_eq!(
350 CStr::from_ptr(__quantum__rt__string_get_data(str3))
351 .to_str()
352 .unwrap(),
353 "PauliZ"
354 );
355 }
356 let input4 = __quantum__rt__bigint_create_i64(400_002);
357 unsafe {
358 let str4 = __quantum__rt__bigint_to_string(input4);
359 assert_eq!(
360 CStr::from_ptr(__quantum__rt__string_get_data(str4))
361 .to_str()
362 .unwrap(),
363 "400002"
364 );
365 __quantum__rt__string_update_reference_count(str4, -1);
366 }
367 unsafe {
368 let bytes = [0x18, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF3, 0x01];
369 let input5 =
370 __quantum__rt__bigint_create_array(bytes.len().try_into().unwrap(), bytes.as_ptr());
371 let str5 = __quantum__rt__bigint_to_string(input5);
372 assert_eq!(
373 CStr::from_ptr(__quantum__rt__string_get_data(str5))
374 .to_str()
375 .unwrap(),
376 "9223372036854775807000"
377 );
378 __quantum__rt__string_update_reference_count(str0, -1);
379 __quantum__rt__string_update_reference_count(str1, -1);
380 __quantum__rt__string_update_reference_count(str1_1, -1);
381 __quantum__rt__string_update_reference_count(str1_2, -1);
382 __quantum__rt__string_update_reference_count(str1_3, -1);
383 __quantum__rt__string_update_reference_count(str2, -1);
384 __quantum__rt__string_update_reference_count(str3, -1);
385 __quantum__rt__bigint_update_reference_count(input4, -1);
386 __quantum__rt__bigint_update_reference_count(input5, -1);
387 }
388 }
389}