compression/
aa_field_key.rs1use crate::{ffi, util, CompressionError, Result};
2use std::ffi::{c_void, CStr};
3use std::fmt;
4use std::ptr::NonNull;
5
6#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
7pub struct FieldKey(u32);
8
9fn parse_field_key(value: &str) -> Result<FieldKey> {
10 if value.len() != 3 || !value.bytes().all(|byte| byte.is_ascii() && byte != 0) {
11 return Err(CompressionError::InvalidFieldKey {
12 key: value.to_string(),
13 });
14 }
15
16 let upper = value.to_ascii_uppercase();
17 let bytes = upper.as_bytes();
18 Ok(FieldKey::from_bytes([bytes[0], bytes[1], bytes[2]]))
19}
20
21impl FieldKey {
22 pub const ACL: Self = Self::from_bytes(*b"ACL");
23 pub const BTM: Self = Self::from_bytes(*b"BTM");
24 pub const CKS: Self = Self::from_bytes(*b"CKS");
25 pub const CLC: Self = Self::from_bytes(*b"CLC");
26 pub const CTM: Self = Self::from_bytes(*b"CTM");
27 pub const DAT: Self = Self::from_bytes(*b"DAT");
28 pub const DEV: Self = Self::from_bytes(*b"DEV");
29 pub const DE2: Self = Self::from_bytes(*b"DE2");
30 pub const DUZ: Self = Self::from_bytes(*b"DUZ");
31 pub const FLG: Self = Self::from_bytes(*b"FLG");
32 pub const GID: Self = Self::from_bytes(*b"GID");
33 pub const GIN: Self = Self::from_bytes(*b"GIN");
34 pub const HLC: Self = Self::from_bytes(*b"HLC");
35 pub const IDX: Self = Self::from_bytes(*b"IDX");
36 pub const IDZ: Self = Self::from_bytes(*b"IDZ");
37 pub const INO: Self = Self::from_bytes(*b"INO");
38 pub const LNK: Self = Self::from_bytes(*b"LNK");
39 pub const MOD: Self = Self::from_bytes(*b"MOD");
40 pub const MTM: Self = Self::from_bytes(*b"MTM");
41 pub const NLK: Self = Self::from_bytes(*b"NLK");
42 pub const PAT: Self = Self::from_bytes(*b"PAT");
43 pub const SH1: Self = Self::from_bytes(*b"SH1");
44 pub const SH2: Self = Self::from_bytes(*b"SH2");
45 pub const SH3: Self = Self::from_bytes(*b"SH3");
46 pub const SH5: Self = Self::from_bytes(*b"SH5");
47 pub const SIZ: Self = Self::from_bytes(*b"SIZ");
48 pub const SLC: Self = Self::from_bytes(*b"SLC");
49 pub const TYP: Self = Self::from_bytes(*b"TYP");
50 pub const UID: Self = Self::from_bytes(*b"UID");
51 pub const UIN: Self = Self::from_bytes(*b"UIN");
52 pub const XAT: Self = Self::from_bytes(*b"XAT");
53 pub const YAF: Self = Self::from_bytes(*b"YAF");
54
55 pub const fn from_bytes(bytes: [u8; 3]) -> Self {
56 Self(u32::from_le_bytes([bytes[0], bytes[1], bytes[2], 0]))
57 }
58
59 pub fn parse(value: &str) -> Result<Self> {
60 parse_field_key(value)
61 }
62
63 pub(crate) const fn from_raw(raw: u32) -> Self {
64 Self(raw)
65 }
66
67 pub const fn raw(self) -> u32 {
68 self.0
69 }
70
71 pub const fn as_bytes(self) -> [u8; 3] {
72 let [a, b, c, _] = self.0.to_le_bytes();
73 [a, b, c]
74 }
75
76 pub fn as_string(self) -> String {
77 String::from_utf8_lossy(&self.as_bytes()).into_owned()
78 }
79}
80
81impl fmt::Debug for FieldKey {
82 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83 write!(f, "FieldKey({self})")
84 }
85}
86
87impl std::str::FromStr for FieldKey {
88 type Err = CompressionError;
89
90 fn from_str(value: &str) -> Result<Self> {
91 parse_field_key(value)
92 }
93}
94
95impl fmt::Display for FieldKey {
96 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
97 f.write_str(&self.as_string())
98 }
99}
100
101impl TryFrom<&str> for FieldKey {
102 type Error = CompressionError;
103
104 fn try_from(value: &str) -> Result<Self> {
105 parse_field_key(value)
106 }
107}
108
109#[derive(Debug)]
110pub struct FieldKeySet {
111 handle: NonNull<c_void>,
112}
113
114impl FieldKeySet {
115 pub fn new() -> Result<Self> {
116 let handle = unsafe { ffi::aa_field_key::compression_rs_aa_field_key_set_create() };
117 Ok(Self {
118 handle: util::nonnull_handle(handle, "AAFieldKeySetCreate")?,
119 })
120 }
121
122 pub fn from_csv(value: &str) -> Result<Self> {
123 let value = util::cstring("value", value)?;
124 let handle = unsafe {
125 ffi::aa_field_key::compression_rs_aa_field_key_set_create_with_string(value.as_ptr())
126 };
127 Ok(Self {
128 handle: util::nonnull_handle(handle, "AAFieldKeySetCreateWithString")?,
129 })
130 }
131
132 pub(crate) fn as_ptr(&self) -> *mut c_void {
133 self.handle.as_ptr()
134 }
135
136 pub fn clear(&mut self) -> Result<()> {
137 let status =
138 unsafe { ffi::aa_field_key::compression_rs_aa_field_key_set_clear(self.as_ptr()) };
139 util::status_result("AAFieldKeySetClear", status)
140 }
141
142 pub fn contains(&self, key: FieldKey) -> Result<bool> {
143 match unsafe {
144 ffi::aa_field_key::compression_rs_aa_field_key_set_contains_key(
145 self.as_ptr(),
146 key.raw(),
147 )
148 } {
149 value if value < 0 => Err(CompressionError::OperationFailed {
150 operation: "AAFieldKeySetContainsKey",
151 code: value,
152 }),
153 0 => Ok(false),
154 _ => Ok(true),
155 }
156 }
157
158 pub fn insert(&mut self, key: FieldKey) -> Result<()> {
159 let status = unsafe {
160 ffi::aa_field_key::compression_rs_aa_field_key_set_insert_key(self.as_ptr(), key.raw())
161 };
162 util::status_result("AAFieldKeySetInsertKey", status)
163 }
164
165 pub fn remove(&mut self, key: FieldKey) -> Result<()> {
166 let status = unsafe {
167 ffi::aa_field_key::compression_rs_aa_field_key_set_remove_key(self.as_ptr(), key.raw())
168 };
169 util::status_result("AAFieldKeySetRemoveKey", status)
170 }
171
172 pub fn insert_set(&mut self, other: &Self) -> Result<()> {
173 let status = unsafe {
174 ffi::aa_field_key::compression_rs_aa_field_key_set_insert_key_set(
175 self.as_ptr(),
176 other.as_ptr(),
177 )
178 };
179 util::status_result("AAFieldKeySetInsertKeySet", status)
180 }
181
182 pub fn remove_set(&mut self, other: &Self) -> Result<()> {
183 let status = unsafe {
184 ffi::aa_field_key::compression_rs_aa_field_key_set_remove_key_set(
185 self.as_ptr(),
186 other.as_ptr(),
187 )
188 };
189 util::status_result("AAFieldKeySetRemoveKeySet", status)
190 }
191
192 pub fn select_set(&mut self, other: &Self) -> Result<()> {
193 let status = unsafe {
194 ffi::aa_field_key::compression_rs_aa_field_key_set_select_key_set(
195 self.as_ptr(),
196 other.as_ptr(),
197 )
198 };
199 util::status_result("AAFieldKeySetSelectKeySet", status)
200 }
201
202 pub fn len(&self) -> u32 {
203 unsafe { ffi::aa_field_key::compression_rs_aa_field_key_set_get_key_count(self.as_ptr()) }
204 }
205
206 pub fn is_empty(&self) -> bool {
207 self.len() == 0
208 }
209
210 pub fn key(&self, index: u32) -> Result<FieldKey> {
211 if index >= self.len() {
212 return Err(CompressionError::OperationFailed {
213 operation: "AAFieldKeySetGetKey",
214 code: -1,
215 });
216 }
217
218 Ok(FieldKey::from_raw(unsafe {
219 ffi::aa_field_key::compression_rs_aa_field_key_set_get_key(self.as_ptr(), index)
220 }))
221 }
222
223 pub fn serialize(&self) -> Result<String> {
224 let capacity = (self.len() as usize)
225 .saturating_mul(4)
226 .saturating_add(1)
227 .max(1);
228 let mut buffer = vec![0_i8; capacity];
229 let status = unsafe {
230 ffi::aa_field_key::compression_rs_aa_field_key_set_serialize(
231 self.as_ptr(),
232 buffer.len(),
233 buffer.as_mut_ptr(),
234 )
235 };
236 util::status_result("AAFieldKeySetSerialize", status)?;
237
238 let value = unsafe { CStr::from_ptr(buffer.as_ptr()) }
239 .to_str()
240 .map_err(|_| CompressionError::Utf8Error {
241 operation: "AAFieldKeySetSerialize",
242 })?;
243 Ok(value.to_string())
244 }
245}
246
247impl Clone for FieldKeySet {
248 fn clone(&self) -> Self {
249 let handle =
250 unsafe { ffi::aa_field_key::compression_rs_aa_field_key_set_clone(self.as_ptr()) };
251 Self {
252 handle: util::nonnull_handle(handle, "AAFieldKeySetClone")
253 .expect("AAFieldKeySetClone returned null"),
254 }
255 }
256}
257
258impl Drop for FieldKeySet {
259 fn drop(&mut self) {
260 unsafe { ffi::aa_field_key::compression_rs_aa_field_key_set_release(self.as_ptr()) };
261 }
262}