Skip to content

Commit 6092caa

Browse files
committed
Replace Encoding with the objc_encode crate
1 parent 33f1daa commit 6092caa

File tree

8 files changed

+59
-274
lines changed

8 files changed

+59
-274
lines changed

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ verify_message = []
2525

2626
[dependencies]
2727
malloc_buf = "1.0"
28+
objc-encode = "1.0"
2829

2930
[dependencies.objc_exception]
3031
version = "0.1"

examples/example.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ fn main() {
3535
let hash_method = cls.instance_method(hash_sel).unwrap();
3636
let hash_return = hash_method.return_type();
3737
println!("-[NSObject hash] return type: {:?}", hash_return);
38-
assert!(hash_return == usize::encode());
38+
assert!(*hash_return == usize::ENCODING);
3939

4040
// Invoke a method on the object
4141
let hash: usize = unsafe {

src/declare.rs

+13-14
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,13 @@ fn count_args(sel: Sel) -> usize {
9292
}
9393

9494
fn method_type_encoding(ret: &Encoding, args: &[Encoding]) -> CString {
95-
let mut types = ret.as_str().to_owned();
9695
// First two arguments are always self and the selector
97-
types.push_str(<*mut Object>::encode().as_str());
98-
types.push_str(Sel::encode().as_str());
99-
types.extend(args.iter().map(|e| e.as_str()));
96+
let mut types = format!("{}{}{}",
97+
ret, <*mut Object>::ENCODING, Sel::ENCODING);
98+
for enc in args {
99+
use std::fmt::Write;
100+
write!(&mut types, "{}", enc).unwrap();
101+
}
100102
CString::new(types).unwrap()
101103
}
102104

@@ -166,15 +168,14 @@ impl ClassDecl {
166168
/// are expected when the method is invoked from Objective-C.
167169
pub unsafe fn add_method<F>(&mut self, sel: Sel, func: F)
168170
where F: MethodImplementation<Callee=Object> {
169-
let encs = F::Args::encodings();
170-
let encs = encs.as_ref();
171+
let encs = F::Args::ENCODINGS;
171172
let sel_args = count_args(sel);
172173
assert!(sel_args == encs.len(),
173174
"Selector accepts {} arguments, but function accepts {}",
174175
sel_args, encs.len(),
175176
);
176177

177-
let types = method_type_encoding(&F::Ret::encode(), encs);
178+
let types = method_type_encoding(&F::Ret::ENCODING, encs);
178179
let success = runtime::class_addMethod(self.cls, sel, func.imp(),
179180
types.as_ptr());
180181
assert!(success != NO, "Failed to add method {:?}", sel);
@@ -187,15 +188,14 @@ impl ClassDecl {
187188
/// are expected when the method is invoked from Objective-C.
188189
pub unsafe fn add_class_method<F>(&mut self, sel: Sel, func: F)
189190
where F: MethodImplementation<Callee=Class> {
190-
let encs = F::Args::encodings();
191-
let encs = encs.as_ref();
191+
let encs = F::Args::ENCODINGS;
192192
let sel_args = count_args(sel);
193193
assert!(sel_args == encs.len(),
194194
"Selector accepts {} arguments, but function accepts {}",
195195
sel_args, encs.len(),
196196
);
197197

198-
let types = method_type_encoding(&F::Ret::encode(), encs);
198+
let types = method_type_encoding(&F::Ret::ENCODING, encs);
199199
let metaclass = (*self.cls).metaclass() as *const _ as *mut _;
200200
let success = runtime::class_addMethod(metaclass, sel, func.imp(),
201201
types.as_ptr());
@@ -206,7 +206,7 @@ impl ClassDecl {
206206
/// Panics if the ivar wasn't successfully added.
207207
pub fn add_ivar<T>(&mut self, name: &str) where T: Encode {
208208
let c_name = CString::new(name).unwrap();
209-
let encoding = CString::new(T::encode().as_str()).unwrap();
209+
let encoding = CString::new(T::ENCODING.to_string()).unwrap();
210210
let size = mem::size_of::<T>();
211211
let align = log2_align_of::<T>();
212212
let success = unsafe {
@@ -269,14 +269,13 @@ impl ProtocolDecl {
269269
is_instance_method: bool)
270270
where Args: EncodeArguments,
271271
Ret: Encode {
272-
let encs = Args::encodings();
273-
let encs = encs.as_ref();
272+
let encs = Args::ENCODINGS;
274273
let sel_args = count_args(sel);
275274
assert!(sel_args == encs.len(),
276275
"Selector accepts {} arguments, but function accepts {}",
277276
sel_args, encs.len(),
278277
);
279-
let types = method_type_encoding(&Ret::encode(), encs);
278+
let types = method_type_encoding(&Ret::ENCODING, encs);
280279
unsafe {
281280
runtime::protocol_addMethodDescription(
282281
self.proto, sel, types.as_ptr(), is_required as BOOL, is_instance_method as BOOL);

src/encode.rs

+20-227
Original file line numberDiff line numberDiff line change
@@ -1,223 +1,39 @@
1-
use std::fmt;
2-
use std::os::raw::{c_char, c_void};
3-
use std::str;
4-
5-
use malloc_buf::Malloc;
6-
71
use runtime::{Class, Object, Sel};
2+
use {Encode, Encoding};
83

9-
const QUALIFIERS: &'static [char] = &[
10-
'r', // const
11-
'n', // in
12-
'N', // inout
13-
'o', // out
14-
'O', // bycopy
15-
'R', // byref
16-
'V', // oneway
17-
];
18-
19-
#[cfg(target_pointer_width = "64")]
20-
const CODE_INLINE_CAP: usize = 30;
21-
22-
#[cfg(target_pointer_width = "32")]
23-
const CODE_INLINE_CAP: usize = 14;
24-
25-
enum Code {
26-
Slice(&'static str),
27-
Owned(String),
28-
Inline(u8, [u8; CODE_INLINE_CAP]),
29-
Malloc(Malloc<str>)
30-
}
31-
32-
/// An Objective-C type encoding.
33-
///
34-
/// For more information, see Apple's documentation:
35-
/// <https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html>
36-
pub struct Encoding {
37-
code: Code,
38-
}
39-
40-
impl Encoding {
41-
/// Constructs an `Encoding` from its string representation.
42-
/// Unsafe because the caller must ensure the string is a valid encoding.
43-
pub unsafe fn from_str(code: &str) -> Encoding {
44-
from_str(code)
45-
}
46-
47-
/// Returns self as a `str`.
48-
pub fn as_str(&self) -> &str {
49-
match self.code {
50-
Code::Slice(code) => code,
51-
Code::Owned(ref code) => code,
52-
Code::Inline(len, ref bytes) => unsafe {
53-
str::from_utf8_unchecked(&bytes[..len as usize])
54-
},
55-
Code::Malloc(ref buf) => &*buf,
56-
}
57-
}
58-
}
59-
60-
impl Clone for Encoding {
61-
fn clone(&self) -> Encoding {
62-
if let Code::Slice(code) = self.code {
63-
from_static_str(code)
64-
} else {
65-
from_str(self.as_str())
66-
}
67-
}
68-
}
69-
70-
impl PartialEq for Encoding {
71-
fn eq(&self, other: &Encoding) -> bool {
72-
// strip qualifiers when comparing
73-
let s = self.as_str().trim_left_matches(QUALIFIERS);
74-
let o = other.as_str().trim_left_matches(QUALIFIERS);
75-
s == o
76-
}
77-
}
78-
79-
impl fmt::Debug for Encoding {
80-
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
81-
write!(f, "{}", self.as_str())
82-
}
83-
}
84-
85-
pub fn from_static_str(code: &'static str) -> Encoding {
86-
Encoding { code: Code::Slice(code) }
87-
}
88-
89-
pub fn from_str(code: &str) -> Encoding {
90-
if code.len() > CODE_INLINE_CAP {
91-
Encoding { code: Code::Owned(code.to_owned()) }
92-
} else {
93-
let mut bytes = [0; CODE_INLINE_CAP];
94-
for (dst, byte) in bytes.iter_mut().zip(code.bytes()) {
95-
*dst = byte;
96-
}
97-
Encoding { code: Code::Inline(code.len() as u8, bytes) }
98-
}
99-
}
100-
101-
pub unsafe fn from_malloc_str(ptr: *mut c_char) -> Encoding {
102-
let buf = Malloc::from_c_str(ptr);
103-
Encoding { code: Code::Malloc(buf.unwrap()) }
104-
}
105-
106-
/// Types that have an Objective-C type encoding.
107-
///
108-
/// Unsafe because Objective-C will make assumptions about the type (like its
109-
/// size and alignment) from its encoding, so the implementer must verify that
110-
/// the encoding is accurate.
111-
pub unsafe trait Encode {
112-
/// Returns the Objective-C type encoding for Self.
113-
fn encode() -> Encoding;
4+
unsafe impl Encode for Sel {
5+
const ENCODING: Encoding<'static> = Encoding::Sel;
1146
}
1157

116-
macro_rules! encode_impls {
117-
($($t:ty : $s:expr,)*) => ($(
118-
unsafe impl Encode for $t {
119-
fn encode() -> Encoding { from_static_str($s) }
120-
}
121-
)*);
8+
unsafe impl<'a> Encode for &'a Object {
9+
const ENCODING: Encoding<'static> = Encoding::Object;
12210
}
12311

124-
encode_impls!(
125-
i8: "c",
126-
i16: "s",
127-
i32: "i",
128-
i64: "q",
129-
u8: "C",
130-
u16: "S",
131-
u32: "I",
132-
u64: "Q",
133-
f32: "f",
134-
f64: "d",
135-
bool: "B",
136-
(): "v",
137-
*mut c_char: "*",
138-
*const c_char: "r*",
139-
*mut c_void: "^v",
140-
*const c_void: "r^v",
141-
Sel: ":",
142-
);
143-
144-
unsafe impl Encode for isize {
145-
#[cfg(target_pointer_width = "32")]
146-
fn encode() -> Encoding { i32::encode() }
147-
148-
#[cfg(target_pointer_width = "64")]
149-
fn encode() -> Encoding { i64::encode() }
12+
unsafe impl<'a> Encode for &'a mut Object {
13+
const ENCODING: Encoding<'static> = Encoding::Object;
15014
}
15115

152-
unsafe impl Encode for usize {
153-
#[cfg(target_pointer_width = "32")]
154-
fn encode() -> Encoding { u32::encode() }
155-
156-
#[cfg(target_pointer_width = "64")]
157-
fn encode() -> Encoding { u64::encode() }
16+
unsafe impl<'a> Encode for &'a Class {
17+
const ENCODING: Encoding<'static> = Encoding::Class;
15818
}
15919

160-
macro_rules! encode_message_impl {
161-
($code:expr, $name:ident) => (
162-
encode_message_impl!($code, $name,);
163-
);
164-
($code:expr, $name:ident, $($t:ident),*) => (
165-
unsafe impl<'a $(, $t)*> $crate::Encode for &'a $name<$($t),*> {
166-
fn encode() -> Encoding { from_static_str($code) }
167-
}
168-
169-
unsafe impl<'a $(, $t)*> $crate::Encode for &'a mut $name<$($t),*> {
170-
fn encode() -> Encoding { from_static_str($code) }
171-
}
172-
173-
unsafe impl<'a $(, $t)*> $crate::Encode for Option<&'a $name<$($t),*>> {
174-
fn encode() -> Encoding { from_static_str($code) }
175-
}
176-
177-
unsafe impl<'a $(, $t)*> $crate::Encode for Option<&'a mut $name<$($t),*>> {
178-
fn encode() -> Encoding { from_static_str($code) }
179-
}
180-
181-
unsafe impl<$($t),*> $crate::Encode for *const $name<$($t),*> {
182-
fn encode() -> Encoding { from_static_str($code) }
183-
}
184-
185-
unsafe impl<$($t),*> $crate::Encode for *mut $name<$($t),*> {
186-
fn encode() -> Encoding { from_static_str($code) }
187-
}
188-
);
20+
unsafe impl<'a> Encode for &'a mut Class {
21+
const ENCODING: Encoding<'static> = Encoding::Class;
18922
}
19023

191-
encode_message_impl!("@", Object);
192-
193-
encode_message_impl!("#", Class);
194-
19524
/// Types that represent a group of arguments, where each has an Objective-C
19625
/// type encoding.
19726
pub trait EncodeArguments {
19827
/// The type as which the encodings for Self will be returned.
199-
type Encs: AsRef<[Encoding]>;
200-
201-
/// Returns the Objective-C type encodings for Self.
202-
fn encodings() -> Self::Encs;
203-
}
204-
205-
macro_rules! count_idents {
206-
() => (0);
207-
($a:ident) => (1);
208-
($a:ident, $($b:ident),+) => (1 + count_idents!($($b),*));
28+
const ENCODINGS: &'static [Encoding<'static>];
20929
}
21030

21131
macro_rules! encode_args_impl {
21232
($($t:ident),*) => (
21333
impl<$($t: Encode),*> EncodeArguments for ($($t,)*) {
214-
type Encs = [Encoding; count_idents!($($t),*)];
215-
216-
fn encodings() -> Self::Encs {
217-
[
218-
$($t::encode()),*
219-
]
220-
}
34+
const ENCODINGS: &'static [Encoding<'static>] = &[
35+
$($t::ENCODING),*
36+
];
22137
}
22238
);
22339
}
@@ -238,37 +54,14 @@ encode_args_impl!(A, B, C, D, E, F, G, H, I, J, K, L);
23854

23955
#[cfg(test)]
24056
mod tests {
57+
use objc_encode::Encode;
24158
use runtime::{Class, Object, Sel};
242-
use super::{Encode, Encoding};
24359

24460
#[test]
24561
fn test_encode() {
246-
assert!(u32::encode().as_str() == "I");
247-
assert!(<()>::encode().as_str() == "v");
248-
assert!(<&Object>::encode().as_str() == "@");
249-
assert!(<*mut Object>::encode().as_str() == "@");
250-
assert!(<&Class>::encode().as_str() == "#");
251-
assert!(Sel::encode().as_str() == ":");
252-
}
253-
254-
#[test]
255-
fn test_inline_encoding() {
256-
let enc = unsafe { Encoding::from_str("C") };
257-
assert!(enc.as_str() == "C");
258-
259-
let enc2 = enc.clone();
260-
assert!(enc2 == enc);
261-
assert!(enc2.as_str() == "C");
262-
}
263-
264-
#[test]
265-
fn test_owned_encoding() {
266-
let s = "{Test=CCCCCCCCCCCCCCCCCCCCCCCCC}";
267-
let enc = unsafe { Encoding::from_str(s) };
268-
assert!(enc.as_str() == s);
269-
270-
let enc2 = enc.clone();
271-
assert!(enc2 == enc);
272-
assert!(enc2.as_str() == s);
62+
assert!(<&Object>::ENCODING.to_string() == "@");
63+
assert!(<*mut Object>::ENCODING.to_string() == "@");
64+
assert!(<&Class>::ENCODING.to_string() == "#");
65+
assert!(Sel::ENCODING.to_string() == ":");
27366
}
27467
}

src/lib.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,13 @@ The bindings can be used on Linux or *BSD utilizing the
6666
#![warn(missing_docs)]
6767

6868
extern crate malloc_buf;
69+
extern crate objc_encode;
6970
#[cfg(feature = "exception")]
7071
extern crate objc_exception;
7172

72-
pub use encode::{Encode, EncodeArguments, Encoding};
73+
pub use objc_encode::{Encode, Encoding};
74+
75+
pub use encode::EncodeArguments;
7376
pub use message::{Message, MessageArguments, MessageError};
7477

7578
pub use message::send_message as __send_message;

0 commit comments

Comments
 (0)