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
125#[derive(Debug)]
127pub struct CFPropertyList;
128
129impl CFPropertyList {
130 pub fn create_deep_copy(
132 property_list: &dyn AsCFType,
133 options: CFPropertyListMutabilityOptions,
134 ) -> Result<CFType, crate::CFError> {
135 let ptr = unsafe {
136 ffi::cf_property_list_create_deep_copy(property_list.as_ptr(), options.as_u64())
137 };
138 CFType::from_raw(ptr).ok_or(crate::CFError::new("CFPropertyListCreateDeepCopy"))
139 }
140
141 pub fn create_with_data(
143 data: &CFData,
144 options: CFPropertyListMutabilityOptions,
145 ) -> Result<(CFType, CFPropertyListFormat), CFPropertyListError> {
146 let mut format = 0_isize;
147 let mut error = std::ptr::null_mut();
148 let ptr = unsafe {
149 ffi::cf_property_list_create_with_data(
150 data.as_ptr(),
151 options.as_u64(),
152 &mut format,
153 &mut error,
154 )
155 };
156 CFType::from_raw(ptr)
157 .map(|value| (value, property_list_format(format)))
158 .ok_or_else(|| property_list_error("CFPropertyListCreateWithData", error))
159 }
160
161 pub fn create_with_stream(
163 stream: &CFReadStream,
164 stream_length: usize,
165 options: CFPropertyListMutabilityOptions,
166 ) -> Result<(CFType, CFPropertyListFormat), CFPropertyListError> {
167 let mut format = 0_isize;
168 let mut error = std::ptr::null_mut();
169 let stream_length = isize::try_from(stream_length).unwrap_or(isize::MAX);
170 let ptr = unsafe {
171 ffi::cf_property_list_create_with_stream(
172 stream.as_ptr(),
173 stream_length,
174 options.as_u64(),
175 &mut format,
176 &mut error,
177 )
178 };
179 CFType::from_raw(ptr)
180 .map(|value| (value, property_list_format(format)))
181 .ok_or_else(|| property_list_error("CFPropertyListCreateWithStream", error))
182 }
183
184 pub fn create_data(
186 property_list: &dyn AsCFType,
187 format: CFPropertyListFormat,
188 options: u64,
189 ) -> Result<CFData, CFPropertyListError> {
190 let mut error = std::ptr::null_mut();
191 let ptr = unsafe {
192 ffi::cf_property_list_create_data(
193 property_list.as_ptr(),
194 format as isize,
195 options,
196 &mut error,
197 )
198 };
199 CFData::from_raw(ptr).ok_or_else(|| property_list_error("CFPropertyListCreateData", error))
200 }
201
202 pub fn write(
204 property_list: &dyn AsCFType,
205 stream: &CFWriteStream,
206 format: CFPropertyListFormat,
207 options: u64,
208 ) -> Result<usize, CFPropertyListError> {
209 let mut error = std::ptr::null_mut();
210 let written = unsafe {
211 ffi::cf_property_list_write(
212 property_list.as_ptr(),
213 stream.as_ptr(),
214 format as isize,
215 options,
216 &mut error,
217 )
218 };
219 if written > 0 {
220 usize::try_from(written).map_err(|_| {
221 CFPropertyListError::Null(crate::CFError::new("CFPropertyListWrite overflow"))
222 })
223 } else {
224 Err(property_list_error("CFPropertyListWrite", error))
225 }
226 }
227
228 #[must_use]
230 pub fn is_valid(property_list: &dyn AsCFType, format: CFPropertyListFormat) -> bool {
231 unsafe { ffi::cf_property_list_is_valid(property_list.as_ptr(), format as isize) }
232 }
233}