Skip to main content

compression/
aa_field_key.rs

1use 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}