objc_foundation/
dictionary.rs

1use std::cmp::min;
2use std::marker::PhantomData;
3use std::ops::Index;
4use std::ptr;
5
6use objc::runtime::Class;
7use objc_id::{Id, Owned, Ownership, ShareId};
8
9use {
10    INSArray, INSFastEnumeration, INSCopying, INSObject,
11    NSArray, NSSharedArray, NSEnumerator,
12};
13
14unsafe fn from_refs<D, T>(keys: &[&T], vals: &[&D::Value]) -> Id<D>
15        where D: INSDictionary, T: INSCopying<Output=D::Key> {
16    let cls = D::class();
17    let count = min(keys.len(), vals.len());
18    let obj: *mut D = msg_send![cls, alloc];
19    let obj: *mut D = msg_send![obj, initWithObjects:vals.as_ptr()
20                                             forKeys:keys.as_ptr()
21                                               count:count];
22    Id::from_retained_ptr(obj)
23}
24
25pub trait INSDictionary : INSObject {
26    type Key: INSObject;
27    type Value: INSObject;
28    type Own: Ownership;
29
30    fn count(&self) -> usize {
31        unsafe {
32            msg_send![self, count]
33        }
34    }
35
36    fn object_for(&self, key: &Self::Key) -> Option<&Self::Value> {
37        unsafe {
38            let obj: *mut Self::Value = msg_send![self, objectForKey:key];
39            if obj.is_null() { None } else { Some(&*obj) }
40        }
41    }
42
43    fn keys(&self) -> Vec<&Self::Key> {
44        let len = self.count();
45        let mut keys = Vec::with_capacity(len);
46        unsafe {
47            let _: () = msg_send![self, getObjects:ptr::null_mut::<Self::Value>()
48                                           andKeys:keys.as_mut_ptr()];
49            keys.set_len(len);
50        }
51        keys
52    }
53
54    fn values(&self) -> Vec<&Self::Value> {
55        let len = self.count();
56        let mut vals = Vec::with_capacity(len);
57        unsafe {
58            let _: () = msg_send![self, getObjects:vals.as_mut_ptr()
59                                           andKeys:ptr::null_mut::<Self::Key>()];
60            vals.set_len(len);
61        }
62        vals
63    }
64
65    fn keys_and_objects(&self) -> (Vec<&Self::Key>, Vec<&Self::Value>) {
66        let len = self.count();
67        let mut keys = Vec::with_capacity(len);
68        let mut objs = Vec::with_capacity(len);
69        unsafe {
70            let _: () = msg_send![self, getObjects:objs.as_mut_ptr()
71                                           andKeys:keys.as_mut_ptr()];
72            keys.set_len(len);
73            objs.set_len(len);
74        }
75        (keys, objs)
76    }
77
78    fn key_enumerator(&self) -> NSEnumerator<Self::Key> {
79        unsafe {
80            let result = msg_send![self, keyEnumerator];
81            NSEnumerator::from_ptr(result)
82        }
83    }
84
85    fn object_enumerator(&self) -> NSEnumerator<Self::Value> {
86        unsafe {
87            let result = msg_send![self, objectEnumerator];
88            NSEnumerator::from_ptr(result)
89        }
90    }
91
92    fn keys_array(&self) -> Id<NSSharedArray<Self::Key>> {
93        unsafe {
94            let keys: *mut NSSharedArray<Self::Key> = msg_send![self, allKeys];
95            Id::from_ptr(keys)
96        }
97    }
98
99    fn from_keys_and_objects<T>(keys: &[&T],
100            vals: Vec<Id<Self::Value, Self::Own>>) -> Id<Self>
101            where T: INSCopying<Output=Self::Key> {
102        let vals_refs: Vec<&Self::Value> = vals.iter().map(|obj| &**obj).collect();
103        unsafe {
104            from_refs(keys, &vals_refs)
105        }
106    }
107
108    fn into_values_array(dict: Id<Self>) -> Id<NSArray<Self::Value, Self::Own>> {
109        unsafe {
110            let vals = msg_send![dict, allValues];
111            Id::from_ptr(vals)
112        }
113    }
114}
115
116pub struct NSDictionary<K, V> {
117    key: PhantomData<ShareId<K>>,
118    obj: PhantomData<Id<V>>,
119}
120
121object_impl!(NSDictionary<K, V>);
122
123impl<K, V> INSObject for NSDictionary<K, V> where K: INSObject, V: INSObject {
124    fn class() -> &'static Class {
125        Class::get("NSDictionary").unwrap()
126    }
127}
128
129impl<K, V> INSDictionary for NSDictionary<K, V>
130        where K: INSObject, V: INSObject {
131    type Key = K;
132    type Value = V;
133    type Own = Owned;
134}
135
136impl<K, V> INSFastEnumeration for NSDictionary<K, V>
137        where K: INSObject, V: INSObject {
138    type Item = K;
139}
140
141impl<'a, K, V> Index<&'a K> for NSDictionary<K, V> where K: INSObject, V: INSObject {
142    type Output = V;
143
144    fn index(&self, index: &K) -> &V {
145        self.object_for(index).unwrap()
146    }
147}
148
149#[cfg(test)]
150mod tests {
151    use objc_id::Id;
152    use {INSArray, INSObject, INSString, NSObject, NSString};
153    use super::{INSDictionary, NSDictionary};
154
155    fn sample_dict(key: &str) -> Id<NSDictionary<NSString, NSObject>> {
156        let string = NSString::from_str(key);
157        let obj = NSObject::new();
158        NSDictionary::from_keys_and_objects(&[&*string], vec![obj])
159    }
160
161    #[test]
162    fn test_count() {
163        let dict = sample_dict("abcd");
164        assert!(dict.count() == 1);
165    }
166
167    #[test]
168    fn test_object_for() {
169        let dict = sample_dict("abcd");
170
171        let string = NSString::from_str("abcd");
172        assert!(dict.object_for(&string).is_some());
173
174        let string = NSString::from_str("abcde");
175        assert!(dict.object_for(&string).is_none());
176    }
177
178    #[test]
179    fn test_keys() {
180        let dict = sample_dict("abcd");
181        let keys = dict.keys();
182
183        assert!(keys.len() == 1);
184        assert!(keys[0].as_str() == "abcd");
185    }
186
187    #[test]
188    fn test_values() {
189        let dict = sample_dict("abcd");
190        let vals = dict.values();
191
192        assert!(vals.len() == 1);
193    }
194
195    #[test]
196    fn test_keys_and_objects() {
197        let dict = sample_dict("abcd");
198        let (keys, objs) = dict.keys_and_objects();
199
200        assert!(keys.len() == 1);
201        assert!(objs.len() == 1);
202        assert!(keys[0].as_str() == "abcd");
203        assert!(objs[0] == dict.object_for(keys[0]).unwrap());
204    }
205
206    #[test]
207    fn test_key_enumerator() {
208        let dict = sample_dict("abcd");
209        assert!(dict.key_enumerator().count() == 1);
210        assert!(dict.key_enumerator().next().unwrap().as_str() == "abcd");
211    }
212
213    #[test]
214    fn test_object_enumerator() {
215        let dict = sample_dict("abcd");
216        assert!(dict.object_enumerator().count() == 1);
217    }
218
219    #[test]
220    fn test_arrays() {
221        let dict = sample_dict("abcd");
222
223        let keys = dict.keys_array();
224        assert!(keys.count() == 1);
225        assert!(keys.object_at(0).as_str() == "abcd");
226
227        let objs = INSDictionary::into_values_array(dict);
228        assert!(objs.count() == 1);
229    }
230}