Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make Sel an opaque struct like Ivar, Method, Class, Protocol and Object #105

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,12 @@ let mut decl = ClassDecl::new("MyNumber", superclass).unwrap();
decl.add_ivar::<u32>("_number");

// Add an ObjC method for getting the number
extern fn my_number_get(this: &Object, _cmd: Sel) -> u32 {
extern fn my_number_get(this: &Object, _cmd: &Sel) -> u32 {
unsafe { *this.get_ivar("_number") }
}
unsafe {
decl.add_method(sel!(number),
my_number_get as extern fn(&Object, Sel) -> u32);
my_number_get as extern fn(&Object, &Sel) -> u32);
}

decl.register();
Expand Down
11 changes: 5 additions & 6 deletions src/cache.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use std::os::raw::c_void;
use std::ptr;
use std::sync::atomic::{AtomicPtr, Ordering};

Expand All @@ -7,7 +6,7 @@ use crate::runtime::{Class, Sel, self};
/// Allows storing a `Sel` in a static and lazily loading it.
#[doc(hidden)]
pub struct CachedSel {
ptr: AtomicPtr<c_void>
ptr: AtomicPtr<Sel>,
}

impl CachedSel {
Expand All @@ -21,16 +20,16 @@ impl CachedSel {
/// Returns the cached selector. If no selector is yet cached, registers
/// one with the given name and stores it.
#[inline(always)]
pub unsafe fn get(&self, name: &str) -> Sel {
pub unsafe fn get(&self, name: &str) -> &'static Sel {
let ptr = self.ptr.load(Ordering::Relaxed);
// It should be fine to use `Relaxed` ordering here because `sel_registerName` is
// thread-safe.
if ptr.is_null() {
let sel = runtime::sel_registerName(name.as_ptr() as *const _);
self.ptr.store(sel.as_ptr() as *mut _, Ordering::Relaxed);
sel
self.ptr.store(sel as *mut _, Ordering::Relaxed);
&*sel
} else {
Sel::from_ptr(ptr)
&*ptr
}
}
}
Expand Down
53 changes: 31 additions & 22 deletions src/declare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ let mut decl = ClassDecl::new("MyNumber", superclass).unwrap();
decl.add_ivar::<u32>("_number");

// Add an ObjC method for getting the number
extern fn my_number_get(this: &Object, _cmd: Sel) -> u32 {
extern fn my_number_get(this: &Object, _cmd: &Sel) -> u32 {
unsafe { *this.get_ivar("_number") }
}
unsafe {
decl.add_method(sel!(number),
my_number_get as extern fn(&Object, Sel) -> u32);
my_number_get as extern fn(&Object, &Sel) -> u32);
}

decl.register();
Expand Down Expand Up @@ -68,8 +68,8 @@ macro_rules! method_decl_impl {
}
);
($($t:ident),*) => (
method_decl_impl!(-T, R, extern fn(&T, Sel $(, $t)*) -> R, $($t),*);
method_decl_impl!(-T, R, extern fn(&mut T, Sel $(, $t)*) -> R, $($t),*);
method_decl_impl!(-T, R, extern fn(&T, &Sel $(, $t)*) -> R, $($t),*);
method_decl_impl!(-T, R, extern fn(&mut T, &Sel $(, $t)*) -> R, $($t),*);
);
}

Expand All @@ -87,14 +87,13 @@ method_decl_impl!(A, B, C, D, E, F, G, H, I, J);
method_decl_impl!(A, B, C, D, E, F, G, H, I, J, K);
method_decl_impl!(A, B, C, D, E, F, G, H, I, J, K, L);

