bnr_xfs/xfs/
xfs_struct.rs

1//! XFS `struct` types.
2
3use std::fmt;
4
5use crate::{Error, Result};
6
7use super::value::XfsValue;
8
9/// Represents an XFS `struct` containing an [XfsMember].
10#[repr(C)]
11#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
12#[serde(rename = "struct")]
13pub struct XfsStruct {
14    #[serde(rename = "$value", default)]
15    members: Vec<ListMember>,
16}
17
18impl XfsStruct {
19    /// Creates a new [XfsStruct].
20    pub const fn new() -> Self {
21        Self {
22            members: Vec::new(),
23        }
24    }
25
26    /// Creates a new [XfsStruct] with the provided [XfsMember].
27    pub fn create<M: IntoIterator<Item = XfsMember>>(members: M) -> Self {
28        Self {
29            members: members.into_iter().map(ListMember::from).collect(),
30        }
31    }
32
33    /// Gets a reference to the list of [XfsMember].
34    pub fn members(&self) -> &[ListMember] {
35        self.members.as_ref()
36    }
37
38    /// Gets a mutable reference to the list of [XfsMember].
39    pub fn members_mut(&mut self) -> &mut [ListMember] {
40        self.members.as_mut()
41    }
42
43    /// Sets the list of [XfsMember].
44    pub fn set_members<M: IntoIterator<Item = XfsMember>>(&mut self, members: M) {
45        self.members = members.into_iter().map(ListMember::from).collect();
46    }
47
48    /// Builder function that sets the [XfsMember].
49    pub fn with_members<M: IntoIterator<Item = XfsMember>>(mut self, members: M) -> Self {
50        self.set_members(members);
51        self
52    }
53
54    /// Searches for an [XfsMember] with a matching `name`.
55    pub fn find_member(&self, name: &str) -> Result<&XfsMember> {
56        self.members
57            .iter()
58            .map(|m| m.inner())
59            .find(|m| m.name() == name)
60            .ok_or(Error::Xfs(format!(r#"Missing member "{name}""#)))
61    }
62}
63
64impl fmt::Display for XfsStruct {
65    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
66        write!(f, r#"{{"members": ["#)?;
67        for (i, member) in self.members.iter().enumerate() {
68            if i != 0 {
69                write!(f, ", ")?;
70            }
71            write!(f, "{member}")?;
72        }
73        write!(f, "]}}")
74    }
75}
76
77/// Wrapper for an [XfsStruct] value used in a collection.
78#[repr(C)]
79#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
80pub enum ListStruct {
81    #[serde(rename = "struct")]
82    Struct(XfsStruct),
83}
84
85impl ListStruct {
86    /// Creates a new [ListStruct].
87    pub const fn new() -> Self {
88        Self::Struct(XfsStruct::new())
89    }
90
91    /// Creates a new [ListStruct].
92    pub const fn create(xfs: XfsStruct) -> Self {
93        Self::Struct(xfs)
94    }
95
96    /// Destructures the [ListStruct] enum into its inner representation.
97    pub const fn inner(&self) -> &XfsStruct {
98        match self {
99            Self::Struct(s) => s,
100        }
101    }
102
103    /// Destructures the [ListStruct] enum into its mutable inner representation.
104    pub fn inner_mut(&mut self) -> &mut XfsStruct {
105        match self {
106            Self::Struct(s) => s,
107        }
108    }
109
110    /// Converts the [ListStruct] into the inner [XfsStruct].
111    pub fn into_inner(self) -> XfsStruct {
112        match self {
113            Self::Struct(s) => s,
114        }
115    }
116}
117
118impl fmt::Display for ListStruct {
119    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120        match self {
121            Self::Struct(s) => write!(f, "{s}"),
122        }
123    }
124}
125
126/// Represents an XFS `struct` containing an [XfsMember].
127#[repr(C)]
128#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
129#[serde(rename = "member")]
130pub struct XfsMember {
131    name: String,
132    value: XfsValue,
133}
134
135impl XfsMember {
136    /// Creates a new [XfsMember].
137    pub const fn new() -> Self {
138        Self {
139            name: String::new(),
140            value: XfsValue::new(),
141        }
142    }
143
144    /// Creates a new [XfsMember] with the provided parameters.
145    pub fn create<S: Into<String>>(name: S, value: XfsValue) -> Self {
146        Self {
147            name: name.into(),
148            value,
149        }
150    }
151
152    /// Gets a reference to the [XfsMember] name.
153    pub fn name(&self) -> &str {
154        self.name.as_str()
155    }
156
157    /// Sets the [XfsMember] name.
158    pub fn set_name<S: Into<String>>(&mut self, name: S) {
159        self.name = name.into();
160    }
161
162    /// Builder function that sets the [XfsMember] name.
163    pub fn with_name<S: Into<String>>(mut self, name: S) -> Self {
164        self.set_name(name);
165        self
166    }
167
168    /// Gets a reference to the [XfsValue].
169    pub const fn value(&self) -> &XfsValue {
170        &self.value
171    }
172
173    /// Sets the [XfsValue].
174    pub fn set_value(&mut self, value: XfsValue) {
175        self.value = value;
176    }
177
178    /// Builder function that sets the [XfsValue].
179    pub fn with_value(mut self, value: XfsValue) -> Self {
180        self.set_value(value);
181        self
182    }
183}
184
185impl fmt::Display for XfsMember {
186    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
187        write!(f, "{{")?;
188        write!(f, r#""name": "{}", "#, self.name)?;
189        write!(f, r#""value": {}"#, self.value)?;
190        write!(f, "}}")
191    }
192}
193
194/// Wrapper for an [XfsMember] value used in a collection.
195#[repr(C)]
196#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
197pub enum ListMember {
198    #[serde(rename = "member")]
199    Member(XfsMember),
200}
201
202impl ListMember {
203    /// Creates a new [ListMember].
204    pub const fn new() -> Self {
205        Self::Member(XfsMember::new())
206    }
207
208    /// Creates a new [ListMember] from the provided [XfsMember].
209    pub const fn create(m: XfsMember) -> Self {
210        Self::Member(m)
211    }
212
213    /// Creates a new [ListMember] from the provided [XfsMember].
214    pub const fn from_inner(m: XfsMember) -> Self {
215        Self::Member(m)
216    }
217
218    /// Gets a reference to the inner [XfsMember].
219    pub const fn inner(&self) -> &XfsMember {
220        match self {
221            Self::Member(m) => m,
222        }
223    }
224
225    /// Gets a mutable reference to the inner [XfsMember].
226    pub fn inner_mut(&mut self) -> &mut XfsMember {
227        match self {
228            Self::Member(m) => m,
229        }
230    }
231
232    /// Converts the [ListMember] into an [XfsMmeber].
233    pub fn into_inner(self) -> XfsMember {
234        match self {
235            Self::Member(m) => m,
236        }
237    }
238}
239
240impl From<&XfsMember> for ListMember {
241    fn from(val: &XfsMember) -> Self {
242        val.clone().into()
243    }
244}
245
246impl From<XfsMember> for ListMember {
247    fn from(val: XfsMember) -> Self {
248        Self::from_inner(val)
249    }
250}
251
252impl From<&ListMember> for XfsMember {
253    fn from(val: &ListMember) -> Self {
254        val.clone().into()
255    }
256}
257
258impl From<ListMember> for XfsMember {
259    fn from(val: ListMember) -> Self {
260        val.into_inner()
261    }
262}
263
264impl fmt::Display for ListMember {
265    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
266        match self {
267            Self::Member(s) => write!(f, "{s}"),
268        }
269    }
270}
271
272#[cfg(test)]
273mod tests {
274    use super::*;
275    use crate::{xfs, Result};
276
277    #[test]
278    fn test_xfs_value_struct_serde() -> Result<()> {
279        let exp_xml = r#"<?xml version="1.0" encoding="UTF-8"?><value><struct><member><name>test</name><value><i4>16</i4></value></member></struct></value>"#;
280
281        let exp_struct = XfsValue::new().with_xfs_struct(XfsStruct::create([XfsMember::create(
282            "test",
283            XfsValue::new().with_i4(16),
284        )]));
285
286        assert_eq!(xfs::to_string(&exp_struct)?.as_str(), exp_xml);
287        assert_eq!(xfs::from_str::<XfsValue>(exp_xml)?, exp_struct);
288
289        Ok(())
290    }
291}