use core::fmt;
use core::hash;
use super::NSString;
use crate::rc::{DefaultId, Id, Owned, Shared};
use crate::runtime::{Class, Object};
use crate::{ClassType, __inner_extern_class, class, extern_methods, msg_send_id};
__inner_extern_class! {
@__inner
pub struct NSObject () {}
unsafe impl () for NSObject {
INHERITS = [Object];
}
}
unsafe impl ClassType for NSObject {
type Super = Object;
const NAME: &'static str = "NSObject";
#[inline]
fn class() -> &'static Class {
class!(NSObject)
}
fn as_super(&self) -> &Self::Super {
&self.__inner
}
fn as_super_mut(&mut self) -> &mut Self::Super {
&mut self.__inner
}
}
extern_methods!(
unsafe impl NSObject {
pub fn new() -> Id<Self, Owned> {
unsafe { msg_send_id![Self::class(), new] }
}
#[sel(isKindOfClass:)]
fn is_kind_of_inner(&self, cls: &Class) -> bool;
#[sel(isEqual:)]
fn is_equal(&self, other: &Self) -> bool;
#[sel(hash)]
fn hash_code(&self) -> usize;
#[doc(alias = "isKindOfClass:")]
pub fn is_kind_of<T: ClassType>(&self) -> bool {
self.is_kind_of_inner(T::class())
}
}
);
impl PartialEq for NSObject {
#[inline]
#[doc(alias = "isEqual:")]
fn eq(&self, other: &Self) -> bool {
self.is_equal(other)
}
}
impl Eq for NSObject {}
impl hash::Hash for NSObject {
#[inline]
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.hash_code().hash(state);
}
}
impl fmt::Debug for NSObject {
#[doc(alias = "description")]
#[doc(alias = "debugDescription")]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let description: Option<Id<NSString, Shared>> = unsafe { msg_send_id![self, description] };
match description {
Some(description) => fmt::Display::fmt(&description, f),
None => {
let obj: &Object = self;
fmt::Debug::fmt(obj, f)
}
}
}
}
impl DefaultId for NSObject {
type Ownership = Owned;
#[inline]
fn default_id() -> Id<Self, Self::Ownership> {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::format;
#[test]
fn test_deref() {
let mut obj: Id<NSObject, Owned> = NSObject::new();
let _: &NSObject = &obj;
let _: &mut NSObject = &mut obj;
let _: &Object = &obj;
let _: &mut Object = &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 = NSObject::new();
impls_as_ref::<Id<NSObject, Owned>, NSObject>(&obj);
impls_as_mut::<Id<NSObject, Owned>, NSObject>(&mut obj);
impls_as_ref::<NSObject, NSObject>(&obj);
impls_as_mut::<NSObject, NSObject>(&mut obj);
impls_as_ref::<NSObject, Object>(&obj);
impls_as_mut::<NSObject, Object>(&mut 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::<NSString>());
}
}