1use std::fmt;
4
5use super::{array::XfsArray, xfs_struct::XfsStruct};
6
7#[derive(Clone, Debug, PartialEq, serde::Deserialize)]
9#[serde(rename = "value")]
10pub struct XfsValue {
11 #[serde(default)]
13 pub(crate) int: Option<i64>,
14 #[serde(default)]
16 pub(crate) i4: Option<i32>,
17 #[serde(default)]
19 pub(crate) base64: Option<String>,
20 #[serde(rename = "dateTime.iso8601", default)]
22 pub(crate) date_time: Option<String>,
23 #[serde(default)]
28 pub(crate) boolean: Option<u8>,
29 #[serde(default)]
31 pub(crate) string: Option<String>,
32 #[serde(rename = "struct", default)]
34 pub(crate) xfs_struct: Option<XfsStruct>,
35 #[serde(default)]
37 pub(crate) array: Option<XfsArray>,
38}
39
40impl XfsValue {
41 pub const fn new() -> Self {
43 Self {
44 int: None,
45 i4: None,
46 base64: None,
47 date_time: None,
48 boolean: None,
49 string: None,
50 xfs_struct: None,
51 array: None,
52 }
53 }
54
55 pub const fn is_empty(&self) -> bool {
57 self.int.is_none()
58 && self.i4.is_none()
59 && self.base64.is_none()
60 && self.date_time.is_none()
61 && self.boolean.is_none()
62 && self.string.is_none()
63 && self.xfs_struct.is_none()
64 && self.array.is_none()
65 }
66
67 pub const fn int(&self) -> Option<&i64> {
69 self.int.as_ref()
70 }
71
72 pub fn set_int(&mut self, int: i64) {
74 self.int = Some(int);
75 }
76
77 pub fn unset_int(&mut self) -> Option<i64> {
79 self.int.take()
80 }
81
82 pub fn with_int(mut self, int: i64) -> Self {
84 self.set_int(int);
85 self
86 }
87
88 pub const fn i4(&self) -> Option<&i32> {
90 self.i4.as_ref()
91 }
92
93 pub fn set_i4(&mut self, i4: i32) {
95 self.i4 = Some(i4);
96 }
97
98 pub fn unset_i4(&mut self) -> Option<i32> {
100 self.i4.take()
101 }
102
103 pub fn with_i4(mut self, i4: i32) -> Self {
105 self.set_i4(i4);
106 self
107 }
108
109 pub fn base64(&self) -> Option<&str> {
111 self.base64.as_deref()
112 }
113
114 pub fn set_base64<S: Into<String>>(&mut self, base64: S) {
116 self.base64 = Some(base64.into());
117 }
118
119 pub fn unset_base64(&mut self) -> Option<String> {
121 self.base64.take()
122 }
123
124 pub fn with_base64<S: Into<String>>(mut self, base64: S) -> Self {
126 self.set_base64(base64);
127 self
128 }
129
130 pub fn date_time(&self) -> Option<&str> {
132 self.date_time.as_deref()
133 }
134
135 pub fn set_date_time<S: Into<String>>(&mut self, date_time: S) {
137 self.date_time = Some(date_time.into());
138 }
139
140 pub fn unset_date_time(&mut self) -> Option<String> {
142 self.date_time.take()
143 }
144
145 pub fn with_date_time<S: Into<String>>(mut self, date_time: S) -> Self {
147 self.set_date_time(date_time);
148 self
149 }
150
151 pub fn string(&self) -> Option<&str> {
153 self.string.as_deref()
154 }
155
156 pub fn set_string<S: Into<String>>(&mut self, string: S) {
158 self.string = Some(string.into());
159 }
160
161 pub fn unset_string(&mut self) -> Option<String> {
163 self.string.take()
164 }
165
166 pub fn with_string<S: Into<String>>(mut self, string: S) -> Self {
168 self.set_string(string);
169 self
170 }
171
172 pub const fn xfs_struct(&self) -> Option<&XfsStruct> {
174 self.xfs_struct.as_ref()
175 }
176
177 pub fn set_xfs_struct(&mut self, xfs_struct: XfsStruct) {
179 self.xfs_struct = Some(xfs_struct);
180 }
181
182 pub fn unset_xfs_struct(&mut self) -> Option<XfsStruct> {
184 self.xfs_struct.take()
185 }
186
187 pub fn with_xfs_struct(mut self, xfs_struct: XfsStruct) -> Self {
189 self.set_xfs_struct(xfs_struct);
190 self
191 }
192
193 pub const fn boolean(&self) -> Option<&u8> {
195 self.boolean.as_ref()
196 }
197
198 pub fn set_boolean(&mut self, boolean: u8) {
200 self.boolean = Some(boolean);
201 }
202
203 pub fn unset_boolean(&mut self) -> Option<u8> {
205 self.boolean.take()
206 }
207
208 pub fn with_boolean(mut self, boolean: u8) -> Self {
210 self.set_boolean(boolean);
211 self
212 }
213
214 pub const fn array(&self) -> Option<&XfsArray> {
216 self.array.as_ref()
217 }
218
219 pub fn set_array(&mut self, xfs_array: XfsArray) {
221 self.array = Some(xfs_array);
222 }
223
224 pub fn unset_array(&mut self) -> Option<XfsArray> {
226 self.array.take()
227 }
228
229 pub fn with_array(mut self, xfs_array: XfsArray) -> Self {
231 self.set_array(xfs_array);
232 self
233 }
234}
235
236impl serde::Serialize for XfsValue {
237 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
238 where
239 S: serde::Serializer,
240 {
241 use serde::ser::SerializeStruct;
242
243 let mut ser = serializer.serialize_struct("value", 8)?;
244
245 if let Some(v) = self.int() {
246 ser.serialize_field("int", v)?;
247 }
248
249 if let Some(v) = self.i4() {
250 ser.serialize_field("i4", v)?;
251 }
252
253 if let Some(v) = self.base64() {
254 ser.serialize_field("base64", v)?;
255 }
256
257 if let Some(v) = self.date_time() {
258 ser.serialize_field("dateTime.iso8601", v)?;
259 }
260
261 if let Some(v) = self.boolean() {
262 ser.serialize_field("boolean", v)?;
263 }
264
265 if let Some(v) = self.string() {
266 ser.serialize_field("string", v)?;
267 }
268
269 if let Some(v) = self.xfs_struct() {
270 ser.serialize_field("struct", v)?;
271 }
272
273 if let Some(v) = self.array() {
274 ser.serialize_field("array", v)?;
275 }
276
277 ser.end()
278 }
279}
280
281impl_default!(XfsValue);
282
283impl fmt::Display for XfsValue {
284 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
285 write!(f, "{{")?;
286 let mut has_field = false;
287 if let Some(v) = self.int() {
288 write!(f, r#""int": {v}"#)?;
289 has_field = true;
290 }
291 if let Some(v) = self.i4() {
292 if has_field {
293 write!(f, ", ")?;
294 }
295 write!(f, r#""i4": {v}"#)?;
296 has_field = true;
297 }
298 if let Some(v) = self.base64() {
299 if has_field {
300 write!(f, ", ")?;
301 }
302 write!(f, r#""base64": {v}"#)?;
303 has_field = true;
304 }
305 if let Some(v) = self.date_time() {
306 if has_field {
307 write!(f, ", ")?;
308 }
309 write!(f, r#""date_time": {v}"#)?;
310 has_field = true;
311 }
312 if let Some(v) = self.boolean() {
313 if has_field {
314 write!(f, ", ")?;
315 }
316 write!(f, r#""boolean": {v}"#)?;
317 has_field = true;
318 }
319 if let Some(v) = self.string() {
320 if has_field {
321 write!(f, ", ")?;
322 }
323 write!(f, r#""string": "{v}""#)?;
324 has_field = true;
325 }
326 if let Some(v) = self.xfs_struct() {
327 if has_field {
328 write!(f, ", ")?;
329 }
330 write!(f, r#""struct": {v}"#)?;
331 has_field = true;
332 }
333 if let Some(v) = self.array() {
334 if has_field {
335 write!(f, ", ")?;
336 }
337 write!(f, r#""array": {v}"#)?;
338 }
339 write!(f, "}}")
340 }
341}
342
343#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
345pub enum ListValue {
346 #[serde(rename = "value")]
347 Value(XfsValue),
348}
349
350impl ListValue {
351 pub const fn new() -> Self {
353 Self::Value(XfsValue::new())
354 }
355
356 pub const fn create(value: XfsValue) -> Self {
358 Self::Value(value)
359 }
360
361 pub const fn inner(&self) -> &XfsValue {
363 match self {
364 Self::Value(v) => v,
365 }
366 }
367
368 pub fn into_inner(self) -> XfsValue {
370 match self {
371 Self::Value(v) => v,
372 }
373 }
374}
375
376impl From<XfsValue> for ListValue {
377 fn from(val: XfsValue) -> Self {
378 Self::create(val)
379 }
380}
381
382impl From<&XfsValue> for ListValue {
383 fn from(val: &XfsValue) -> Self {
384 val.clone().into()
385 }
386}
387
388impl From<ListValue> for XfsValue {
389 fn from(val: ListValue) -> Self {
390 val.into_inner()
391 }
392}
393
394impl From<&ListValue> for XfsValue {
395 fn from(val: &ListValue) -> Self {
396 val.clone().into()
397 }
398}
399
400impl fmt::Display for ListValue {
401 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
402 let v = self.inner();
403 write!(f, "{v}")
404 }
405}
406
407#[cfg(test)]
408mod tests {
409 use super::*;
410 use crate::{
411 xfs::{self, xfs_struct::XfsMember},
412 Result,
413 };
414
415 #[test]
416 fn test_value_serde() -> Result<()> {
417 let exp_xml = r#"<?xml version="1.0" encoding="UTF-8"?><value/>"#;
418 let exp_val = XfsValue::new();
419
420 assert_eq!(xfs::to_string(&exp_val)?.as_str(), exp_xml);
421 assert_eq!(xfs::from_str::<XfsValue>(exp_xml)?, exp_val);
422
423 let exp_xml = r#"<?xml version="1.0" encoding="UTF-8"?><value><i4>-1</i4></value>"#;
424 let exp_val = XfsValue::new().with_i4(-1);
425
426 assert_eq!(xfs::to_string(&exp_val)?.as_str(), exp_xml);
427
428 Ok(())
429 }
430
431 #[test]
432 fn test_value_list_serde() -> Result<()> {
433 #[derive(Debug, PartialEq, serde::Deserialize, serde::Serialize)]
434 #[serde(rename = "list")]
435 struct List {
436 #[serde(rename = "$value")]
437 value: Vec<Value>,
438 }
439
440 #[derive(Debug, PartialEq, serde::Deserialize, serde::Serialize)]
441 enum Value {
442 #[serde(rename = "value")]
443 Value(XfsValue),
444 }
445
446 let exp_xml = r#"<?xml version="1.0" encoding="UTF-8"?><list><value/></list>"#;
447 let exp_list = List {
448 value: vec![Value::Value(XfsValue::new())],
449 };
450
451 assert_eq!(xfs::to_string(&exp_list)?.as_str(), exp_xml);
452 assert_eq!(xfs::from_str::<List>(exp_xml)?, exp_list);
453
454 Ok(())
455 }
456
457 #[test]
458 fn test_value_struct_serde() -> Result<()> {
459 let exp_xml = r#"<?xml version="1.0" encoding="UTF-8"?><value><struct><member><name>moduleType</name><value><i4>0</i4></value></member></struct></value>"#;
460 let exp_val = ListValue::create(XfsValue::new().with_xfs_struct(XfsStruct::create([
461 XfsMember::create("moduleType", XfsValue::new().with_i4(0)),
462 ])));
463
464 assert_eq!(xfs::from_str::<ListValue>(exp_xml)?, exp_val);
465
466 Ok(())
467 }
468
469 #[test]
470 fn test_array_serde() -> Result<()> {
471 let exp_xml = r#"<?xml version="1.0" encoding="UTF-8"?><array><data><value><struct><member><name>moduleType</name><value><i4>0</i4></value></member></struct></value></data></array>"#;
472 let exp_arr = XfsArray::create([XfsValue::new().with_xfs_struct(XfsStruct::create([
473 XfsMember::create("moduleType", XfsValue::new().with_i4(0)),
474 ]))]);
475
476 assert_eq!(xfs::from_str::<XfsArray>(exp_xml)?, exp_arr);
477 assert_eq!(xfs::to_string(exp_arr)?.as_str(), exp_xml);
478
479 let exp_xml = r#"<?xml version="1.0" encoding="UTF-8"?><value><array><data><value><struct><member><name>moduleType</name><value><i4>0</i4></value></member></struct></value></data></array></value>"#;
480 let exp_val = ListValue::Value(XfsValue::new().with_array(XfsArray::create([
481 XfsValue::new().with_xfs_struct(XfsStruct::create([XfsMember::create(
482 "moduleType",
483 XfsValue::new().with_i4(0),
484 )])),
485 ])));
486
487 assert_eq!(xfs::from_str::<ListValue>(exp_xml)?, exp_val);
488 assert_eq!(xfs::to_string(exp_val)?.as_str(), exp_xml);
489
490 Ok(())
491 }
492
493 #[test]
494 fn test_nested_array_serde() -> Result<()> {
495 let exp_xml = r#"<?xml version="1.0"?><value><array><data><value><struct><member><name>moduleType</name><value><array><data><value><struct><member><name>innerModule</name><value><i4>0</i4></value></member></struct></value></data></array></value></member></struct></value></data></array></value>"#;
496 let exp_val =
497 ListValue::Value(
498 XfsValue::new().with_array(XfsArray::create([XfsValue::new().with_xfs_struct(
499 XfsStruct::create([XfsMember::create(
500 "moduleType",
501 XfsValue::new().with_array(XfsArray::create(
502 [XfsValue::new().with_xfs_struct(XfsStruct::create([
503 XfsMember::create("innerModule", XfsValue::new().with_i4(0)),
504 ]))]
505 .into_iter(),
506 )),
507 )]),
508 )])),
509 );
510
511 assert_eq!(xfs::from_str::<ListValue>(exp_xml)?, exp_val);
512
513 Ok(())
514 }
515
516 #[test]
517 fn test_nested_struct_serde() -> Result<()> {
518 let exp_xml = r#"<?xml version="1.0"?>
519 <value>
520 <struct>
521 <member>
522 <name>outerStruct</name>
523 <value>
524 <array>
525 <data>
526 <value>
527 <struct>
528 <member>
529 <name>innerStruct</name>
530 <value>
531 <array>
532 <data>
533 <value>
534 <i4>0</i4>
535 </value>
536 <value>
537 <i4>1</i4>
538 </value>
539 </data>
540 </array>
541 </value>
542 </member>
543 </struct>
544 </value>
545 </data>
546 </array>
547 </value>
548 </member>
549 </struct>
550 </value>
551 "#;
552
553 xfs::from_str::<ListValue>(exp_xml)?;
554
555 Ok(())
556 }
557}