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