1 use std::any::Any;
2 use std::ffi::{CStr, CString};
3 use std::marker::PhantomData;
4 use std::mem;
5 use std::os::raw::c_char;
6 use std::str;
7 
8 use objc::{Encode, Encoding};
9 use objc::runtime::Class;
10 use objc_id::Id;
11 
12 use {INSCopying, INSObject};
13 
14 pub trait INSValue : INSObject {
15     type Value: 'static + Copy + Encode;
16 
value(&self) -> Self::Value17     fn value(&self) -> Self::Value {
18         assert!(Self::Value::encode() == self.encoding());
19         unsafe {
20             let mut value = mem::uninitialized::<Self::Value>();
21             let _: () = msg_send![self, getValue:&mut value];
22             value
23         }
24     }
25 
encoding(&self) -> Encoding26     fn encoding(&self) -> Encoding {
27         unsafe {
28             let result: *const c_char = msg_send![self, objCType];
29             let s = CStr::from_ptr(result);
30             let s = str::from_utf8(s.to_bytes()).unwrap();
31             Encoding::from_str(s)
32         }
33     }
34 
from_value(value: Self::Value) -> Id<Self>35     fn from_value(value: Self::Value) -> Id<Self> {
36         let cls = Self::class();
37         let encoding = CString::new(Self::Value::encode().as_str()).unwrap();
38         unsafe {
39             let obj: *mut Self = msg_send![cls, alloc];
40             let obj: *mut Self = msg_send![obj, initWithBytes:&value
41                                                      objCType:encoding.as_ptr()];
42             Id::from_retained_ptr(obj)
43         }
44     }
45 }
46 
47 pub struct NSValue<T> {
48     value: PhantomData<T>,
49 }
50 
51 object_impl!(NSValue<T>);
52 
53 impl<T> INSObject for NSValue<T> where T: Any {
class() -> &'static Class54     fn class() -> &'static Class {
55         Class::get("NSValue").unwrap()
56     }
57 }
58 
59 impl<T> INSValue for NSValue<T> where T: Any + Copy + Encode {
60     type Value = T;
61 }
62 
63 impl<T> INSCopying for NSValue<T> where T: Any {
64     type Output = NSValue<T>;
65 }
66 
67 #[cfg(test)]
68 mod tests {
69     use objc::Encode;
70     use {INSValue, NSValue};
71 
72     #[test]
test_value()73     fn test_value() {
74         let val = NSValue::from_value(13u32);
75         assert!(val.value() == 13);
76         assert!(u32::encode() == val.encoding());
77     }
78 }
79