1#![deny(clippy::unwrap_used)]
10
11use anyhow::{bail, Result};
12use std::{
13 cell::RefCell,
14 collections::HashMap,
15 ffi::{CStr, CString},
16};
17
18struct RawCStrs(RefCell<HashMap<String, *mut i8>>);
19
20impl Drop for RawCStrs {
21 fn drop(&mut self) {
22 self.0.borrow_mut().iter_mut().for_each(|(_, c)| unsafe {
23 #[cfg(target_arch = "aarch64")]
24 drop(CString::from_raw((*c) as *mut u8));
25 #[cfg(not(target_arch = "aarch64"))]
26 drop(CString::from_raw(*c));
27 });
28 self.0.borrow_mut().clear();
29 }
30}
31
32thread_local! {
33 static RAW_CSTRS: RawCStrs = RawCStrs(RefCell::new(HashMap::new()));
34}
35
36pub fn raw_cstr<S>(str: S) -> Result<*mut i8>
50where
51 S: AsRef<str>,
52{
53 RAW_CSTRS.with(|rc| {
54 let mut raw_cstrs_map = rc.0.borrow_mut();
55 let saved = raw_cstrs_map.get(str.as_ref());
56
57 if let Some(saved) = saved {
58 Ok(*saved)
59 } else {
60 #[cfg(target_arch = "aarch64")]
61 let raw = CString::new(str.as_ref())?.into_raw() as *mut i8;
62 #[cfg(not(target_arch = "aarch64"))]
63 let raw = CString::new(str.as_ref())?.into_raw();
64 raw_cstrs_map.insert(str.as_ref().to_string(), raw);
65 Ok(raw)
66 }
67 })
68}
69
70pub trait AsRawCstr {
72 fn as_raw_cstr(&self) -> Result<*mut i8>;
74}
75
76impl AsRawCstr for &'static [u8] {
77 fn as_raw_cstr(&self) -> Result<*mut i8> {
79 if self.last().is_some_and(|l| *l == 0) {
80 Ok(self.as_ptr() as *const i8 as *mut i8)
81 } else {
82 bail!("Empty slice or last element is nonzero: {:?}", self);
83 }
84 }
85}
86
87impl AsRawCstr for *mut i8 {
88 fn as_raw_cstr(&self) -> Result<*mut i8> {
89 Ok(*self)
90 }
91}
92
93impl AsRawCstr for &str {
94 fn as_raw_cstr(&self) -> Result<*mut i8> {
95 raw_cstr(self)
96 }
97}
98
99impl AsRawCstr for String {
100 fn as_raw_cstr(&self) -> Result<*mut i8> {
101 raw_cstr(self)
102 }
103}
104
105impl AsRawCstr for CString {
106 fn as_raw_cstr(&self) -> Result<*mut i8> {
107 raw_cstr(self.to_str()?)
109 }
110}
111
112impl AsRawCstr for CStr {
113 fn as_raw_cstr(&self) -> Result<*mut i8> {
114 raw_cstr(self.to_str()?)
116 }
117}
118
119impl AsRawCstr for &'static CStr {
120 fn as_raw_cstr(&self) -> Result<*mut i8> {
121 return Ok(self.as_ptr() as *mut _);
124 }
125}