use core::fmt;
use core::hash;
use crate::ffi::NSUInteger;
use crate::mutability::Root;
use crate::rc::{Allocated, DefaultRetained, Retained};
use crate::runtime::{AnyClass, AnyObject, AnyProtocol, ImplementedBy, ProtocolObject, Sel};
use crate::{extern_methods, msg_send, msg_send_id, Message};
use crate::{ClassType, ProtocolType};
#[repr(C)]
pub struct NSObject {
__inner: AnyObject,
}
crate::__extern_class_impl_traits! {
unsafe impl () for NSObject {
INHERITS = [AnyObject];
fn as_super(&self) {
&self.__inner
}
fn as_super_mut(&mut self) {
&mut self.__inner
}
}
}
unsafe impl ClassType for NSObject {
type Super = AnyObject;
type Mutability = Root;
const NAME: &'static str = "NSObject";
#[inline]
fn class() -> &'static AnyClass {
crate::__class_inner!("NSObject", "NSObject")
}
#[inline]
fn as_super(&self) -> &Self::Super {
&self.__inner
}
#[inline]
fn as_super_mut(&mut self) -> &mut Self::Super {
&mut self.__inner
}
}
#[allow(non_snake_case)] pub unsafe trait NSObjectProtocol {
#[doc(alias = "isEqual:")]
fn isEqual(&self, other: &AnyObject) -> bool
where
Self: Sized + Message,
{
unsafe { msg_send![self, isEqual: other] }
}
fn hash(&self) -> NSUInteger
where
Self: Sized + Message,
{
unsafe { msg_send![self, hash] }
}
#[doc(alias = "isKindOfClass:")]
fn isKindOfClass(&self, cls: &AnyClass) -> bool
where
Self: Sized + Message,
{
unsafe { msg_send![self, isKindOfClass: cls] }
}
#[doc(alias = "isKindOfClass")]
#[doc(alias = "isKindOfClass:")]
fn is_kind_of<T: ClassType>(&self) -> bool
where
Self: Sized + Message,
{
self.isKindOfClass(T::class())
}
#[doc(alias = "isMemberOfClass:")]
fn isMemberOfClass(&self, cls: &AnyClass) -> bool
where
Self: Sized + Message,
{
unsafe { msg_send![self, isMemberOfClass: cls] }
}
#[doc(alias = "respondsToSelector:")]
fn respondsToSelector(&self, aSelector: Sel) -> bool
where
Self: Sized + Message,
{
unsafe { msg_send![self, respondsToSelector: aSelector] }
}
#[doc(alias = "conformsToProtocol:")]
fn conformsToProtocol(&self, aProtocol: &AnyProtocol) -> bool
where
Self: Sized + Message,
{
unsafe { msg_send![self, conformsToProtocol: aProtocol] }
}
fn description(&self) -> Retained<NSObject>
where
Self: Sized + Message,
{
unsafe { msg_send_id![self, description] }
}
fn debugDescription(&self) -> Retained<NSObject>
where
Self: Sized + Message,
{
unsafe { msg_send_id![self, debugDescription] }
}
fn isProxy(&self) -> bool
where
Self: Sized + Message,
{
unsafe { msg_send![self, isProxy] }
}
fn retainCount(&self) -> NSUInteger
where
Self: Sized + Message,
{
unsafe { msg_send![self, retainCount] }
}
}
crate::__inner_extern_protocol!(
()
(NSObjectProtocol)
(dyn NSObjectProtocol)
("NSObject")
);
unsafe impl<T> ImplementedBy<T> for dyn NSObjectProtocol + Send
where
T: ?Sized + Message + NSObjectProtocol + Send,
{
const __INNER: () = ();
}
unsafe impl<T> ImplementedBy<T> for dyn NSObjectProtocol + Sync
where
T: ?Sized + Message + NSObjectProtocol + Sync,
{
const __INNER: () = ();
}
unsafe impl<T> ImplementedBy<T> for dyn NSObjectProtocol + Send + Sync
where
T: ?Sized + Message + NSObjectProtocol + Send + Sync,
{
const __INNER: () = ();
}
unsafe impl NSObjectProtocol for NSObject {}
extern_methods!(
#[allow(non_snake_case)] unsafe impl NSObject {
#[method_id(new)]
pub fn new() -> Retained<Self>;
#[method_id(init)]
pub fn init(this: Allocated<Self>) -> Retained<Self>;
#[method(doesNotRecognizeSelector:)]
fn doesNotRecognizeSelector_inner(&self, sel: Sel);
pub fn doesNotRecognizeSelector(&self, sel: Sel) -> ! {
self.doesNotRecognizeSelector_inner(sel);
unreachable!("doesNotRecognizeSelector: should not return")
}
}
);
impl PartialEq for NSObject {
#[inline]
#[doc(alias = "isEqual:")]
fn eq(&self, other: &Self) -> bool {
self.isEqual(other)
}
}
impl Eq for NSObject {}
impl hash::Hash for NSObject {
#[inline]
fn hash<H: hash::Hasher>(&self, state: &mut H) {
<Self as NSObjectProtocol>::hash(self).hash(state);
}
}
impl fmt::Debug for NSObject {
#[inline]
#[doc(alias = "description")]
#[doc(alias = "debugDescription")]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let obj: &ProtocolObject<dyn NSObjectProtocol> = ProtocolObject::from_ref(self);
obj.fmt(f)
}
}
impl DefaultRetained for NSObject {
#[inline]
fn default_id() -> Retained<Self> {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::format;
use crate::extern_class;
use crate::mutability::Mutable;
use crate::rc::RcTestObject;
extern_class!(
#[derive(Debug, PartialEq, Eq, Hash)]
struct NSObjectMutable;
unsafe impl ClassType for NSObjectMutable {
type Super = NSObject;
type Mutability = Mutable;
const NAME: &'static str = "NSObject";
}
);
impl NSObjectMutable {
fn new() -> Retained<Self> {
unsafe { Retained::cast(NSObject::new()) }
}
}
#[test]
fn test_deref() {
let obj: Retained<NSObject> = NSObject::new();
let _: &NSObject = &obj;
let _: &AnyObject = &obj;
}
#[test]
fn test_deref_mut() {
let mut obj: Retained<NSObjectMutable> = NSObjectMutable::new();
let _: &NSObjectMutable = &obj;
let _: &mut NSObjectMutable = &mut obj;
let _: &NSObject = &obj;
let _: &mut NSObject = &mut obj;
let _: &AnyObject = &obj;
let _: &mut AnyObject = &mut obj;
}
#[test]
fn test_as_ref_borrow() {
use core::borrow::{Borrow, BorrowMut};
fn impls_as_ref<T: AsRef<U> + Borrow<U> + ?Sized, U: ?Sized>(_: &T) {}
fn impls_as_mut<T: AsMut<U> + BorrowMut<U> + ?Sized, U: ?Sized>(_: &mut T) {}
let mut obj = NSObjectMutable::new();
impls_as_ref::<Retained<NSObjectMutable>, NSObjectMutable>(&obj);
impls_as_mut::<Retained<NSObjectMutable>, NSObjectMutable>(&mut obj);
impls_as_ref::<NSObjectMutable, NSObjectMutable>(&obj);
impls_as_mut::<NSObjectMutable, NSObjectMutable>(&mut obj);
impls_as_ref::<NSObject, NSObject>(&obj);
impls_as_mut::<NSObject, NSObject>(&mut obj);
impls_as_ref::<NSObject, AnyObject>(&obj);
impls_as_mut::<NSObject, AnyObject>(&mut obj);
let obj = NSObject::new();
impls_as_ref::<Retained<NSObject>, NSObject>(&obj);
impls_as_ref::<NSObject, NSObject>(&obj);
impls_as_ref::<NSObject, AnyObject>(&obj);
}
#[test]
fn test_equality() {
let obj1 = NSObject::new();
assert_eq!(obj1, obj1);
let obj2 = NSObject::new();
assert_ne!(obj1, obj2);
}
#[test]
fn test_hash() {
use core::hash::Hasher;
use std::collections::hash_map::DefaultHasher;
use std::hash::Hash;
let obj1 = NSObject::new();
let mut hashstate1 = DefaultHasher::new();
let mut hashstate2 = DefaultHasher::new();
obj1.hash(&mut hashstate1);
obj1.hash(&mut hashstate2);
assert_eq!(hashstate1.finish(), hashstate2.finish());
let obj2 = NSObject::new();
let mut hashstate2 = DefaultHasher::new();
obj2.hash(&mut hashstate2);
assert_ne!(hashstate1.finish(), hashstate2.finish());
}
#[test]
fn test_debug() {
let obj = NSObject::new();
let expected = format!("<NSObject: {:p}>", &*obj);
assert_eq!(format!("{obj:?}"), expected);
}
#[test]
fn test_is_kind_of() {
let obj = NSObject::new();
assert!(obj.is_kind_of::<NSObject>());
assert!(!obj.is_kind_of::<RcTestObject>());
let obj = RcTestObject::new();
assert!(obj.is_kind_of::<NSObject>());
assert!(obj.is_kind_of::<RcTestObject>());
}
#[test]
fn test_retain_same() {
let obj1 = NSObject::new();
let ptr1 = Retained::as_ptr(&obj1);
let obj2 = obj1.clone();
let ptr2 = Retained::as_ptr(&obj2);
assert_eq!(ptr1, ptr2);
}
#[test]
fn conforms_to_nsobjectprotocol() {
let protocol = <dyn NSObjectProtocol>::protocol().unwrap();
assert!(NSObject::class().conforms_to(protocol));
}
mod hash_does_not_overlap_with_normal_hash_method {
#[allow(unused_imports)]
use crate::runtime::NSObjectProtocol;
use std::collections::hash_map::DefaultHasher;
use std::hash::Hash;
#[test]
fn inner() {
let integer = 5;
let mut hasher = DefaultHasher::new();
integer.hash(&mut hasher);
}
}
}