use super::NSComparisonResult;
use crate::objc::{Class, NSObject, NSUInteger, Object, BOOL, NO, SEL};
use std::{cmp::Ordering, ffi::CStr, fmt, ops::Deref, os::raw::c_char, ptr::NonNull, str};
mod macros;
#[inline]
#[allow(non_snake_case)]
pub fn NSSelectorFromString(string: &NSString) -> Option<SEL> {
extern "C" {
fn NSSelectorFromString(string: &Object) -> Option<SEL>;
}
unsafe { NSSelectorFromString(string) }
}
#[repr(transparent)]
#[derive(Clone)]
pub struct NSString(NSObject);
impl From<NSString> for NSObject {
#[inline]
fn from(obj: NSString) -> Self {
obj.0
}
}
impl Deref for NSString {
type Target = NSObject;
#[inline]
fn deref(&self) -> &NSObject {
&self.0
}
}
impl PartialEq for NSString {
#[inline]
fn eq(&self, other: &Self) -> bool {
extern "C" {
fn objc_msgSend(obj: &Object, sel: SEL, other: &Object) -> BOOL;
}
let sel = selector!(isEqualToString:);
unsafe { objc_msgSend(self, sel, other) != 0 }
}
}
impl Eq for NSString {}
impl PartialOrd for NSString {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for NSString {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
self.compare(other).into()
}
}
impl From<&str> for NSString {
#[inline]
fn from(s: &str) -> Self {
Self::from_str(s)
}
}
impl From<&mut str> for NSString {
#[inline]
fn from(s: &mut str) -> Self {
Self::from_str(s)
}
}
impl fmt::Debug for NSString {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let str = unsafe { self.to_str() };
str.fmt(f)
}
}
impl fmt::Display for NSString {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let str = unsafe { self.to_str() };
str.fmt(f)
}
}
impl NSString {
#[inline]
pub fn class() -> &'static Class {
extern "C" {
#[link_name = "OBJC_CLASS_$_NSString"]
static CLASS: Class;
}
unsafe { &CLASS }
}
#[inline]
pub const unsafe fn from_ptr(ptr: *mut Object) -> Self {
Self(NSObject::from_ptr(ptr))
}
#[inline]
pub const unsafe fn from_non_null_ptr(ptr: NonNull<Object>) -> Self {
Self(NSObject::from_non_null_ptr(ptr))
}
unsafe fn _from_str(s: &str, class: &Class) -> NSString {
let value: Self = Self(class.alloc());
extern "C" {
fn objc_msgSend(
obj: NSString,
sel: SEL,
bytes: *const u8,
length: NSUInteger,
encoding: NSStringEncoding,
) -> NSString;
}
let obj = value;
let sel = selector!(initWithBytes:length:encoding:);
let bytes = s.as_ptr();
let length = s.len();
let encoding = NSStringEncoding::UTF8;
objc_msgSend(obj, sel, bytes, length, encoding)
}
#[inline]
pub fn from_str(s: &str) -> NSString {
unsafe { Self::_from_str(s, Self::class()) }
}
pub unsafe fn from_str_no_copy(s: &str) -> NSString {
let value: Self = Self(Self::class().alloc());
extern "C" {
fn objc_msgSend(
obj: NSString,
sel: SEL,
bytes: *const u8,
length: NSUInteger,
encoding: NSStringEncoding,
free_when_done: BOOL,
) -> NSString;
}
let obj = value;
let sel = selector!(initWithBytesNoCopy:length:encoding:freeWhenDone:);
let bytes = s.as_ptr();
let length = s.len();
let encoding = NSStringEncoding::UTF8;
let free_when_done = NO;
objc_msgSend(obj, sel, bytes, length, encoding, free_when_done)
}
#[inline]
pub fn copy(&self) -> NSString {
Self(NSObject::copy(self))
}
#[inline]
pub fn mutable_copy(&self) -> NSMutableString {
NSMutableString(Self(NSObject::mutable_copy(self)))
}
#[inline]
pub fn to_utf8_ptr(&self) -> *const c_char {
extern "C" {
fn objc_msgSend(obj: &Object, sel: SEL) -> *const c_char;
}
let sel = selector!(UTF8String);
unsafe { objc_msgSend(self, sel) }
}
#[inline]
pub unsafe fn to_str(&self) -> &str {
let s = self.to_str_with_nul();
s.get_unchecked(..s.len() - 1)
}
pub unsafe fn to_str_with_nul(&self) -> &str {
let cstr = CStr::from_ptr(self.to_utf8_ptr());
str::from_utf8_unchecked(cstr.to_bytes_with_nul())
}
#[inline]
pub fn to_string(&self) -> String {
let mut string = self.to_string_with_nul();
let len = string.len() - 1;
unsafe { string.as_mut_vec().set_len(len) };
string
}
pub fn to_string_with_nul(&self) -> String {
unsafe { self.to_str_with_nul() }.into()
}
#[inline]
pub fn to_selector(&self) -> Option<SEL> {
NSSelectorFromString(self)
}
#[inline]
pub fn compare(&self, other: &NSString) -> NSComparisonResult {
extern "C" {
fn objc_msgSend(obj: &Object, sel: SEL, other: &Object) -> NSComparisonResult;
}
let sel = selector!(compare:);
unsafe { objc_msgSend(self, sel, other) }
}
#[inline]
pub fn localized_compare(&self, other: &NSString) -> NSComparisonResult {
extern "C" {
fn objc_msgSend(obj: &Object, sel: SEL, other: &Object) -> NSComparisonResult;
}
let sel = selector!(localizedCompare:);
unsafe { objc_msgSend(self, sel, other) }
}
#[inline]
pub fn case_insensitive_compare(&self, other: &NSString) -> NSComparisonResult {
extern "C" {
fn objc_msgSend(obj: &Object, sel: SEL, other: &Object) -> NSComparisonResult;
}
let sel = selector!(caseInsensitiveCompare:);
unsafe { objc_msgSend(self, sel, other) }
}
#[inline]
pub fn localized_case_insensitive_compare(&self, other: &NSString) -> NSComparisonResult {
extern "C" {
fn objc_msgSend(obj: &Object, sel: SEL, other: &Object) -> NSComparisonResult;
}
let sel = selector!(localizedCaseInsensitiveCompare:);
unsafe { objc_msgSend(self, sel, other) }
}
#[inline]
pub fn localized_standard_compare(&self, other: &NSString) -> NSComparisonResult {
extern "C" {
fn objc_msgSend(obj: &Object, sel: SEL, other: &Object) -> NSComparisonResult;
}
let sel = selector!(localizedStandardCompare:);
unsafe { objc_msgSend(self, sel, other) }
}
#[inline]
pub fn has_prefix(&self, prefix: &NSString) -> bool {
extern "C" {
fn objc_msgSend(obj: &Object, sel: SEL, prefix: &Object) -> BOOL;
}
let sel = selector!(hasPrefix:);
unsafe { objc_msgSend(self, sel, prefix) != 0 }
}
#[inline]
pub fn has_suffix(&self, suffix: &NSString) -> bool {
extern "C" {
fn objc_msgSend(obj: &Object, sel: SEL, suffix: &Object) -> BOOL;
}
let sel = selector!(hasSuffix:);
unsafe { objc_msgSend(self, sel, suffix) != 0 }
}
}
#[repr(transparent)]
#[derive(Clone)]
pub struct NSMutableString(NSString);
impl From<NSMutableString> for NSObject {
#[inline]
fn from(obj: NSMutableString) -> Self {
(obj.0).0
}
}
impl From<NSMutableString> for NSString {
#[inline]
fn from(obj: NSMutableString) -> Self {
obj.0
}
}
impl Deref for NSMutableString {
type Target = NSString;
#[inline]
fn deref(&self) -> &NSString {
&self.0
}
}
impl PartialEq for NSMutableString {
#[inline]
fn eq(&self, other: &Self) -> bool {
NSString::eq(self, other)
}
}
impl PartialEq<NSString> for NSMutableString {
#[inline]
fn eq(&self, other: &NSString) -> bool {
(self as &NSString).eq(other)
}
}
impl PartialEq<NSMutableString> for NSString {
#[inline]
fn eq(&self, other: &NSMutableString) -> bool {
self.eq(other as &NSString)
}
}
impl Eq for NSMutableString {}
impl PartialOrd for NSMutableString {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl PartialOrd<NSString> for NSMutableString {
#[inline]
fn partial_cmp(&self, other: &NSString) -> Option<Ordering> {
Some(NSString::cmp(self, other))
}
}
impl PartialOrd<NSMutableString> for NSString {
#[inline]
fn partial_cmp(&self, other: &NSMutableString) -> Option<Ordering> {
Some(NSString::cmp(self, other))
}
}
impl Ord for NSMutableString {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
NSString::cmp(self, other)
}
}
impl From<&str> for NSMutableString {
#[inline]
fn from(s: &str) -> Self {
Self::from_str(s)
}
}
impl From<&mut str> for NSMutableString {
#[inline]
fn from(s: &mut str) -> Self {
Self::from_str(s)
}
}
impl fmt::Debug for NSMutableString {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
(self as &NSString).fmt(f)
}
}
impl fmt::Display for NSMutableString {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
(self as &NSString).fmt(f)
}
}
impl NSMutableString {
#[inline]
pub fn class() -> &'static Class {
extern "C" {
#[link_name = "OBJC_CLASS_$_NSMutableString"]
static CLASS: Class;
}
unsafe { &CLASS }
}
#[inline]
pub const unsafe fn from_ptr(ptr: *mut Object) -> Self {
Self(NSString::from_ptr(ptr))
}
#[inline]
pub const unsafe fn from_non_null_ptr(ptr: NonNull<Object>) -> Self {
Self(NSString::from_non_null_ptr(ptr))
}
#[inline]
pub fn from_str(s: &str) -> NSMutableString {
unsafe { Self(NSString::_from_str(s, Self::class())) }
}
pub unsafe fn from_str_no_copy(s: &mut str) -> NSMutableString {
let value: Self = Self(NSString(Self::class().alloc()));
extern "C" {
fn objc_msgSend(
obj: NSMutableString,
sel: SEL,
bytes: *mut u8,
length: NSUInteger,
encoding: NSStringEncoding,
free_when_done: BOOL,
) -> NSMutableString;
}
let obj = value;
let sel = selector!(initWithBytesNoCopy:length:encoding:freeWhenDone:);
let bytes = s.as_mut_ptr();
let length = s.len();
let encoding = NSStringEncoding::UTF8;
let free_when_done = NO;
objc_msgSend(obj, sel, bytes, length, encoding, free_when_done)
}
}
#[repr(transparent)]
#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub struct NSStringEncoding(pub NSUInteger);
#[allow(non_upper_case_globals)]
impl NSStringEncoding {
pub const ASCII: Self = Self(1);
pub const NEXTSTEP: Self = Self(2);
pub const JapaneseEUC: Self = Self(3);
pub const UTF8: Self = Self(4);
pub const ISOLatin1: Self = Self(5);
pub const Symbol: Self = Self(6);
pub const NonLossyASCII: Self = Self(7);
pub const ShiftJIS: Self = Self(8);
pub const ISOLatin2: Self = Self(9);
pub const Unicode: Self = Self(10);
pub const WindowsCP1251: Self = Self(11);
pub const WindowsCP1252: Self = Self(12);
pub const WindowsCP1253: Self = Self(13);
pub const WindowsCP1254: Self = Self(14);
pub const WindowsCP1250: Self = Self(15);
pub const ISO2022JP: Self = Self(21);
pub const MacOSRoman: Self = Self(30);
pub const UTF16: Self = Self::Unicode;
pub const UTF16BigEndian: Self = Self(0x90000100);
pub const UTF16LittleEndian: Self = Self(0x94000100);
pub const UTF32: Self = Self(0x8c000100);
pub const UTF32BigEndian: Self = Self(0x98000100);
pub const UTF32LittleEndian: Self = Self(0x9c000100);
}