1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
extern crate file_metadata_mditem_macros;

use std::marker::PhantomData;

use core_foundation_sys::base::{TCFTypeRef, CFTypeID};
use core_foundation::string::{CFString, CFStringRef};
use core_foundation::array::{CFArray, CFArrayRef};
use core_foundation::base::TCFType;
use libc::c_void;

#[repr(C)]
pub struct __MDItemRef(c_void);
pub type MDItemRef = *const __MDItemRef;

#[link(name = "CoreServices", kind = "framework")]
extern "C" {
    fn MDItemCopyAttribute(item: MDItemRef, name: CFStringRef) -> *const c_void;
    fn MDItemCopyAttributeNames(item: MDItemRef) -> CFArrayRef;
    fn MDItemGetTypeID() -> CFTypeID;
}

pub struct Attribute<T> {
    pub key_getter: fn() -> CFStringRef,
    pub phantom: PhantomData<T>
}

impl<T: TCFType> Attribute<T> {
    pub fn key(&self) -> CFStringRef {
        (self.key_getter)()
    }
}

pub mod attributes;

declare_TCFType!{
    MDItem, MDItemRef
}
impl_TCFType!(MDItem, MDItemRef, MDItemGetTypeID);

impl MDItem {
    pub fn attributes(&self) -> CFArray<CFString> {
        unsafe {
            TCFType::wrap_under_create_rule(MDItemCopyAttributeNames(self.0))
        }
    }

    #[inline]
    pub fn get<T>(&self, attr: Attribute<T>) -> Option<T> where T: TCFType {
        let value = unsafe { MDItemCopyAttribute(self.0, attr.key()) };

        if value.is_null() {
            None
        } else {
            Some(unsafe { T::wrap_under_create_rule(T::Ref::from_void_ptr(value)) })
        }
    }
}

#[cfg(test)]
mod tests {
    use super::attributes::URL;
    use core_foundation::string::CFString;
    use core_foundation::base::TCFType;

    #[test]
    fn it_works() {
        println!("{:#?}", unsafe { CFString::wrap_under_get_rule(URL.key()) });
    }
}