use super::{NSObject, Object, BOOL, SEL};
use std::{
cmp,
ffi::CStr,
fmt, hash,
ops::Deref,
os::raw::{c_char, c_int},
panic::RefUnwindSafe,
ptr,
};
#[repr(C)]
pub struct Class(
Object,
);
impl RefUnwindSafe for Class {}
impl Deref for Class {
type Target = Object;
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl AsRef<Object> for Class {
#[inline]
fn as_ref(&self) -> &Object {
self
}
}
impl fmt::Debug for Class {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("Class").field(&self.name()).finish()
}
}
impl PartialEq for Class {
#[inline]
fn eq(&self, other: &Self) -> bool {
ptr::eq(self, other)
}
}
impl Eq for Class {}
impl PartialOrd for Class {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Class {
#[inline]
fn cmp(&self, other: &Self) -> cmp::Ordering {
(self as *const Self).cmp(&(other as *const Self))
}
}
impl hash::Hash for Class {
#[inline]
fn hash<H: hash::Hasher>(&self, state: &mut H) {
(self as *const Self).hash(state);
}
}
impl Class {
#[inline]
pub fn get(name: &CStr) -> Option<&'static Class> {
unsafe { objc_getClass(name.as_ptr()) }
}
#[inline]
pub fn count() -> usize {
unsafe { objc_getClassList(ptr::null_mut(), 0) as usize }
}
pub fn all() -> Vec<&'static Class> {
let len = Self::count();
let mut all = Vec::<&'static Class>::with_capacity(len);
unsafe {
objc_getClassList(all.as_mut_ptr(), len as c_int);
all.set_len(len);
}
all
}
#[inline]
pub(crate) fn alloc(&self) -> NSObject {
extern "C" {
fn objc_msgSend(class: &Class, sel: SEL) -> NSObject;
}
let sel = selector!(alloc);
unsafe { objc_msgSend(self, sel) }
}
#[inline]
pub const fn as_object(&self) -> &Object {
&self.0
}
#[inline]
pub fn responds_to_selector(&self, selector: SEL) -> bool {
extern "C" {
fn objc_msgSend(class: &Class, sel: SEL, selector: SEL) -> BOOL;
}
let sel = selector!(respondsToSelector:);
unsafe { objc_msgSend(self, sel, selector) != 0 }
}
#[inline]
pub fn instances_respond_to_selector(&self, selector: SEL) -> bool {
extern "C" {
fn objc_msgSend(class: &Class, sel: SEL, selector: SEL) -> BOOL;
}
let sel = selector!(instancesRespondToSelector:);
unsafe { objc_msgSend(self, sel, selector) != 0 }
}
#[inline]
pub fn name(&self) -> &CStr {
unsafe { CStr::from_ptr(class_getName(self)) }
}
#[inline]
pub fn superclass(&self) -> Option<&Class> {
unsafe { class_getSuperclass(self) }
}
#[inline]
pub fn superclass_iter(&self) -> impl Iterator<Item = &Class> + Copy {
#[derive(Copy, Clone)]
struct Iter<'a>(&'a Class);
impl<'a> Iterator for Iter<'a> {
type Item = &'a Class;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let superclass = self.0.superclass()?;
self.0 = superclass;
Some(superclass)
}
}
impl std::iter::FusedIterator for Iter<'_> {}
Iter(self)
}
#[inline]
pub fn superclass_count(&self) -> usize {
self.superclass_iter().count()
}
#[inline]
pub fn is_subclass(&self) -> bool {
self.superclass().is_some()
}
pub fn is_subclass_of(&self, other: &Self) -> bool {
if self == other {
true
} else {
self.superclass_iter().any(|superclass| superclass == other)
}
}
#[inline]
pub fn instance_size(&self) -> usize {
unsafe { class_getInstanceSize(self) }
}
}
extern "C" {
fn objc_getClass(name: *const c_char) -> Option<&'static Class>;
fn objc_getClassList(buf: *mut &'static Class, buf_len: c_int) -> c_int;
fn class_getName(class: &Class) -> *const c_char;
fn class_getSuperclass(class: &Class) -> Option<&Class>;
fn class_getInstanceSize(class: &Class) -> usize;
}