diff --git a/core-foundation/src/dictionary.rs b/core-foundation/src/dictionary.rs index 10b9158..5b808c3 100644 --- a/core-foundation/src/dictionary.rs +++ b/core-foundation/src/dictionary.rs @@ -19,6 +19,7 @@ use std::marker::PhantomData; use base::{ItemRef, FromVoid, ToVoid}; use base::{CFIndexConvertible, TCFType}; +use ConcreteCFType; // consume the type parameters with PhantomDatas pub struct CFDictionary(CFDictionaryRef, PhantomData, PhantomData); @@ -32,6 +33,8 @@ impl Drop for CFDictionary { impl_TCFType!(CFDictionary, CFDictionaryRef, CFDictionaryGetTypeID); impl_CFTypeDescription!(CFDictionary); +unsafe impl ConcreteCFType for CFDictionary<*const c_void, *const c_void> {} + impl CFDictionary { pub fn from_CFType_pairs(pairs: &[(K, V)]) -> CFDictionary where K: TCFType, V: TCFType { let (keys, values): (Vec, Vec) = pairs @@ -50,6 +53,20 @@ impl CFDictionary { } } + #[inline] + pub fn to_untyped(&self) -> CFDictionary { + unsafe { CFDictionary::wrap_under_get_rule(self.0) } + } + + /// Returns the same dictionary, but with the types reset to void pointers. + /// Equal to `to_untyped`, but is faster since it does not increment the retain count. + #[inline] + pub fn into_untyped(self) -> CFDictionary { + let reference = self.0; + mem::forget(self); + unsafe { CFDictionary::wrap_under_create_rule(reference) } + } + #[inline] pub fn len(&self) -> usize { unsafe { @@ -146,6 +163,26 @@ impl CFMutableDictionary { result } + #[inline] + pub fn to_untyped(&self) -> CFMutableDictionary { + unsafe { CFMutableDictionary::wrap_under_get_rule(self.0) } + } + + /// Returns the same dictionary, but with the types reset to void pointers. + /// Equal to `to_untyped`, but is faster since it does not increment the retain count. + #[inline] + pub fn into_untyped(self) -> CFMutableDictionary { + let reference = self.0; + mem::forget(self); + unsafe { CFMutableDictionary::wrap_under_create_rule(reference) } + } + + /// Returns a `CFDictionary` pointing to the same underlying dictionary as this mutable one. + #[inline] + pub fn to_immutable(&self) -> CFDictionary { + unsafe { CFDictionary::wrap_under_get_rule(self.0) } + } + // Immutable interface #[inline] @@ -235,6 +272,17 @@ impl CFMutableDictionary { } } +impl<'a, K, V> From<&'a CFDictionary> for CFMutableDictionary { + /// Creates a new mutable dictionary with the key-value pairs from another dictionary. + /// The capacity of the new mutable dictionary is not limited. + fn from(dict: &'a CFDictionary) -> Self { + unsafe { + let mut_dict_ref = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, dict.0); + TCFType::wrap_under_create_rule(mut_dict_ref) + } + } +} + #[cfg(test)] pub mod test { @@ -313,4 +361,36 @@ pub mod test { assert_eq!(value, CFBoolean::true_value()); assert_eq!(dict.find(&invalid_key), None); } + + #[test] + fn convert_immutable_to_mutable_dict() { + let dict: CFDictionary = CFDictionary::from_CFType_pairs(&[ + (CFString::from_static_string("Foo"), CFBoolean::true_value()), + ]); + let mut mut_dict = CFMutableDictionary::from(&dict); + assert_eq!(dict.retain_count(), 1); + assert_eq!(mut_dict.retain_count(), 1); + + assert_eq!(mut_dict.len(), 1); + assert_eq!(*mut_dict.get(&CFString::from_static_string("Foo")), CFBoolean::true_value()); + + mut_dict.add(&CFString::from_static_string("Bar"), &CFBoolean::false_value()); + assert_eq!(dict.len(), 1); + assert_eq!(mut_dict.len(), 2); + } + + #[test] + fn mutable_dictionary_as_immutable() { + let mut mut_dict: CFMutableDictionary = CFMutableDictionary::new(); + mut_dict.add(&CFString::from_static_string("Bar"), &CFBoolean::false_value()); + assert_eq!(mut_dict.retain_count(), 1); + + let dict = mut_dict.to_immutable(); + assert_eq!(mut_dict.retain_count(), 2); + assert_eq!(dict.retain_count(), 2); + assert_eq!(*dict.get(&CFString::from_static_string("Bar")), CFBoolean::false_value()); + + mem::drop(dict); + assert_eq!(mut_dict.retain_count(), 1); + } } diff --git a/core-foundation/src/lib.rs b/core-foundation/src/lib.rs index 814c240..d1c88aa 100644 --- a/core-foundation/src/lib.rs +++ b/core-foundation/src/lib.rs @@ -97,21 +97,21 @@ macro_rules! impl_TCFType { unsafe impl<'a> $crate::base::ToVoid<$ty> for &'a $ty { fn to_void(&self) -> *const ::std::os::raw::c_void { - use $crate::base::TCFTypeRef; + use $crate::base::TCFTypeRef; self.as_concrete_TypeRef().as_void_ptr() } } unsafe impl $crate::base::ToVoid<$ty> for $ty { fn to_void(&self) -> *const ::std::os::raw::c_void { - use $crate::base::TCFTypeRef; + use $crate::base::TCFTypeRef; self.as_concrete_TypeRef().as_void_ptr() } } unsafe impl $crate::base::ToVoid<$ty> for $ty_ref { fn to_void(&self) -> *const ::std::os::raw::c_void { - use $crate::base::TCFTypeRef; + use $crate::base::TCFTypeRef; self.as_void_ptr() } }