use std::ffi::{CStr, CString}; use std::fmt; use std::os::raw::{c_char, c_int, c_uint, c_void}; use std::ptr; use std::str; use malloc_buf::MallocBuffer;
use encode; use {Encode, Encoding};
/// The Objective-C `BOOL` type. /// /// To convert an Objective-C `BOOL` into a Rust `bool`, compare it with `NO`. #[cfg(not(target_arch = "aarch64"))] pubtype BOOL = ::std::os::raw::c_schar; /// The equivalent of true for Objective-C's `BOOL` type. #[cfg(not(target_arch = "aarch64"))] pubconst YES: BOOL = 1; /// The equivalent of false for Objective-C's `BOOL` type. #[cfg(not(target_arch = "aarch64"))] pubconst NO: BOOL = 0;
impl Sel { /// Registers a method with the Objective-C runtime system, /// maps the method name to a selector, and returns the selector value. pubfn register(name: &str) -> Sel { let name = CString::new(name).unwrap(); unsafe {
sel_registerName(name.as_ptr())
}
}
/// Returns the name of the method specified by self. pubfn name(&self) -> &str { let name = unsafe {
CStr::from_ptr(sel_getName(*self))
};
str::from_utf8(name.to_bytes()).unwrap()
}
/// Wraps a raw pointer to a selector into a `Sel` object. /// /// This is almost never what you want; use `Sel::register()` instead. #[inline] pubunsafefn from_ptr(ptr: *const c_void) -> Sel {
Sel {
ptr: ptr,
}
}
/// Returns a pointer to the raw selector. #[inline] pubfn as_ptr(&self) -> *const c_void { self.ptr
}
}
impl PartialEq for Sel { fn eq(&self, other: &Sel) -> bool { self.ptr == other.ptr
}
}
impl Eq for Sel { }
// Sel is safe to share across threads because it is immutable unsafeimpl Sync for Sel { } unsafeimpl Send for Sel { }
impl Copy for Sel { }
impl Clone for Sel { fn clone(&self) -> Sel { *self }
}
impl fmt::Debug for Sel { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.name())
}
}
impl Ivar { /// Returns the name of self. pubfn name(&self) -> &str { let name = unsafe {
CStr::from_ptr(ivar_getName(self))
};
str::from_utf8(name.to_bytes()).unwrap()
}
/// Returns the offset of self. pubfn offset(&self) -> isize { let offset = unsafe {
ivar_getOffset(self)
};
offset as isize
}
/// Returns the `Encoding` of self. pubfn type_encoding(&self) -> Encoding { let encoding = unsafe {
CStr::from_ptr(ivar_getTypeEncoding(self))
}; let s = str::from_utf8(encoding.to_bytes()).unwrap();
encode::from_str(s)
}
}
impl Method { /// Returns the name of self. pubfn name(&self) -> Sel { unsafe {
method_getName(self)
}
}
/// Returns the `Encoding` of self's return type. pubfn return_type(&self) -> Encoding { unsafe { let encoding = method_copyReturnType(self);
encode::from_malloc_str(encoding)
}
}
/// Returns the `Encoding` of a single parameter type of self, or /// `None` if self has no parameter at the given index. pubfn argument_type(&self, index: usize) -> Option<Encoding> { unsafe { let encoding = method_copyArgumentType(self, index as c_uint); if encoding.is_null() {
None
} else {
Some(encode::from_malloc_str(encoding))
}
}
}
/// Returns the number of arguments accepted by self. pubfn arguments_count(&self) -> usize { unsafe {
method_getNumberOfArguments(self) as usize
}
}
/// Returns the implementation of self. pubfn implementation(&self) -> Imp { unsafe {
method_getImplementation(self)
}
}
}
impl Class { /// Returns the class definition of a specified class, or `None` if the /// class is not registered with the Objective-C runtime. pubfn get(name: &str) -> Option<&'static Class> { let name = CString::new(name).unwrap(); unsafe { let cls = objc_getClass(name.as_ptr()); if cls.is_null() { None } else { Some(&*cls) }
}
}
/// Obtains the list of registered class definitions. pubfn classes() -> MallocBuffer<&'static Class> { unsafe { letmut count: c_uint = 0; let classes = objc_copyClassList(&mut count);
MallocBuffer::new(classes as *mut _, count as usize).unwrap()
}
}
/// Returns the total number of registered classes. pubfn classes_count() -> usize { unsafe {
objc_getClassList(ptr::null_mut(), 0) as usize
}
}
/// Returns the name of self. pubfn name(&self) -> &str { let name = unsafe {
CStr::from_ptr(class_getName(self))
};
str::from_utf8(name.to_bytes()).unwrap()
}
/// Returns the superclass of self, or `None` if self is a root class. pubfn superclass(&self) -> Option<&Class> { unsafe { let superclass = class_getSuperclass(self); if superclass.is_null() { None } else { Some(&*superclass) }
}
}
/// Returns the metaclass of self. pubfn metaclass(&self) -> &Class { unsafe { let self_ptr: *const Class = self;
&*object_getClass(self_ptr as *const Object)
}
}
/// Returns the size of instances of self. pubfn instance_size(&self) -> usize { unsafe {
class_getInstanceSize(self) as usize
}
}
/// Returns a specified instance method for self, or `None` if self and /// its superclasses do not contain an instance method with the /// specified selector. pubfn instance_method(&self, sel: Sel) -> Option<&Method> { unsafe { let method = class_getInstanceMethod(self, sel); if method.is_null() { None } else { Some(&*method) }
}
}
/// Returns the ivar for a specified instance variable of self, or `None` /// if self has no ivar with the given name. pubfn instance_variable(&self, name: &str) -> Option<&Ivar> { let name = CString::new(name).unwrap(); unsafe { let ivar = class_getInstanceVariable(self, name.as_ptr()); if ivar.is_null() { None } else { Some(&*ivar) }
}
}
/// Describes the instance methods implemented by self. pubfn instance_methods(&self) -> MallocBuffer<&Method> { unsafe { letmut count: c_uint = 0; let methods = class_copyMethodList(self, &mut count);
MallocBuffer::new(methods as *mut _, count as usize).unwrap()
}
}
/// Checks whether this class conforms to the specified protocol. pubfn conforms_to(&self, proto: &Protocol) -> bool { unsafe { class_conformsToProtocol(self, proto) == YES }
}
/// Get a list of the protocols to which this class conforms. pubfn adopted_protocols(&self) -> MallocBuffer<&Protocol> { unsafe { letmut count: c_uint = 0; let protos = class_copyProtocolList(self, &mut count);
MallocBuffer::new(protos as *mut _, count as usize).unwrap()
}
}
/// Describes the instance variables declared by self. pubfn instance_variables(&self) -> MallocBuffer<&Ivar> { unsafe { letmut count: c_uint = 0; let ivars = class_copyIvarList(self, &mut count);
MallocBuffer::new(ivars as *mut _, count as usize).unwrap()
}
}
}
impl PartialEq for Class { fn eq(&self, other: &Class) -> bool { let self_ptr: *const Class = self; let other_ptr: *const Class = other;
self_ptr == other_ptr
}
}
impl Eq for Class { }
impl fmt::Debug for Class { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.name())
}
}
impl Protocol { /// Returns the protocol definition of a specified protocol, or `None` if the /// protocol is not registered with the Objective-C runtime. pubfn get(name: &str) -> Option<&'static Protocol> { let name = CString::new(name).unwrap(); unsafe { let proto = objc_getProtocol(name.as_ptr()); if proto.is_null() { None } else { Some(&*proto) }
}
}
/// Obtains the list of registered protocol definitions. pubfn protocols() -> MallocBuffer<&'static Protocol> { unsafe { letmut count: c_uint = 0; let protocols = objc_copyProtocolList(&mut count);
MallocBuffer::new(protocols as *mut _, count as usize).unwrap()
}
}
/// Get a list of the protocols to which this protocol conforms. pubfn adopted_protocols(&self) -> MallocBuffer<&Protocol> { unsafe { letmut count: c_uint = 0; let protocols = protocol_copyProtocolList(self, &mut count);
MallocBuffer::new(protocols as *mut _, count as usize).unwrap()
}
}
/// Checks whether this protocol conforms to the specified protocol. pubfn conforms_to(&self, proto: &Protocol) -> bool { unsafe { protocol_conformsToProtocol(self, proto) == YES }
}
/// Returns the name of self. pubfn name(&self) -> &str { let name = unsafe {
CStr::from_ptr(protocol_getName(self))
};
str::from_utf8(name.to_bytes()).unwrap()
}
}
impl Object { /// Returns the class of self. pubfn class(&self) -> &Class { unsafe {
&*object_getClass(self)
}
}
/// Returns a reference to the ivar of self with the given name. /// Panics if self has no ivar with the given name. /// Unsafe because the caller must ensure that the ivar is actually /// of type `T`. pubunsafefn get_ivar<T>(&self, name: &str) -> &T where T: Encode { let offset = { let cls = self.class(); match cls.instance_variable(name) {
Some(ivar) => {
assert!(ivar.type_encoding() == T::encode());
ivar.offset()
}
None => panic!("Ivar {} not found on class {:?}", name, cls),
}
}; let ptr = { let self_ptr: *const Object = self;
(self_ptr as *const u8).offset(offset) as *const T
};
&*ptr
}
/// Returns a mutable reference to the ivar of self with the given name. /// Panics if self has no ivar with the given name. /// Unsafe because the caller must ensure that the ivar is actually /// of type `T`. pubunsafefn get_mut_ivar<T>(&mutself, name: &str) -> &mut T where T: Encode { let offset = { let cls = self.class(); match cls.instance_variable(name) {
Some(ivar) => {
assert!(ivar.type_encoding() == T::encode());
ivar.offset()
}
None => panic!("Ivar {} not found on class {:?}", name, cls),
}
}; let ptr = { let self_ptr: *mut Object = self;
(self_ptr as *mut u8).offset(offset) as *mut T
};
&mut *ptr
}
/// Sets the value of the ivar of self with the given name. /// Panics if self has no ivar with the given name. /// Unsafe because the caller must ensure that the ivar is actually /// of type `T`. pubunsafefn set_ivar<T>(&mutself, name: &str, value: T) where T: Encode {
*self.get_mut_ivar::<T>(name) = value;
}
}
#[test] fn test_protocol() { let proto = test_utils::custom_protocol();
assert!(proto.name() == "CustomProtocol"); let class = test_utils::custom_class();
assert!(class.conforms_to(proto)); let class_protocols = class.adopted_protocols();
assert!(class_protocols.len() > 0);
}
#[test] fn test_protocol_method() { let class = test_utils::custom_class(); let result: i32 = unsafe {
msg_send![class, addNumber:1 toNumber:2]
};
assert_eq!(result, 3);
}
#[test] fn test_subprotocols() { let sub_proto = test_utils::custom_subprotocol(); let super_proto = test_utils::custom_protocol();
assert!(sub_proto.conforms_to(super_proto)); let adopted_protocols = sub_proto.adopted_protocols();
assert_eq!(adopted_protocols[0], super_proto);
}
#[test] fn test_protocols() { // Ensure that a protocol has been registered on linux let _ = test_utils::custom_protocol();
let protocols = Protocol::protocols();
assert!(protocols.len() > 0);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.