fn count_args(sel: Sel) -> usize {
fn count_args(sel: &Sel) -> usize {
sel.name().chars().filter(|&c| c == ':').count()
}

fn method_type_encoding(ret: &Encoding, args: &[Encoding]) -> CString {
// First two arguments are always self and the selector
let mut types = format!("{}{}{}",
ret, <*mut Object>::ENCODING, Sel::ENCODING);
let mut types = format!("{}{}{}", ret, <*mut Object>::ENCODING, <&Sel>::ENCODING);
for enc in args {
use std::fmt::Write;
write!(&mut types, "{}", enc).unwrap();
Expand Down Expand Up @@ -150,8 +149,7 @@ impl ClassDecl {
Functionality it expects, like implementations of `-retain` and `-release`
used by ARC, will not be present otherwise.
*/
pub fn root(name: &str, intitialize_fn: extern fn(&Class, Sel))
-> Option<ClassDecl> {
pub fn root(name: &str, intitialize_fn: extern "C" fn(&Class, &Sel)) -> Option<ClassDecl> {
let mut decl = ClassDecl::with_superclass(name, None);
if let Some(ref mut decl) = decl {
unsafe {
Expand All @@ -166,7 +164,7 @@ impl ClassDecl {
/// or if the selector and function take different numbers of arguments.
/// Unsafe because the caller must ensure that the types match those that
/// are expected when the method is invoked from Objective-C.
pub unsafe fn add_method<F>(&mut self, sel: Sel, func: F)
pub unsafe fn add_method<F>(&mut self, sel: &Sel, func: F)
where F: MethodImplementation<Callee=Object> {
let encs = F::Args::ENCODINGS;
let sel_args = count_args(sel);
Expand All @@ -186,8 +184,10 @@ impl ClassDecl {
/// or if the selector and function take different numbers of arguments.
/// Unsafe because the caller must ensure that the types match those that
/// are expected when the method is invoked from Objective-C.
pub unsafe fn add_class_method<F>(&mut self, sel: Sel, func: F)
where F: MethodImplementation<Callee=Class> {
pub unsafe fn add_class_method<F>(&mut self, sel: &Sel, func: F)
where
F: MethodImplementation<Callee = Class>,
{
let encs = F::Args::ENCODINGS;
let sel_args = count_args(sel);
assert!(sel_args == encs.len(),
Expand Down Expand Up @@ -265,10 +265,15 @@ impl ProtocolDecl {
}
}

fn add_method_description_common<Args, Ret>(&mut self, sel: Sel, is_required: bool,
is_instance_method: bool)
where Args: EncodeArguments,
Ret: Encode {
fn add_method_description_common<Args, Ret>(
&mut self,
sel: &Sel,
is_required: bool,
is_instance_method: bool,
) where
Args: EncodeArguments,
Ret: Encode,
{
let encs = Args::ENCODINGS;
let sel_args = count_args(sel);
assert!(sel_args == encs.len(),
Expand All @@ -283,16 +288,20 @@ impl ProtocolDecl {
}

/// Adds an instance method declaration with a given description to self.
pub fn add_method_description<Args, Ret>(&mut self, sel: Sel, is_required: bool)
where Args: EncodeArguments,
Ret: Encode {
pub fn add_method_description<Args, Ret>(&mut self, sel: &Sel, is_required: bool)
where
Args: EncodeArguments,
Ret: Encode,
{
self.add_method_description_common::<Args, Ret>(sel, is_required, true)
}

/// Adds a class method declaration with a given description to self.
pub fn add_class_method_description<Args, Ret>(&mut self, sel: Sel, is_required: bool)
where Args: EncodeArguments,
Ret: Encode {
pub fn add_class_method_description<Args, Ret>(&mut self, sel: &Sel, is_required: bool)
where
Args: EncodeArguments,
Ret: Encode,
{
self.add_method_description_common::<Args, Ret>(sel, is_required, false)
}

Expand Down
7 changes: 5 additions & 2 deletions src/encode.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use crate::runtime::{Class, Object, Sel};
use crate::{Encode, Encoding};

unsafe impl Encode for Sel {
unsafe impl<'a> Encode for &'a Sel {
const ENCODING: Encoding<'static> = Encoding::Sel;
}

// We don't implement `Encode` for `&mut Sel` because selectors are immutable.

unsafe impl<'a> Encode for &'a Object {
const ENCODING: Encoding<'static> = Encoding::Object;
}
Expand Down Expand Up @@ -62,6 +64,7 @@ mod tests {
assert!(<&Object>::ENCODING.to_string() == "@");
assert!(<*mut Object>::ENCODING.to_string() == "@");
assert!(<&Class>::ENCODING.to_string() == "#");
assert!(Sel::ENCODING.to_string() == ":");
assert!(<*const Sel>::ENCODING.to_string() == ":");
assert!(<&Sel>::ENCODING.to_string() == ":");
}
}
2 changes: 1 addition & 1 deletion src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ macro_rules! class {
}

/**
Registers a selector, returning a `Sel`.
Registers a selector, returning a `&'static Sel`.

# Example
```
Expand Down
4 changes: 2 additions & 2 deletions src/message/apple/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ mod arch;

use self::arch::{msg_send_fn, msg_send_super_fn};

pub unsafe fn send_unverified<T, A, R>(obj: *const T, sel: Sel, args: A)
pub unsafe fn send_unverified<T, A, R>(obj: *const T, sel: &Sel, args: A)
-> Result<R, MessageError>
where T: Message, A: MessageArguments, R: Any {
let receiver = obj as *mut T as *mut Object;
Expand All @@ -29,7 +29,7 @@ pub unsafe fn send_unverified<T, A, R>(obj: *const T, sel: Sel, args: A)
}

pub unsafe fn send_super_unverified<T, A, R>(obj: *const T, superclass: &Class,
sel: Sel, args: A) -> Result<R, MessageError>
sel: &Sel, args: A) -> Result<R, MessageError>
where T: Message, A: MessageArguments, R: Any {
let sup = Super { receiver: obj as *mut T as *mut Object, superclass: superclass };
let receiver = &sup as *const Super as *mut Object;
Expand Down
8 changes: 4 additions & 4 deletions src/message/gnustep.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ use crate::runtime::{Class, Object, Imp, Sel};
use super::{Message, MessageArguments, MessageError, Super};

extern {
fn objc_msg_lookup(receiver: *mut Object, op: Sel) -> Imp;
fn objc_msg_lookup_super(sup: *const Super, sel: Sel) -> Imp;
fn objc_msg_lookup(receiver: *mut Object, op: &Sel) -> Imp;
fn objc_msg_lookup_super(sup: *const Super, sel: &Sel) -> Imp;
}

pub unsafe fn send_unverified<T, A, R>(obj: *const T, sel: Sel, args: A)
pub unsafe fn send_unverified<T, A, R>(obj: *const T, sel: &Sel, args: A)
-> Result<R, MessageError>
where T: Message, A: MessageArguments, R: Any {
if obj.is_null() {
Expand All @@ -24,7 +24,7 @@ pub unsafe fn send_unverified<T, A, R>(obj: *const T, sel: Sel, args: A)
}

pub unsafe fn send_super_unverified<T, A, R>(obj: *const T, superclass: &Class,
sel: Sel, args: A) -> Result<R, MessageError>
sel: &Sel, args: A) -> Result<R, MessageError>
where T: Message, A: MessageArguments, R: Any {
let receiver = obj as *mut T as *mut Object;
let sup = Super { receiver: receiver, superclass: superclass };
Expand Down
20 changes: 10 additions & 10 deletions src/message/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,14 @@ pub unsafe trait Message {
`msg_send!` macro rather than this method.
*/
#[cfg(not(feature = "verify_message"))]
unsafe fn send_message<A, R>(&self, sel: Sel, args: A)
unsafe fn send_message<A, R>(&self, sel: &Sel, args: A)
-> Result<R, MessageError>
where Self: Sized, A: MessageArguments, R: Any {
send_message(self, sel, args)
}

#[cfg(feature = "verify_message")]
unsafe fn send_message<A, R>(&self, sel: Sel, args: A)
unsafe fn send_message<A, R>(&self, sel: &Sel, args: A)
-> Result<R, MessageError>
where Self: Sized, A: MessageArguments + EncodeArguments,
R: Any + Encode {
Expand Down Expand Up @@ -96,7 +96,7 @@ pub unsafe trait Message {
# }
```
*/
fn verify_message<A, R>(&self, sel: Sel) -> Result<(), MessageError>
fn verify_message<A, R>(&self, sel: &Sel) -> Result<(), MessageError>
where Self: Sized, A: EncodeArguments, R: Encode {
let obj = unsafe { &*(self as *const _ as *const Object) };
verify_message_signature::<A, R>(obj.class(), sel)
Expand All @@ -115,16 +115,16 @@ pub trait MessageArguments: Sized {
/// This method is the primitive used when sending messages and should not
/// be called directly; instead, use the `msg_send!` macro or, in cases
/// with a dynamic selector, the `Message::send_message` method.
unsafe fn invoke<R>(imp: Imp, obj: *mut Object, sel: Sel, args: Self) -> R
unsafe fn invoke<R>(imp: Imp, obj: *mut Object, sel: &Sel, args: Self) -> R
where R: Any;
}

macro_rules! message_args_impl {
($($a:ident : $t:ident),*) => (
impl<$($t),*> MessageArguments for ($($t,)*) {
unsafe fn invoke<R>(imp: Imp, obj: *mut Object, sel: Sel, ($($a,)*): Self) -> R
unsafe fn invoke<R>(imp: Imp, obj: *mut Object, sel: &Sel, ($($a,)*): Self) -> R
where R: Any {
let imp: unsafe extern fn(*mut Object, Sel $(, $t)*) -> R =
let imp: unsafe extern fn(*mut Object, &Sel $(, $t)*) -> R =
mem::transmute(imp);
imp(obj, sel $(, $a)*)
}
Expand Down Expand Up @@ -179,7 +179,7 @@ impl<'a> From<VerificationError<'a>> for MessageError {
#[doc(hidden)]
#[inline(always)]
#[cfg(not(feature = "verify_message"))]
pub unsafe fn send_message<T, A, R>(obj: *const T, sel: Sel, args: A)
pub unsafe fn send_message<T, A, R>(obj: *const T, sel: &Sel, args: A)
-> Result<R, MessageError>
where T: Message, A: MessageArguments, R: Any {
send_unverified(obj, sel, args)
Expand All @@ -188,7 +188,7 @@ pub unsafe fn send_message<T, A, R>(obj: *const T, sel: Sel, args: A)
#[doc(hidden)]
#[inline(always)]
#[cfg(feature = "verify_message")]
pub unsafe fn send_message<T, A, R>(obj: *const T, sel: Sel, args: A)
pub unsafe fn send_message<T, A, R>(obj: *const T, sel: &Sel, args: A)
-> Result<R, MessageError>
where T: Message, A: MessageArguments + EncodeArguments,
R: Any + Encode {
Expand All @@ -206,7 +206,7 @@ pub unsafe fn send_message<T, A, R>(obj: *const T, sel: Sel, args: A)
#[inline(always)]
#[cfg(not(feature = "verify_message"))]
pub unsafe fn send_super_message<T, A, R>(obj: *const T, superclass: &Class,
sel: Sel, args: A) -> Result<R, MessageError>
sel: &Sel, args: A) -> Result<R, MessageError>
where T: Message, A: MessageArguments, R: Any {
send_super_unverified(obj, superclass, sel, args)
}
Expand All @@ -215,7 +215,7 @@ pub unsafe fn send_super_message<T, A, R>(obj: *const T, superclass: &Class,
#[inline(always)]
#[cfg(feature = "verify_message")]
pub unsafe fn send_super_message<T, A, R>(obj: *const T, superclass: &Class,
sel: Sel, args: A) -> Result<R, MessageError>
sel: &Sel, args: A) -> Result<R, MessageError>
where T: Message, A: MessageArguments + EncodeArguments,
R: Any + Encode {
if obj.is_null() {
Expand Down
13 changes: 7 additions & 6 deletions src/message/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use crate::runtime::{Class, Method, Object, Sel};
use crate::{Encode, Encoding, EncodeArguments};

pub enum VerificationError<'a> {
NilReceiver(Sel),
MethodNotFound(&'a Class, Sel),
NilReceiver(&'a Sel),
MethodNotFound(&'a Class, &'a Sel),
MismatchedReturn(&'a Method, Encoding<'static>),
MismatchedArgumentsCount(&'a Method, usize),
MismatchedArgument(&'a Method, usize, Encoding<'static>),
Expand Down Expand Up @@ -39,9 +39,10 @@ impl<'a> fmt::Display for VerificationError<'a> {
}
}

pub fn verify_message_signature<A, R>(cls: &Class, sel: Sel)
-> Result<(), VerificationError>
where A: EncodeArguments, R: Encode {
pub fn verify_message_signature<'a, A: EncodeArguments, R: Encode>(
cls: &'a Class,
sel: &'a Sel,
) -> Result<(), VerificationError<'a>> {
let method = match cls.instance_method(sel) {
Some(method) => method,
None => return Err(VerificationError::MethodNotFound(cls, sel)),
Expand All @@ -53,7 +54,7 @@ pub fn verify_message_signature<A, R>(cls: &Class, sel: Sel)
return Err(VerificationError::MismatchedReturn(method, ret));
}

let self_and_cmd = [<*mut Object>::ENCODING, Sel::ENCODING];
let self_and_cmd = [<*mut Object>::ENCODING, <&Sel>::ENCODING];
let args = A::ENCODINGS;

let count = self_and_cmd.len() + args.len();
Expand Down
Loading