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