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