133d722a9Sopenharmony_ciuse crate::actually_private::Private; 233d722a9Sopenharmony_ciuse crate::lossy; 333d722a9Sopenharmony_ci#[cfg(feature = "alloc")] 433d722a9Sopenharmony_ciuse alloc::borrow::Cow; 533d722a9Sopenharmony_ci#[cfg(feature = "alloc")] 633d722a9Sopenharmony_ciuse alloc::string::String; 733d722a9Sopenharmony_ciuse core::cmp::Ordering; 833d722a9Sopenharmony_ciuse core::fmt::{self, Debug, Display}; 933d722a9Sopenharmony_ciuse core::hash::{Hash, Hasher}; 1033d722a9Sopenharmony_ciuse core::marker::{PhantomData, PhantomPinned}; 1133d722a9Sopenharmony_ciuse core::mem::MaybeUninit; 1233d722a9Sopenharmony_ciuse core::pin::Pin; 1333d722a9Sopenharmony_ciuse core::slice; 1433d722a9Sopenharmony_ciuse core::str::{self, Utf8Error}; 1533d722a9Sopenharmony_ci 1633d722a9Sopenharmony_ciextern "C" { 1733d722a9Sopenharmony_ci #[link_name = "cxxbridge1$cxx_string$init"] 1833d722a9Sopenharmony_ci fn string_init(this: &mut MaybeUninit<CxxString>, ptr: *const u8, len: usize); 1933d722a9Sopenharmony_ci #[link_name = "cxxbridge1$cxx_string$destroy"] 2033d722a9Sopenharmony_ci fn string_destroy(this: &mut MaybeUninit<CxxString>); 2133d722a9Sopenharmony_ci #[link_name = "cxxbridge1$cxx_string$data"] 2233d722a9Sopenharmony_ci fn string_data(this: &CxxString) -> *const u8; 2333d722a9Sopenharmony_ci #[link_name = "cxxbridge1$cxx_string$length"] 2433d722a9Sopenharmony_ci fn string_length(this: &CxxString) -> usize; 2533d722a9Sopenharmony_ci #[link_name = "cxxbridge1$cxx_string$clear"] 2633d722a9Sopenharmony_ci fn string_clear(this: Pin<&mut CxxString>); 2733d722a9Sopenharmony_ci #[link_name = "cxxbridge1$cxx_string$reserve_total"] 2833d722a9Sopenharmony_ci fn string_reserve_total(this: Pin<&mut CxxString>, new_cap: usize); 2933d722a9Sopenharmony_ci #[link_name = "cxxbridge1$cxx_string$push"] 3033d722a9Sopenharmony_ci fn string_push(this: Pin<&mut CxxString>, ptr: *const u8, len: usize); 3133d722a9Sopenharmony_ci} 3233d722a9Sopenharmony_ci 3333d722a9Sopenharmony_ci/// Binding to C++ `std::string`. 3433d722a9Sopenharmony_ci/// 3533d722a9Sopenharmony_ci/// # Invariants 3633d722a9Sopenharmony_ci/// 3733d722a9Sopenharmony_ci/// As an invariant of this API and the static analysis of the cxx::bridge 3833d722a9Sopenharmony_ci/// macro, in Rust code we can never obtain a `CxxString` by value. C++'s string 3933d722a9Sopenharmony_ci/// requires a move constructor and may hold internal pointers, which is not 4033d722a9Sopenharmony_ci/// compatible with Rust's move behavior. Instead in Rust code we will only ever 4133d722a9Sopenharmony_ci/// look at a CxxString through a reference or smart pointer, as in `&CxxString` 4233d722a9Sopenharmony_ci/// or `UniquePtr<CxxString>`. 4333d722a9Sopenharmony_ci#[repr(C)] 4433d722a9Sopenharmony_cipub struct CxxString { 4533d722a9Sopenharmony_ci _private: [u8; 0], 4633d722a9Sopenharmony_ci _pinned: PhantomData<PhantomPinned>, 4733d722a9Sopenharmony_ci} 4833d722a9Sopenharmony_ci 4933d722a9Sopenharmony_ci/// Construct a C++ std::string on the Rust stack. 5033d722a9Sopenharmony_ci/// 5133d722a9Sopenharmony_ci/// # Syntax 5233d722a9Sopenharmony_ci/// 5333d722a9Sopenharmony_ci/// In statement position: 5433d722a9Sopenharmony_ci/// 5533d722a9Sopenharmony_ci/// ``` 5633d722a9Sopenharmony_ci/// # use cxx::let_cxx_string; 5733d722a9Sopenharmony_ci/// # let expression = ""; 5833d722a9Sopenharmony_ci/// let_cxx_string!(var = expression); 5933d722a9Sopenharmony_ci/// ``` 6033d722a9Sopenharmony_ci/// 6133d722a9Sopenharmony_ci/// The `expression` may have any type that implements `AsRef<[u8]>`. Commonly 6233d722a9Sopenharmony_ci/// it will be a string literal, but for example `&[u8]` and `String` would work 6333d722a9Sopenharmony_ci/// as well. 6433d722a9Sopenharmony_ci/// 6533d722a9Sopenharmony_ci/// The macro expands to something resembling `let $var: Pin<&mut CxxString> = 6633d722a9Sopenharmony_ci/// /*???*/;`. The resulting [`Pin`] can be deref'd to `&CxxString` as needed. 6733d722a9Sopenharmony_ci/// 6833d722a9Sopenharmony_ci/// # Example 6933d722a9Sopenharmony_ci/// 7033d722a9Sopenharmony_ci/// ``` 7133d722a9Sopenharmony_ci/// use cxx::{let_cxx_string, CxxString}; 7233d722a9Sopenharmony_ci/// 7333d722a9Sopenharmony_ci/// fn f(s: &CxxString) {/* ... */} 7433d722a9Sopenharmony_ci/// 7533d722a9Sopenharmony_ci/// fn main() { 7633d722a9Sopenharmony_ci/// let_cxx_string!(s = "example"); 7733d722a9Sopenharmony_ci/// f(&s); 7833d722a9Sopenharmony_ci/// } 7933d722a9Sopenharmony_ci/// ``` 8033d722a9Sopenharmony_ci#[macro_export] 8133d722a9Sopenharmony_cimacro_rules! let_cxx_string { 8233d722a9Sopenharmony_ci ($var:ident = $value:expr $(,)?) => { 8333d722a9Sopenharmony_ci let mut cxx_stack_string = $crate::private::StackString::new(); 8433d722a9Sopenharmony_ci #[allow(unused_mut, unused_unsafe)] 8533d722a9Sopenharmony_ci let mut $var = match $value { 8633d722a9Sopenharmony_ci let_cxx_string => unsafe { cxx_stack_string.init(let_cxx_string) }, 8733d722a9Sopenharmony_ci }; 8833d722a9Sopenharmony_ci }; 8933d722a9Sopenharmony_ci} 9033d722a9Sopenharmony_ci 9133d722a9Sopenharmony_ciimpl CxxString { 9233d722a9Sopenharmony_ci /// `CxxString` is not constructible via `new`. Instead, use the 9333d722a9Sopenharmony_ci /// [`let_cxx_string!`] macro. 9433d722a9Sopenharmony_ci pub fn new<T: Private>() -> Self { 9533d722a9Sopenharmony_ci unreachable!() 9633d722a9Sopenharmony_ci } 9733d722a9Sopenharmony_ci 9833d722a9Sopenharmony_ci /// Returns the length of the string in bytes. 9933d722a9Sopenharmony_ci /// 10033d722a9Sopenharmony_ci /// Matches the behavior of C++ [std::string::size][size]. 10133d722a9Sopenharmony_ci /// 10233d722a9Sopenharmony_ci /// [size]: https://en.cppreference.com/w/cpp/string/basic_string/size 10333d722a9Sopenharmony_ci pub fn len(&self) -> usize { 10433d722a9Sopenharmony_ci unsafe { string_length(self) } 10533d722a9Sopenharmony_ci } 10633d722a9Sopenharmony_ci 10733d722a9Sopenharmony_ci /// Returns true if `self` has a length of zero bytes. 10833d722a9Sopenharmony_ci /// 10933d722a9Sopenharmony_ci /// Matches the behavior of C++ [std::string::empty][empty]. 11033d722a9Sopenharmony_ci /// 11133d722a9Sopenharmony_ci /// [empty]: https://en.cppreference.com/w/cpp/string/basic_string/empty 11233d722a9Sopenharmony_ci pub fn is_empty(&self) -> bool { 11333d722a9Sopenharmony_ci self.len() == 0 11433d722a9Sopenharmony_ci } 11533d722a9Sopenharmony_ci 11633d722a9Sopenharmony_ci /// Returns a byte slice of this string's contents. 11733d722a9Sopenharmony_ci pub fn as_bytes(&self) -> &[u8] { 11833d722a9Sopenharmony_ci let data = self.as_ptr(); 11933d722a9Sopenharmony_ci let len = self.len(); 12033d722a9Sopenharmony_ci unsafe { slice::from_raw_parts(data, len) } 12133d722a9Sopenharmony_ci } 12233d722a9Sopenharmony_ci 12333d722a9Sopenharmony_ci /// Produces a pointer to the first character of the string. 12433d722a9Sopenharmony_ci /// 12533d722a9Sopenharmony_ci /// Matches the behavior of C++ [std::string::data][data]. 12633d722a9Sopenharmony_ci /// 12733d722a9Sopenharmony_ci /// Note that the return type may look like `const char *` but is not a 12833d722a9Sopenharmony_ci /// `const char *` in the typical C sense, as C++ strings may contain 12933d722a9Sopenharmony_ci /// internal null bytes. As such, the returned pointer only makes sense as a 13033d722a9Sopenharmony_ci /// string in combination with the length returned by [`len()`][len]. 13133d722a9Sopenharmony_ci /// 13233d722a9Sopenharmony_ci /// [data]: https://en.cppreference.com/w/cpp/string/basic_string/data 13333d722a9Sopenharmony_ci /// [len]: #method.len 13433d722a9Sopenharmony_ci pub fn as_ptr(&self) -> *const u8 { 13533d722a9Sopenharmony_ci unsafe { string_data(self) } 13633d722a9Sopenharmony_ci } 13733d722a9Sopenharmony_ci 13833d722a9Sopenharmony_ci /// Validates that the C++ string contains UTF-8 data and produces a view of 13933d722a9Sopenharmony_ci /// it as a Rust &str, otherwise an error. 14033d722a9Sopenharmony_ci pub fn to_str(&self) -> Result<&str, Utf8Error> { 14133d722a9Sopenharmony_ci str::from_utf8(self.as_bytes()) 14233d722a9Sopenharmony_ci } 14333d722a9Sopenharmony_ci 14433d722a9Sopenharmony_ci /// If the contents of the C++ string are valid UTF-8, this function returns 14533d722a9Sopenharmony_ci /// a view as a Cow::Borrowed &str. Otherwise replaces any invalid UTF-8 14633d722a9Sopenharmony_ci /// sequences with the U+FFFD [replacement character] and returns a 14733d722a9Sopenharmony_ci /// Cow::Owned String. 14833d722a9Sopenharmony_ci /// 14933d722a9Sopenharmony_ci /// [replacement character]: https://doc.rust-lang.org/std/char/constant.REPLACEMENT_CHARACTER.html 15033d722a9Sopenharmony_ci #[cfg(feature = "alloc")] 15133d722a9Sopenharmony_ci #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] 15233d722a9Sopenharmony_ci pub fn to_string_lossy(&self) -> Cow<str> { 15333d722a9Sopenharmony_ci String::from_utf8_lossy(self.as_bytes()) 15433d722a9Sopenharmony_ci } 15533d722a9Sopenharmony_ci 15633d722a9Sopenharmony_ci /// Removes all characters from the string. 15733d722a9Sopenharmony_ci /// 15833d722a9Sopenharmony_ci /// Matches the behavior of C++ [std::string::clear][clear]. 15933d722a9Sopenharmony_ci /// 16033d722a9Sopenharmony_ci /// Note: **unlike** the guarantee of Rust's `std::string::String::clear`, 16133d722a9Sopenharmony_ci /// the C++ standard does not require that capacity is unchanged by this 16233d722a9Sopenharmony_ci /// operation. In practice existing implementations do not change the 16333d722a9Sopenharmony_ci /// capacity but all pointers, references, and iterators into the string 16433d722a9Sopenharmony_ci /// contents are nevertheless invalidated. 16533d722a9Sopenharmony_ci /// 16633d722a9Sopenharmony_ci /// [clear]: https://en.cppreference.com/w/cpp/string/basic_string/clear 16733d722a9Sopenharmony_ci pub fn clear(self: Pin<&mut Self>) { 16833d722a9Sopenharmony_ci unsafe { string_clear(self) } 16933d722a9Sopenharmony_ci } 17033d722a9Sopenharmony_ci 17133d722a9Sopenharmony_ci /// Ensures that this string's capacity is at least `additional` bytes 17233d722a9Sopenharmony_ci /// larger than its length. 17333d722a9Sopenharmony_ci /// 17433d722a9Sopenharmony_ci /// The capacity may be increased by more than `additional` bytes if it 17533d722a9Sopenharmony_ci /// chooses, to amortize the cost of frequent reallocations. 17633d722a9Sopenharmony_ci /// 17733d722a9Sopenharmony_ci /// **The meaning of the argument is not the same as 17833d722a9Sopenharmony_ci /// [std::string::reserve][reserve] in C++.** The C++ standard library and 17933d722a9Sopenharmony_ci /// Rust standard library both have a `reserve` method on strings, but in 18033d722a9Sopenharmony_ci /// C++ code the argument always refers to total capacity, whereas in Rust 18133d722a9Sopenharmony_ci /// code it always refers to additional capacity. This API on `CxxString` 18233d722a9Sopenharmony_ci /// follows the Rust convention, the same way that for the length accessor 18333d722a9Sopenharmony_ci /// we use the Rust conventional `len()` naming and not C++ `size()` or 18433d722a9Sopenharmony_ci /// `length()`. 18533d722a9Sopenharmony_ci /// 18633d722a9Sopenharmony_ci /// # Panics 18733d722a9Sopenharmony_ci /// 18833d722a9Sopenharmony_ci /// Panics if the new capacity overflows usize. 18933d722a9Sopenharmony_ci /// 19033d722a9Sopenharmony_ci /// [reserve]: https://en.cppreference.com/w/cpp/string/basic_string/reserve 19133d722a9Sopenharmony_ci pub fn reserve(self: Pin<&mut Self>, additional: usize) { 19233d722a9Sopenharmony_ci let new_cap = self 19333d722a9Sopenharmony_ci .len() 19433d722a9Sopenharmony_ci .checked_add(additional) 19533d722a9Sopenharmony_ci .expect("CxxString capacity overflow"); 19633d722a9Sopenharmony_ci unsafe { string_reserve_total(self, new_cap) } 19733d722a9Sopenharmony_ci } 19833d722a9Sopenharmony_ci 19933d722a9Sopenharmony_ci /// Appends a given string slice onto the end of this C++ string. 20033d722a9Sopenharmony_ci pub fn push_str(self: Pin<&mut Self>, s: &str) { 20133d722a9Sopenharmony_ci self.push_bytes(s.as_bytes()); 20233d722a9Sopenharmony_ci } 20333d722a9Sopenharmony_ci 20433d722a9Sopenharmony_ci /// Appends arbitrary bytes onto the end of this C++ string. 20533d722a9Sopenharmony_ci pub fn push_bytes(self: Pin<&mut Self>, bytes: &[u8]) { 20633d722a9Sopenharmony_ci unsafe { string_push(self, bytes.as_ptr(), bytes.len()) } 20733d722a9Sopenharmony_ci } 20833d722a9Sopenharmony_ci} 20933d722a9Sopenharmony_ci 21033d722a9Sopenharmony_ciimpl Display for CxxString { 21133d722a9Sopenharmony_ci fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 21233d722a9Sopenharmony_ci lossy::display(self.as_bytes(), f) 21333d722a9Sopenharmony_ci } 21433d722a9Sopenharmony_ci} 21533d722a9Sopenharmony_ci 21633d722a9Sopenharmony_ciimpl Debug for CxxString { 21733d722a9Sopenharmony_ci fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 21833d722a9Sopenharmony_ci lossy::debug(self.as_bytes(), f) 21933d722a9Sopenharmony_ci } 22033d722a9Sopenharmony_ci} 22133d722a9Sopenharmony_ci 22233d722a9Sopenharmony_ciimpl PartialEq for CxxString { 22333d722a9Sopenharmony_ci fn eq(&self, other: &Self) -> bool { 22433d722a9Sopenharmony_ci self.as_bytes() == other.as_bytes() 22533d722a9Sopenharmony_ci } 22633d722a9Sopenharmony_ci} 22733d722a9Sopenharmony_ci 22833d722a9Sopenharmony_ciimpl PartialEq<CxxString> for str { 22933d722a9Sopenharmony_ci fn eq(&self, other: &CxxString) -> bool { 23033d722a9Sopenharmony_ci self.as_bytes() == other.as_bytes() 23133d722a9Sopenharmony_ci } 23233d722a9Sopenharmony_ci} 23333d722a9Sopenharmony_ci 23433d722a9Sopenharmony_ciimpl PartialEq<str> for CxxString { 23533d722a9Sopenharmony_ci fn eq(&self, other: &str) -> bool { 23633d722a9Sopenharmony_ci self.as_bytes() == other.as_bytes() 23733d722a9Sopenharmony_ci } 23833d722a9Sopenharmony_ci} 23933d722a9Sopenharmony_ci 24033d722a9Sopenharmony_ciimpl Eq for CxxString {} 24133d722a9Sopenharmony_ci 24233d722a9Sopenharmony_ciimpl PartialOrd for CxxString { 24333d722a9Sopenharmony_ci fn partial_cmp(&self, other: &Self) -> Option<Ordering> { 24433d722a9Sopenharmony_ci self.as_bytes().partial_cmp(other.as_bytes()) 24533d722a9Sopenharmony_ci } 24633d722a9Sopenharmony_ci} 24733d722a9Sopenharmony_ci 24833d722a9Sopenharmony_ciimpl Ord for CxxString { 24933d722a9Sopenharmony_ci fn cmp(&self, other: &Self) -> Ordering { 25033d722a9Sopenharmony_ci self.as_bytes().cmp(other.as_bytes()) 25133d722a9Sopenharmony_ci } 25233d722a9Sopenharmony_ci} 25333d722a9Sopenharmony_ci 25433d722a9Sopenharmony_ciimpl Hash for CxxString { 25533d722a9Sopenharmony_ci fn hash<H: Hasher>(&self, state: &mut H) { 25633d722a9Sopenharmony_ci self.as_bytes().hash(state); 25733d722a9Sopenharmony_ci } 25833d722a9Sopenharmony_ci} 25933d722a9Sopenharmony_ci 26033d722a9Sopenharmony_ciimpl fmt::Write for Pin<&mut CxxString> { 26133d722a9Sopenharmony_ci fn write_str(&mut self, s: &str) -> fmt::Result { 26233d722a9Sopenharmony_ci self.as_mut().push_str(s); 26333d722a9Sopenharmony_ci Ok(()) 26433d722a9Sopenharmony_ci } 26533d722a9Sopenharmony_ci} 26633d722a9Sopenharmony_ci 26733d722a9Sopenharmony_ci#[cfg(feature = "std")] 26833d722a9Sopenharmony_ciimpl std::io::Write for Pin<&mut CxxString> { 26933d722a9Sopenharmony_ci fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> { 27033d722a9Sopenharmony_ci self.as_mut().push_bytes(buf); 27133d722a9Sopenharmony_ci Ok(buf.len()) 27233d722a9Sopenharmony_ci } 27333d722a9Sopenharmony_ci 27433d722a9Sopenharmony_ci fn flush(&mut self) -> std::io::Result<()> { 27533d722a9Sopenharmony_ci Ok(()) 27633d722a9Sopenharmony_ci } 27733d722a9Sopenharmony_ci} 27833d722a9Sopenharmony_ci 27933d722a9Sopenharmony_ci#[doc(hidden)] 28033d722a9Sopenharmony_ci#[repr(C)] 28133d722a9Sopenharmony_cipub struct StackString { 28233d722a9Sopenharmony_ci // Static assertions in cxx.cc validate that this is large enough and 28333d722a9Sopenharmony_ci // aligned enough. 28433d722a9Sopenharmony_ci space: MaybeUninit<[usize; 8]>, 28533d722a9Sopenharmony_ci} 28633d722a9Sopenharmony_ci 28733d722a9Sopenharmony_ci#[allow(missing_docs)] 28833d722a9Sopenharmony_ciimpl StackString { 28933d722a9Sopenharmony_ci pub fn new() -> Self { 29033d722a9Sopenharmony_ci StackString { 29133d722a9Sopenharmony_ci space: MaybeUninit::uninit(), 29233d722a9Sopenharmony_ci } 29333d722a9Sopenharmony_ci } 29433d722a9Sopenharmony_ci 29533d722a9Sopenharmony_ci pub unsafe fn init(&mut self, value: impl AsRef<[u8]>) -> Pin<&mut CxxString> { 29633d722a9Sopenharmony_ci let value = value.as_ref(); 29733d722a9Sopenharmony_ci unsafe { 29833d722a9Sopenharmony_ci let this = &mut *self.space.as_mut_ptr().cast::<MaybeUninit<CxxString>>(); 29933d722a9Sopenharmony_ci string_init(this, value.as_ptr(), value.len()); 30033d722a9Sopenharmony_ci Pin::new_unchecked(&mut *this.as_mut_ptr()) 30133d722a9Sopenharmony_ci } 30233d722a9Sopenharmony_ci } 30333d722a9Sopenharmony_ci} 30433d722a9Sopenharmony_ci 30533d722a9Sopenharmony_ciimpl Drop for StackString { 30633d722a9Sopenharmony_ci fn drop(&mut self) { 30733d722a9Sopenharmony_ci unsafe { 30833d722a9Sopenharmony_ci let this = &mut *self.space.as_mut_ptr().cast::<MaybeUninit<CxxString>>(); 30933d722a9Sopenharmony_ci string_destroy(this); 31033d722a9Sopenharmony_ci } 31133d722a9Sopenharmony_ci } 31233d722a9Sopenharmony_ci} 313