New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add CFPropertyList and methods for casting to subclasses #131
Changes from 1 commit
File filter...
Jump to…
Add CFPropertyList and methods for casting to subclasses
- Loading branch information
| @@ -10,16 +10,18 @@ | ||
| //! Core Foundation property lists | ||
|
|
||
| use std::ptr; | ||
| use std::mem; | ||
|
|
||
| use libc::c_void; | ||
|
|
||
| use error::CFError; | ||
| use data::CFData; | ||
| use base::{TCFType}; | ||
| use base::{CFType, TCFType}; | ||
|
|
||
| pub use core_foundation_sys::propertylist::*; | ||
| use core_foundation_sys::error::CFErrorRef; | ||
| use core_foundation_sys::base::{kCFAllocatorDefault}; | ||
| use core_foundation_sys::base::{CFGetRetainCount, CFGetTypeID, CFIndex, CFRelease, CFRetain, | ||
| CFShow, CFTypeID, kCFAllocatorDefault}; | ||
|
|
||
| pub fn create_with_data(data: CFData, | ||
| options: CFPropertyListMutabilityOptions) | ||
| @@ -56,8 +58,142 @@ pub fn create_data(property_list: *const c_void, format: CFPropertyListFormat) - | ||
| } | ||
| } | ||
|
|
||
|
|
||
| /// Trait for all subclasses of CFPropertyList. | ||
| pub trait CFPropertyListSubClass<Raw>: TCFType<*const Raw> { | ||
faern
Author
Contributor
|
||
| /// Create an instance of the superclass type `CFPropertyList` for this instance. | ||
| fn to_CFPropertyList(&self) -> CFPropertyList { | ||
| unsafe { CFPropertyList::wrap_under_get_rule(self.as_concrete_TypeRef() as *const c_void) } | ||
| } | ||
| } | ||
|
|
||
| impl CFPropertyListSubClass<::data::__CFData> for ::data::CFData {} | ||
| impl CFPropertyListSubClass<::string::__CFString> for ::string::CFString {} | ||
| impl CFPropertyListSubClass<::array::__CFArray> for ::array::CFArray {} | ||
| impl CFPropertyListSubClass<::dictionary::__CFDictionary> for ::dictionary::CFDictionary {} | ||
| impl CFPropertyListSubClass<::date::__CFDate> for ::date::CFDate {} | ||
| impl CFPropertyListSubClass<::number::__CFBoolean> for ::boolean::CFBoolean {} | ||
| impl CFPropertyListSubClass<::number::__CFNumber> for ::number::CFNumber {} | ||
|
|
||
| /// A CFPropertyList struct. This is superclass to CFData, CFString, CFArray, CFDictionary, | ||
| /// CFDate, CFBoolean, and CFNumber. | ||
| /// | ||
| /// This superclass type does not have its own CFTypeID, instead each instance has the CFTypeID of | ||
| /// the subclass it is an instance of. Thus, this type cannot implement the `TCFType` trait, since | ||
| /// it cannot implement the static `TCFType::type_id()` method. | ||
| pub struct CFPropertyList(CFPropertyListRef); | ||
|
|
||
| impl Drop for CFPropertyList { | ||
| fn drop(&mut self) { | ||
| unsafe { CFRelease(self.as_CFTypeRef()) } | ||
| } | ||
| } | ||
|
|
||
| impl CFPropertyList { | ||
| #[inline] | ||
| pub fn as_concrete_TypeRef(&self) -> CFPropertyListRef { | ||
| self.0 | ||
| } | ||
|
|
||
| #[inline] | ||
| pub unsafe fn wrap_under_get_rule(reference: CFPropertyListRef) -> CFPropertyList { | ||
| let reference = mem::transmute(CFRetain(mem::transmute(reference))); | ||
| CFPropertyList(reference) | ||
| } | ||
|
|
||
| #[inline] | ||
| pub fn as_CFType(&self) -> CFType { | ||
| unsafe { CFType::wrap_under_get_rule(self.as_CFTypeRef()) } | ||
| } | ||
|
|
||
| #[inline] | ||
| pub fn as_CFTypeRef(&self) -> ::core_foundation_sys::base::CFTypeRef { | ||
| unsafe { mem::transmute(self.as_concrete_TypeRef()) } | ||
| } | ||
|
|
||
| #[inline] | ||
| pub unsafe fn wrap_under_create_rule(obj: CFPropertyListRef) -> CFPropertyList { | ||
| CFPropertyList(obj) | ||
| } | ||
|
|
||
| /// Returns the reference count of the object. It is unwise to do anything other than test | ||
| /// whether the return value of this method is greater than zero. | ||
| #[inline] | ||
| pub fn retain_count(&self) -> CFIndex { | ||
| unsafe { CFGetRetainCount(self.as_CFTypeRef()) } | ||
| } | ||
|
|
||
| /// Returns the type ID of this object. Will be one of CFData, CFString, CFArray, CFDictionary, | ||
| /// CFDate, CFBoolean, or CFNumber. | ||
| #[inline] | ||
| pub fn type_of(&self) -> CFTypeID { | ||
| unsafe { CFGetTypeID(self.as_CFTypeRef()) } | ||
| } | ||
|
|
||
| /// Writes a debugging version of this object on standard error. | ||
| pub fn show(&self) { | ||
| unsafe { CFShow(self.as_CFTypeRef()) } | ||
| } | ||
|
|
||
| /// Returns true if this value is an instance of another type. | ||
| #[inline] | ||
| pub fn instance_of<OtherConcreteTypeRef, OtherCFType: TCFType<OtherConcreteTypeRef>>( | ||
| &self, | ||
| ) -> bool { | ||
| self.type_of() == <OtherCFType as TCFType<_>>::type_id() | ||
| } | ||
| } | ||
|
|
||
| impl Clone for CFPropertyList { | ||
| #[inline] | ||
| fn clone(&self) -> CFPropertyList { | ||
| unsafe { CFPropertyList::wrap_under_get_rule(self.0) } | ||
| } | ||
| } | ||
|
|
||
| impl PartialEq for CFPropertyList { | ||
| #[inline] | ||
| fn eq(&self, other: &CFPropertyList) -> bool { | ||
| self.as_CFType().eq(&other.as_CFType()) | ||
| } | ||
| } | ||
|
|
||
| impl Eq for CFPropertyList {} | ||
|
|
||
| impl CFPropertyList { | ||
| /// Try to downcast the CFPropertyList to a subclass. Checking if the instance is the correct | ||
| /// subclass happens at runtime and an error is returned if it is not the correct type. | ||
| /// Works similar to `Box::downcast`. | ||
| /// | ||
| /// # Examples | ||
| /// | ||
| /// ``` | ||
| /// # use core_foundation::string::CFString; | ||
| /// # use core_foundation::propertylist::{CFPropertyList, CFPropertyListSubClass}; | ||
| /// # | ||
| /// // Create a string. | ||
| /// let string: CFString = CFString::from_static_string("FooBar"); | ||
| /// // Cast it up to a property list. | ||
| /// let propertylist: CFPropertyList = string.to_CFPropertyList(); | ||
| /// // Cast it down again. | ||
| /// assert!(propertylist.downcast::<_, CFString>().unwrap().to_string() == "FooBar"); | ||
| /// ``` | ||
| pub fn downcast<Raw, T: CFPropertyListSubClass<Raw>>(&self) -> Result<T, ()> { | ||
|
||
| if self.instance_of::<_, T>() { | ||
| Ok(unsafe { T::wrap_under_get_rule(self.0 as *const Raw) }) | ||
| } else { | ||
| Err(()) | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
||
| #[cfg(test)] | ||
| pub mod test { | ||
| use super::*; | ||
| use string::CFString; | ||
| use boolean::CFBoolean; | ||
|
|
||
| #[test] | ||
| fn test_property_list_serialization() { | ||
| use base::{TCFType, CFEqual}; | ||
| @@ -84,4 +220,18 @@ pub mod test { | ||
| assert!(CFEqual(dict1.as_CFTypeRef(), dict2) == 1); | ||
| } | ||
| } | ||
|
|
||
| #[test] | ||
| fn downcast_string() { | ||
| let propertylist = CFString::from_static_string("Bar").to_CFPropertyList(); | ||
| assert!(propertylist.downcast::<_, CFString>().unwrap().to_string() == "Bar"); | ||
| assert!(propertylist.downcast::<_, CFBoolean>().is_err()); | ||
| } | ||
|
|
||
| #[test] | ||
| fn downcast_boolean() { | ||
| let propertylist = CFBoolean::true_value().to_CFPropertyList(); | ||
| assert!(propertylist.downcast::<_, CFBoolean>().is_ok()); | ||
| assert!(propertylist.downcast::<_, CFString>().is_err()); | ||
| } | ||
| } | ||
We should be able to do
pub trait CFPropertyListSubClass: TCFType<*const Self> {and avoid some redundancy in the implementations.