apple_cf/cf/
property_list.rs1#![allow(clippy::missing_errors_doc)]
4use super::{AsCFType, CFData, CFError as CoreFoundationError, CFReadStream, CFType, CFWriteStream};
26use crate::ffi;
27use std::fmt;
28
29#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
31#[repr(isize)]
32pub enum CFPropertyListFormat {
33 OpenStep = 1,
34 XmlV1_0 = 100,
35 BinaryV1_0 = 200,
36}
37
38impl TryFrom<isize> for CFPropertyListFormat {
39 type Error = isize;
40
41 fn try_from(value: isize) -> Result<Self, Self::Error> {
42 match value {
43 1 => Ok(Self::OpenStep),
44 100 => Ok(Self::XmlV1_0),
45 200 => Ok(Self::BinaryV1_0),
46 other => Err(other),
47 }
48 }
49}
50
51#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
53pub struct CFPropertyListMutabilityOptions(u64);
54
55impl CFPropertyListMutabilityOptions {
56 pub const IMMUTABLE: Self = Self(0);
58 pub const MUTABLE_CONTAINERS: Self = Self(1 << 0);
60 pub const MUTABLE_CONTAINERS_AND_LEAVES: Self = Self(1 << 1);
62
63 #[must_use]
65 pub const fn from_bits(bits: u64) -> Self {
66 Self(bits)
67 }
68
69 #[must_use]
71 pub const fn as_u64(self) -> u64 {
72 self.0
73 }
74
75 #[must_use]
77 pub const fn contains(self, other: Self) -> bool {
78 (self.0 & other.0) == other.0
79 }
80}
81
82impl From<CFPropertyListMutabilityOptions> for u64 {
83 fn from(options: CFPropertyListMutabilityOptions) -> Self {
84 options.0
85 }
86}
87
88#[derive(Debug)]
90pub enum CFPropertyListError {
91 CoreFoundation(CoreFoundationError),
93 Null(crate::CFError),
95}
96
97impl fmt::Display for CFPropertyListError {
98 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99 match self {
100 Self::CoreFoundation(error) => fmt::Display::fmt(error, f),
101 Self::Null(error) => fmt::Display::fmt(error, f),
102 }
103 }
104}
105
106impl std::error::Error for CFPropertyListError {}
107
108fn property_list_error(
109 operation: &'static str,
110 error_ptr: *mut std::ffi::c_void,
111) -> CFPropertyListError {
112 CoreFoundationError::from_raw(error_ptr)
113 .map_or_else(|| CFPropertyListError::Null(crate::CFError::new(operation)), CFPropertyListError::CoreFoundation)
114}
115
116fn property_list_format(raw: isize) -> CFPropertyListFormat {
117 CFPropertyListFormat::try_from(raw)
118 .expect("Core Foundation returned an unknown CFPropertyListFormat")
119}
120
121pub struct CFPropertyList;
123
124impl CFPropertyList {
125 pub fn create_deep_copy(
127 property_list: &dyn AsCFType,
128 options: CFPropertyListMutabilityOptions,
129 ) -> Result<CFType, crate::CFError> {
130 let ptr = unsafe {
131 ffi::cf_property_list_create_deep_copy(property_list.as_ptr(), options.as_u64())
132 };
133 CFType::from_raw(ptr).ok_or(crate::CFError::new("CFPropertyListCreateDeepCopy"))
134 }
135
136 pub fn create_with_data(
138 data: &CFData,
139 options: CFPropertyListMutabilityOptions,
140 ) -> Result<(CFType, CFPropertyListFormat), CFPropertyListError> {
141 let mut format = 0_isize;
142 let mut error = std::ptr::null_mut();
143 let ptr = unsafe {
144 ffi::cf_property_list_create_with_data(
145 data.as_ptr(),
146 options.as_u64(),
147 &mut format,
148 &mut error,
149 )
150 };
151 CFType::from_raw(ptr)
152 .map(|value| (value, property_list_format(format)))
153 .ok_or_else(|| property_list_error("CFPropertyListCreateWithData", error))
154 }
155
156 pub fn create_with_stream(
158 stream: &CFReadStream,
159 stream_length: usize,
160 options: CFPropertyListMutabilityOptions,
161 ) -> Result<(CFType, CFPropertyListFormat), CFPropertyListError> {
162 let mut format = 0_isize;
163 let mut error = std::ptr::null_mut();
164 let stream_length = isize::try_from(stream_length).unwrap_or(isize::MAX);
165 let ptr = unsafe {
166 ffi::cf_property_list_create_with_stream(
167 stream.as_ptr(),
168 stream_length,
169 options.as_u64(),
170 &mut format,
171 &mut error,
172 )
173 };
174 CFType::from_raw(ptr)
175 .map(|value| (value, property_list_format(format)))
176 .ok_or_else(|| property_list_error("CFPropertyListCreateWithStream", error))
177 }
178
179 pub fn create_data(
181 property_list: &dyn AsCFType,
182 format: CFPropertyListFormat,
183 options: u64,
184 ) -> Result<CFData, CFPropertyListError> {
185 let mut error = std::ptr::null_mut();
186 let ptr = unsafe {
187 ffi::cf_property_list_create_data(
188 property_list.as_ptr(),
189 format as isize,
190 options,
191 &mut error,
192 )
193 };
194 CFData::from_raw(ptr).ok_or_else(|| property_list_error("CFPropertyListCreateData", error))
195 }
196
197 pub fn write(
199 property_list: &dyn AsCFType,
200 stream: &CFWriteStream,
201 format: CFPropertyListFormat,
202 options: u64,
203 ) -> Result<usize, CFPropertyListError> {
204 let mut error = std::ptr::null_mut();
205 let written = unsafe {
206 ffi::cf_property_list_write(
207 property_list.as_ptr(),
208 stream.as_ptr(),
209 format as isize,
210 options,
211 &mut error,
212 )
213 };
214 if written > 0 {
215 usize::try_from(written).map_err(|_| {
216 CFPropertyListError::Null(crate::CFError::new("CFPropertyListWrite overflow"))
217 })
218 } else {
219 Err(property_list_error("CFPropertyListWrite", error))
220 }
221 }
222
223 #[must_use]
225 pub fn is_valid(property_list: &dyn AsCFType, format: CFPropertyListFormat) -> bool {
226 unsafe { ffi::cf_property_list_is_valid(property_list.as_ptr(), format as isize) }
227 }
228}