1 // Copyright 2013 The Servo Project Developers. See the COPYRIGHT 2 // file at the top-level directory of this distribution. 3 // 4 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or 5 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license 6 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your 7 // option. This file may not be copied, modified, or distributed 8 // except according to those terms. 9 10 //! Dictionaries of key-value pairs. 11 12 pub use core_foundation_sys::dictionary::*; 13 14 use core_foundation_sys::base::{CFTypeRef, CFRelease, kCFAllocatorDefault}; 15 use std::mem; 16 use std::os::raw::c_void; 17 use std::ptr; 18 use std::marker::PhantomData; 19 20 use base::{ItemRef, FromVoid, ToVoid}; 21 use base::{CFIndexConvertible, TCFType}; 22 use ConcreteCFType; 23 24 // consume the type parameters with PhantomDatas 25 pub struct CFDictionary<K = *const c_void, V = *const c_void>(CFDictionaryRef, PhantomData<K>, PhantomData<V>); 26 27 impl<K, V> Drop for CFDictionary<K, V> { drop(&mut self)28 fn drop(&mut self) { 29 unsafe { CFRelease(self.as_CFTypeRef()) } 30 } 31 } 32 33 impl_TCFType!(CFDictionary<K, V>, CFDictionaryRef, CFDictionaryGetTypeID); 34 impl_CFTypeDescription!(CFDictionary); 35 36 unsafe impl ConcreteCFType for CFDictionary<*const c_void, *const c_void> {} 37 38 impl<K, V> CFDictionary<K, V> { from_CFType_pairs(pairs: &[(K, V)]) -> CFDictionary<K, V> where K: TCFType, V: TCFType39 pub fn from_CFType_pairs(pairs: &[(K, V)]) -> CFDictionary<K, V> where K: TCFType, V: TCFType { 40 let (keys, values): (Vec<CFTypeRef>, Vec<CFTypeRef>) = pairs 41 .iter() 42 .map(|&(ref key, ref value)| (key.as_CFTypeRef(), value.as_CFTypeRef())) 43 .unzip(); 44 45 unsafe { 46 let dictionary_ref = CFDictionaryCreate(kCFAllocatorDefault, 47 mem::transmute(keys.as_ptr()), 48 mem::transmute(values.as_ptr()), 49 keys.len().to_CFIndex(), 50 &kCFTypeDictionaryKeyCallBacks, 51 &kCFTypeDictionaryValueCallBacks); 52 TCFType::wrap_under_create_rule(dictionary_ref) 53 } 54 } 55 56 #[inline] to_untyped(&self) -> CFDictionary57 pub fn to_untyped(&self) -> CFDictionary { 58 unsafe { CFDictionary::wrap_under_get_rule(self.0) } 59 } 60 61 /// Returns the same dictionary, but with the types reset to void pointers. 62 /// Equal to `to_untyped`, but is faster since it does not increment the retain count. 63 #[inline] into_untyped(self) -> CFDictionary64 pub fn into_untyped(self) -> CFDictionary { 65 let reference = self.0; 66 mem::forget(self); 67 unsafe { CFDictionary::wrap_under_create_rule(reference) } 68 } 69 70 #[inline] len(&self) -> usize71 pub fn len(&self) -> usize { 72 unsafe { 73 CFDictionaryGetCount(self.0) as usize 74 } 75 } 76 77 #[inline] is_empty(&self) -> bool78 pub fn is_empty(&self) -> bool { 79 self.len() == 0 80 } 81 82 #[inline] contains_key(&self, key: &K) -> bool where K: ToVoid<K>83 pub fn contains_key(&self, key: &K) -> bool where K: ToVoid<K> { 84 unsafe { CFDictionaryContainsKey(self.0, key.to_void()) != 0 } 85 } 86 87 #[inline] find<'a, T: ToVoid<K>>(&'a self, key: T) -> Option<ItemRef<'a, V>> where V: FromVoid, K: ToVoid<K>88 pub fn find<'a, T: ToVoid<K>>(&'a self, key: T) -> Option<ItemRef<'a, V>> where V: FromVoid, K: ToVoid<K> { 89 unsafe { 90 let mut value: *const c_void = ptr::null(); 91 if CFDictionaryGetValueIfPresent(self.0, key.to_void(), &mut value) != 0 { 92 Some(V::from_void(value)) 93 } else { 94 None 95 } 96 } 97 } 98 99 /// # Panics 100 /// 101 /// Panics if the key is not present in the dictionary. Use `find` to get an `Option` instead 102 /// of panicking. 103 #[inline] get<'a, T: ToVoid<K>>(&'a self, key: T) -> ItemRef<'a, V> where V: FromVoid, K: ToVoid<K>104 pub fn get<'a, T: ToVoid<K>>(&'a self, key: T) -> ItemRef<'a, V> where V: FromVoid, K: ToVoid<K> { 105 let ptr = key.to_void(); 106 self.find(key).expect(&format!("No entry found for key {:p}", ptr)) 107 } 108 get_keys_and_values(&self) -> (Vec<*const c_void>, Vec<*const c_void>)109 pub fn get_keys_and_values(&self) -> (Vec<*const c_void>, Vec<*const c_void>) { 110 let length = self.len(); 111 let mut keys = Vec::with_capacity(length); 112 let mut values = Vec::with_capacity(length); 113 114 unsafe { 115 CFDictionaryGetKeysAndValues(self.0, keys.as_mut_ptr(), values.as_mut_ptr()); 116 keys.set_len(length); 117 values.set_len(length); 118 } 119 120 (keys, values) 121 } 122 } 123 124 // consume the type parameters with PhantomDatas 125 pub struct CFMutableDictionary<K = *const c_void, V = *const c_void>(CFMutableDictionaryRef, PhantomData<K>, PhantomData<V>); 126 127 impl<K, V> Drop for CFMutableDictionary<K, V> { drop(&mut self)128 fn drop(&mut self) { 129 unsafe { CFRelease(self.as_CFTypeRef()) } 130 } 131 } 132 133 impl_TCFType!(CFMutableDictionary<K, V>, CFMutableDictionaryRef, CFDictionaryGetTypeID); 134 impl_CFTypeDescription!(CFMutableDictionary); 135 136 impl<K, V> CFMutableDictionary<K, V> { new() -> Self137 pub fn new() -> Self { 138 Self::with_capacity(0) 139 } 140 with_capacity(capacity: isize) -> Self141 pub fn with_capacity(capacity: isize) -> Self { 142 unsafe { 143 let dictionary_ref = CFDictionaryCreateMutable(kCFAllocatorDefault, 144 capacity as _, 145 &kCFTypeDictionaryKeyCallBacks, 146 &kCFTypeDictionaryValueCallBacks); 147 TCFType::wrap_under_create_rule(dictionary_ref) 148 } 149 } 150 copy_with_capacity(&self, capacity: isize) -> Self151 pub fn copy_with_capacity(&self, capacity: isize) -> Self { 152 unsafe { 153 let dictionary_ref = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, capacity as _, self.0); 154 TCFType::wrap_under_get_rule(dictionary_ref) 155 } 156 } 157 from_CFType_pairs(pairs: &[(K, V)]) -> CFMutableDictionary<K, V> where K: ToVoid<K>, V: ToVoid<V>158 pub fn from_CFType_pairs(pairs: &[(K, V)]) -> CFMutableDictionary<K, V> where K: ToVoid<K>, V: ToVoid<V> { 159 let mut result = Self::with_capacity(pairs.len() as _); 160 for &(ref key, ref value) in pairs { 161 result.add(key, value); 162 } 163 result 164 } 165 166 #[inline] to_untyped(&self) -> CFMutableDictionary167 pub fn to_untyped(&self) -> CFMutableDictionary { 168 unsafe { CFMutableDictionary::wrap_under_get_rule(self.0) } 169 } 170 171 /// Returns the same dictionary, but with the types reset to void pointers. 172 /// Equal to `to_untyped`, but is faster since it does not increment the retain count. 173 #[inline] into_untyped(self) -> CFMutableDictionary174 pub fn into_untyped(self) -> CFMutableDictionary { 175 let reference = self.0; 176 mem::forget(self); 177 unsafe { CFMutableDictionary::wrap_under_create_rule(reference) } 178 } 179 180 /// Returns a `CFDictionary` pointing to the same underlying dictionary as this mutable one. 181 #[inline] to_immutable(&self) -> CFDictionary<K, V>182 pub fn to_immutable(&self) -> CFDictionary<K, V> { 183 unsafe { CFDictionary::wrap_under_get_rule(self.0) } 184 } 185 186 // Immutable interface 187 188 #[inline] len(&self) -> usize189 pub fn len(&self) -> usize { 190 unsafe { 191 CFDictionaryGetCount(self.0) as usize 192 } 193 } 194 195 #[inline] is_empty(&self) -> bool196 pub fn is_empty(&self) -> bool { 197 self.len() == 0 198 } 199 200 #[inline] contains_key(&self, key: *const c_void) -> bool201 pub fn contains_key(&self, key: *const c_void) -> bool { 202 unsafe { 203 CFDictionaryContainsKey(self.0, key) != 0 204 } 205 } 206 207 #[inline] find<'a>(&'a self, key: &K) -> Option<ItemRef<'a, V>> where V: FromVoid, K: ToVoid<K>208 pub fn find<'a>(&'a self, key: &K) -> Option<ItemRef<'a, V>> where V: FromVoid, K: ToVoid<K> { 209 unsafe { 210 let mut value: *const c_void = ptr::null(); 211 if CFDictionaryGetValueIfPresent(self.0, key.to_void(), &mut value) != 0 { 212 Some(V::from_void(value)) 213 } else { 214 None 215 } 216 } 217 } 218 219 /// # Panics 220 /// 221 /// Panics if the key is not present in the dictionary. Use `find` to get an `Option` instead 222 /// of panicking. 223 #[inline] get<'a>(&'a self, key: &K) -> ItemRef<'a, V> where V: FromVoid, K: ToVoid<K>224 pub fn get<'a>(&'a self, key: &K) -> ItemRef<'a, V> where V: FromVoid, K: ToVoid<K> { 225 let ptr = key.to_void(); 226 self.find(&key).expect(&format!("No entry found for key {:p}", ptr)) 227 } 228 get_keys_and_values(&self) -> (Vec<*const c_void>, Vec<*const c_void>)229 pub fn get_keys_and_values(&self) -> (Vec<*const c_void>, Vec<*const c_void>) { 230 let length = self.len(); 231 let mut keys = Vec::with_capacity(length); 232 let mut values = Vec::with_capacity(length); 233 234 unsafe { 235 CFDictionaryGetKeysAndValues(self.0, keys.as_mut_ptr(), values.as_mut_ptr()); 236 keys.set_len(length); 237 values.set_len(length); 238 } 239 240 (keys, values) 241 } 242 243 // Mutable interface 244 245 /// Adds the key-value pair to the dictionary if no such key already exist. 246 #[inline] add(&mut self, key: &K, value: &V) where K: ToVoid<K>, V: ToVoid<V>247 pub fn add(&mut self, key: &K, value: &V) where K: ToVoid<K>, V: ToVoid<V> { 248 unsafe { CFDictionaryAddValue(self.0, key.to_void(), value.to_void()) } 249 } 250 251 /// Sets the value of the key in the dictionary. 252 #[inline] set(&mut self, key: K, value: V) where K: ToVoid<K>, V: ToVoid<V>253 pub fn set(&mut self, key: K, value: V) where K: ToVoid<K>, V: ToVoid<V> { 254 unsafe { CFDictionarySetValue(self.0, key.to_void(), value.to_void()) } 255 } 256 257 /// Replaces the value of the key in the dictionary. 258 #[inline] replace(&mut self, key: K, value: V) where K: ToVoid<K>, V: ToVoid<V>259 pub fn replace(&mut self, key: K, value: V) where K: ToVoid<K>, V: ToVoid<V> { 260 unsafe { CFDictionaryReplaceValue(self.0, key.to_void(), value.to_void()) } 261 } 262 263 /// Removes the value of the key from the dictionary. 264 #[inline] remove(&mut self, key: K) where K: ToVoid<K>265 pub fn remove(&mut self, key: K) where K: ToVoid<K> { 266 unsafe { CFDictionaryRemoveValue(self.0, key.to_void()) } 267 } 268 269 #[inline] remove_all(&mut self)270 pub fn remove_all(&mut self) { 271 unsafe { CFDictionaryRemoveAllValues(self.0) } 272 } 273 } 274 275 impl<'a, K, V> From<&'a CFDictionary<K, V>> for CFMutableDictionary<K, V> { 276 /// Creates a new mutable dictionary with the key-value pairs from another dictionary. 277 /// The capacity of the new mutable dictionary is not limited. from(dict: &'a CFDictionary<K, V>) -> Self278 fn from(dict: &'a CFDictionary<K, V>) -> Self { 279 unsafe { 280 let mut_dict_ref = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, dict.0); 281 TCFType::wrap_under_create_rule(mut_dict_ref) 282 } 283 } 284 } 285 286 287 #[cfg(test)] 288 pub mod test { 289 use super::*; 290 use base::{CFType, TCFType}; 291 use boolean::CFBoolean; 292 use number::CFNumber; 293 use string::CFString; 294 295 296 #[test] dictionary()297 fn dictionary() { 298 let bar = CFString::from_static_string("Bar"); 299 let baz = CFString::from_static_string("Baz"); 300 let boo = CFString::from_static_string("Boo"); 301 let foo = CFString::from_static_string("Foo"); 302 let tru = CFBoolean::true_value(); 303 let n42 = CFNumber::from(42); 304 305 let d = CFDictionary::from_CFType_pairs(&[ 306 (bar.as_CFType(), boo.as_CFType()), 307 (baz.as_CFType(), tru.as_CFType()), 308 (foo.as_CFType(), n42.as_CFType()), 309 ]); 310 311 let (v1, v2) = d.get_keys_and_values(); 312 assert!(v1 == &[bar.as_CFTypeRef(), baz.as_CFTypeRef(), foo.as_CFTypeRef()]); 313 assert!(v2 == &[boo.as_CFTypeRef(), tru.as_CFTypeRef(), n42.as_CFTypeRef()]); 314 } 315 316 #[test] mutable_dictionary()317 fn mutable_dictionary() { 318 let bar = CFString::from_static_string("Bar"); 319 let baz = CFString::from_static_string("Baz"); 320 let boo = CFString::from_static_string("Boo"); 321 let foo = CFString::from_static_string("Foo"); 322 let tru = CFBoolean::true_value(); 323 let n42 = CFNumber::from(42); 324 325 let mut d = CFMutableDictionary::<CFString, CFType>::new(); 326 d.add(&bar, &boo.as_CFType()); 327 d.add(&baz, &tru.as_CFType()); 328 d.add(&foo, &n42.as_CFType()); 329 assert_eq!(d.len(), 3); 330 331 let (v1, v2) = d.get_keys_and_values(); 332 assert!(v1 == &[bar.as_CFTypeRef(), baz.as_CFTypeRef(), foo.as_CFTypeRef()]); 333 assert!(v2 == &[boo.as_CFTypeRef(), tru.as_CFTypeRef(), n42.as_CFTypeRef()]); 334 335 d.remove(baz); 336 assert_eq!(d.len(), 2); 337 338 let (v1, v2) = d.get_keys_and_values(); 339 assert!(v1 == &[bar.as_CFTypeRef(), foo.as_CFTypeRef()]); 340 assert!(v2 == &[boo.as_CFTypeRef(), n42.as_CFTypeRef()]); 341 342 d.remove_all(); 343 assert_eq!(d.len(), 0) 344 } 345 346 #[test] dict_find_and_contains_key()347 fn dict_find_and_contains_key() { 348 let dict = CFDictionary::from_CFType_pairs(&[ 349 ( 350 CFString::from_static_string("hello"), 351 CFBoolean::true_value(), 352 ), 353 ]); 354 let key = CFString::from_static_string("hello"); 355 let invalid_key = CFString::from_static_string("foobar"); 356 357 assert!(dict.contains_key(&key)); 358 assert!(!dict.contains_key(&invalid_key)); 359 360 let value = dict.find(&key).unwrap().clone(); 361 assert_eq!(value, CFBoolean::true_value()); 362 assert_eq!(dict.find(&invalid_key), None); 363 } 364 365 #[test] convert_immutable_to_mutable_dict()366 fn convert_immutable_to_mutable_dict() { 367 let dict: CFDictionary<CFString, CFBoolean> = CFDictionary::from_CFType_pairs(&[ 368 (CFString::from_static_string("Foo"), CFBoolean::true_value()), 369 ]); 370 let mut mut_dict = CFMutableDictionary::from(&dict); 371 assert_eq!(dict.retain_count(), 1); 372 assert_eq!(mut_dict.retain_count(), 1); 373 374 assert_eq!(mut_dict.len(), 1); 375 assert_eq!(*mut_dict.get(&CFString::from_static_string("Foo")), CFBoolean::true_value()); 376 377 mut_dict.add(&CFString::from_static_string("Bar"), &CFBoolean::false_value()); 378 assert_eq!(dict.len(), 1); 379 assert_eq!(mut_dict.len(), 2); 380 } 381 382 #[test] mutable_dictionary_as_immutable()383 fn mutable_dictionary_as_immutable() { 384 let mut mut_dict: CFMutableDictionary<CFString, CFBoolean> = CFMutableDictionary::new(); 385 mut_dict.add(&CFString::from_static_string("Bar"), &CFBoolean::false_value()); 386 assert_eq!(mut_dict.retain_count(), 1); 387 388 let dict = mut_dict.to_immutable(); 389 assert_eq!(mut_dict.retain_count(), 2); 390 assert_eq!(dict.retain_count(), 2); 391 assert_eq!(*dict.get(&CFString::from_static_string("Bar")), CFBoolean::false_value()); 392 393 mem::drop(dict); 394 assert_eq!(mut_dict.retain_count(), 1); 395 } 396 } 397