#[cfg(feature = "NSObjCRuntime")]
use core::cmp;
use core::fmt;
use core::ops::AddAssign;
use core::panic::RefUnwindSafe;
use core::panic::UnwindSafe;
#[cfg(target_vendor = "apple")]
use core::slice;
use core::str;
use std::os::raw::c_void;
use objc2::msg_send_id;
use objc2::rc::{autoreleasepool_leaking, Allocated, AutoreleasePool, Retained};
use objc2::runtime::__nsstring::{nsstring_len, nsstring_to_str, UTF8_ENCODING};
use objc2::{ClassType, Message};
use crate::{NSMutableString, NSString};
unsafe impl Sync for NSString {}
unsafe impl Send for NSString {}
impl UnwindSafe for NSString {}
impl RefUnwindSafe for NSString {}
impl NSString {
#[doc(alias = "lengthOfBytesUsingEncoding")]
#[doc(alias = "lengthOfBytesUsingEncoding:")]
pub fn len(&self) -> usize {
unsafe { nsstring_len(self) }
}
#[doc(alias = "length")]
pub fn len_utf16(&self) -> usize {
self.length()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[doc(alias = "CFStringGetCStringPtr")]
#[allow(unused)]
#[cfg(target_vendor = "apple")]
fn as_str_wip(&self) -> Option<&str> {
use core::ptr::NonNull;
use std::os::raw::c_char;
type CFStringEncoding = u32;
#[allow(non_upper_case_globals)]
const kCFStringEncodingUTF8: CFStringEncoding = 0x08000100;
extern "C" {
fn CFStringGetCStringPtr(s: &NSString, encoding: CFStringEncoding) -> *const c_char;
}
let bytes = unsafe { CFStringGetCStringPtr(self, kCFStringEncodingUTF8) };
NonNull::new(bytes as *mut u8).map(|bytes| {
let len = self.len();
let bytes: &[u8] = unsafe { slice::from_raw_parts(bytes.as_ptr(), len) };
str::from_utf8(bytes).unwrap()
})
}
#[allow(unused)]
#[cfg(target_vendor = "apple")]
fn as_utf16(&self) -> Option<&[u16]> {
use core::ptr::NonNull;
extern "C" {
fn CFStringGetCharactersPtr(s: &NSString) -> *const u16;
}
let ptr = unsafe { CFStringGetCharactersPtr(self) };
NonNull::new(ptr as *mut u16)
.map(|ptr| unsafe { slice::from_raw_parts(ptr.as_ptr(), self.len_utf16()) })
}
#[doc(alias = "UTF8String")]
pub fn as_str<'r, 's: 'r, 'p: 'r>(&'s self, pool: AutoreleasePool<'p>) -> &'r str {
unsafe { nsstring_to_str(self, pool) }
}
#[doc(alias = "initWithBytes")]
#[doc(alias = "initWithBytes:length:encoding:")]
#[allow(clippy::should_implement_trait)] pub fn from_str(string: &str) -> Retained<Self> {
unsafe { init_with_str(Self::alloc(), string) }
}
}
impl NSMutableString {
#[doc(alias = "initWithBytes:length:encoding:")]
#[allow(clippy::should_implement_trait)] pub fn from_str(string: &str) -> Retained<Self> {
unsafe { init_with_str(Self::alloc(), string) }
}
}
unsafe fn init_with_str<T: Message>(obj: Allocated<T>, string: &str) -> Retained<T> {
let bytes: *const c_void = string.as_ptr().cast();
unsafe {
msg_send_id![
obj,
initWithBytes: bytes,
length: string.len(),
encoding: UTF8_ENCODING,
]
}
}
impl PartialEq<NSString> for NSMutableString {
#[inline]
fn eq(&self, other: &NSString) -> bool {
PartialEq::eq(&**self, other)
}
}
impl PartialEq<NSMutableString> for NSString {
#[inline]
fn eq(&self, other: &NSMutableString) -> bool {
PartialEq::eq(self, &**other)
}
}
#[cfg(feature = "NSObjCRuntime")]
impl PartialOrd for NSString {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}
#[cfg(feature = "NSObjCRuntime")]
impl Ord for NSString {
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.compare(other).into()
}
}
#[cfg(feature = "NSObjCRuntime")]
impl PartialOrd for NSMutableString {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}
#[cfg(feature = "NSObjCRuntime")]
impl PartialOrd<NSString> for NSMutableString {
#[inline]
fn partial_cmp(&self, other: &NSString) -> Option<cmp::Ordering> {
PartialOrd::partial_cmp(&**self, other)
}
}
#[cfg(feature = "NSObjCRuntime")]
impl PartialOrd<NSMutableString> for NSString {
#[inline]
fn partial_cmp(&self, other: &NSMutableString) -> Option<cmp::Ordering> {
PartialOrd::partial_cmp(self, &**other)
}
}
#[cfg(feature = "NSObjCRuntime")]
impl Ord for NSMutableString {
#[inline]
fn cmp(&self, other: &Self) -> cmp::Ordering {
Ord::cmp(&**self, &**other)
}
}
impl AddAssign<&NSString> for NSMutableString {
#[inline]
fn add_assign(&mut self, other: &NSString) {
self.appendString(other);
}
}
impl fmt::Display for NSString {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
autoreleasepool_leaking(|pool| fmt::Display::fmt(self.as_str(pool), f))
}
}
impl fmt::Display for NSMutableString {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&**self, f)
}
}
impl fmt::Debug for NSString {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
autoreleasepool_leaking(|pool| fmt::Debug::fmt(self.as_str(pool), f))
}
}
impl fmt::Debug for NSMutableString {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
impl fmt::Write for NSMutableString {
fn write_str(&mut self, s: &str) -> fmt::Result {
let nsstring = NSString::from_str(s);
self.appendString(&nsstring);
Ok(())
}
}