1use std::borrow::Cow;
2use std::fmt::Display;
3use std::str::FromStr;
4
5use super::{AutosarVersion, CharacterData, CharacterDataSpec, EnumItem};
6
7impl CharacterData {
8 pub(crate) fn check_value(value: &CharacterData, spec: &CharacterDataSpec, file_version: AutosarVersion) -> bool {
9 match spec {
10 CharacterDataSpec::Enum { items } => {
12 if let CharacterData::Enum(enumitem) = &value {
14 if let Some((_, version_mask)) = items.iter().find(|(name, _)| *name == *enumitem) {
16 if *version_mask & (file_version as u32) != 0 {
18 return true;
19 }
20 }
21 }
22 }
23 CharacterDataSpec::Pattern {
24 check_fn, max_length, ..
25 } => {
26 if let CharacterData::String(stringval) = &value
27 && stringval.len() <= max_length.unwrap_or(usize::MAX)
28 && check_fn(stringval.as_bytes())
29 {
30 return true;
31 }
32 }
33 CharacterDataSpec::String { max_length, .. } => {
34 if let CharacterData::String(stringval) = &value
35 && stringval.len() <= max_length.unwrap_or(usize::MAX)
36 {
37 return true;
38 }
39 }
40 CharacterDataSpec::UnsignedInteger => {
41 if let CharacterData::UnsignedInteger(_) = &value {
42 return true;
43 }
44 }
45 CharacterDataSpec::Float => {
46 if let CharacterData::Float(floatval) = &value
47 && !(floatval.is_nan() || floatval.is_infinite())
48 {
49 return true;
50 }
51 }
52 }
53 false
54 }
55
56 pub(crate) fn check_version_compatibility(
57 &self,
58 data_spec: &CharacterDataSpec,
59 target_version: AutosarVersion,
60 ) -> (bool, u32) {
61 if let CharacterDataSpec::Enum { items } = data_spec {
62 if let CharacterData::Enum(attrval) = self {
63 if let Some((_, enumitem_version_mask)) = items.iter().find(|(item, _)| *item == *attrval) {
64 if target_version.compatible(*enumitem_version_mask) {
65 (true, *enumitem_version_mask)
66 } else {
67 (false, *enumitem_version_mask)
68 }
69 } else {
70 (false, 0)
72 }
73 } else {
74 (false, u32::MAX)
76 }
77 } else {
78 (true, u32::MAX)
79 }
80 }
81
82 pub(crate) fn parse(input: &str, character_data_spec: &CharacterDataSpec, version: AutosarVersion) -> Option<Self> {
83 match character_data_spec {
84 CharacterDataSpec::Enum { items } => {
85 if let Ok(enumitem) = EnumItem::from_str(input)
86 && let Some((_, version_mask)) = items.iter().find(|(item, _)| *item == enumitem)
87 && version as u32 & version_mask != 0
88 {
89 return Some(CharacterData::Enum(enumitem));
90 }
91 }
92 CharacterDataSpec::Pattern {
93 check_fn, max_length, ..
94 } => {
95 if input.len() <= max_length.unwrap_or(usize::MAX) && check_fn(input.as_bytes()) {
96 return Some(CharacterData::String(input.to_owned()));
97 }
98 }
99 CharacterDataSpec::String { max_length, .. } => {
100 if input.len() <= max_length.unwrap_or(usize::MAX) {
101 return Some(CharacterData::String(input.to_owned()));
102 }
103 }
104 CharacterDataSpec::UnsignedInteger => {
105 if let Ok(value) = input.parse() {
106 return Some(CharacterData::UnsignedInteger(value));
107 }
108 }
109 CharacterDataSpec::Float => {
110 if let Ok(value) = input.parse::<f64>()
111 && !(value.is_infinite() || value.is_nan())
112 {
113 return Some(CharacterData::Float(value));
114 }
115 }
116 }
117 None
118 }
119
120 pub(crate) fn serialize_internal(&self, outstring: &mut String) {
121 match self {
122 CharacterData::Enum(enumval) => outstring.push_str(enumval.to_str()),
123 CharacterData::String(strval) => outstring.push_str(&escape_text(strval)),
124 CharacterData::UnsignedInteger(intval) => outstring.push_str(&intval.to_string()),
125 CharacterData::Float(floatval) => outstring.push_str(&floatval.to_string()),
126 }
127 }
128
129 #[must_use]
133 pub fn enum_value(&self) -> Option<EnumItem> {
134 if let CharacterData::Enum(item) = self {
135 Some(*item)
136 } else {
137 None
138 }
139 }
140
141 #[must_use]
145 pub fn string_value(&self) -> Option<String> {
146 if let CharacterData::String(value) = self {
147 Some(value.to_owned())
148 } else {
149 None
150 }
151 }
152
153 #[must_use]
157 pub fn unsigned_integer_value(&self) -> Option<u64> {
158 if let CharacterData::UnsignedInteger(uintval) = self {
159 Some(*uintval)
160 } else {
161 None
162 }
163 }
164
165 #[must_use]
169 pub fn float_value(&self) -> Option<f64> {
170 if let CharacterData::Float(value) = self {
171 Some(*value)
172 } else {
173 None
174 }
175 }
176
177 #[must_use]
194 pub fn parse_integer<T: num_traits::Num + TryFrom<u64>>(&self) -> Option<T> {
195 if let CharacterData::String(text) = self {
196 if text == "0" {
197 T::try_from(0u64).ok()
199 } else if let Some(hexstr) = text.strip_prefix("0x") {
200 T::from_str_radix(hexstr, 16).ok()
201 } else if let Some(hexstr) = text.strip_prefix("0X") {
202 T::from_str_radix(hexstr, 16).ok()
203 } else if let Some(binstr) = text.strip_prefix("0b") {
204 T::from_str_radix(binstr, 2).ok()
205 } else if let Some(binstr) = text.strip_prefix("0B") {
206 T::from_str_radix(binstr, 2).ok()
207 } else if let Some(octstr) = text.strip_prefix('0') {
208 T::from_str_radix(octstr, 8).ok()
209 } else {
210 T::from_str_radix(text, 10).ok()
211 }
212 } else if let CharacterData::UnsignedInteger(value) = self {
213 T::try_from(*value).ok()
214 } else {
215 None
216 }
217 }
218
219 #[must_use]
241 pub fn parse_float(&self) -> Option<f64> {
242 if let CharacterData::String(text) = self {
243 if text == "0" {
244 Some(0f64)
246 } else if let Some(hexval) = text
247 .strip_prefix("0x")
248 .and_then(|hextxt| u64::from_str_radix(hextxt, 16).ok())
249 {
250 Some(hexval as f64)
251 } else if let Some(hexval) = text
252 .strip_prefix("0X")
253 .and_then(|hextxt| u64::from_str_radix(hextxt, 16).ok())
254 {
255 Some(hexval as f64)
256 } else if let Some(binval) = text
257 .strip_prefix("0b")
258 .and_then(|bintxt| u64::from_str_radix(bintxt, 2).ok())
259 {
260 Some(binval as f64)
261 } else if let Some(binval) = text
262 .strip_prefix("0B")
263 .and_then(|bintxt| u64::from_str_radix(bintxt, 2).ok())
264 {
265 Some(binval as f64)
266 } else if let Some(octval) = text
267 .strip_prefix('0')
268 .and_then(|octtxt| u64::from_str_radix(octtxt, 8).ok())
269 {
270 Some(octval as f64)
271 } else {
272 text.parse().ok()
274 }
275 } else if let CharacterData::Float(value) = self {
276 Some(*value)
277 } else if let CharacterData::UnsignedInteger(value) = self {
278 Some(*value as f64)
279 } else {
280 None
281 }
282 }
283
284 #[must_use]
300 pub fn parse_bool(&self) -> Option<bool> {
301 if let CharacterData::String(text) = self {
302 match text.as_str() {
303 "true" | "1" => Some(true),
304 "false" | "0" => Some(false),
305 _ => None,
306 }
307 } else {
308 None
309 }
310 }
311}
312
313impl From<String> for CharacterData {
314 fn from(value: String) -> Self {
315 Self::String(value)
316 }
317}
318
319impl From<&str> for CharacterData {
320 fn from(value: &str) -> Self {
321 Self::String(value.to_string())
322 }
323}
324
325impl From<EnumItem> for CharacterData {
326 fn from(value: EnumItem) -> Self {
327 Self::Enum(value)
328 }
329}
330
331impl From<u64> for CharacterData {
332 fn from(value: u64) -> Self {
333 Self::UnsignedInteger(value)
334 }
335}
336
337impl From<f64> for CharacterData {
338 fn from(value: f64) -> Self {
339 Self::Float(value)
340 }
341}
342
343impl From<bool> for CharacterData {
344 fn from(value: bool) -> Self {
345 Self::String(value.to_string())
346 }
347}
348
349impl Display for CharacterData {
350 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
351 match self {
352 CharacterData::Enum(enumitem) => f.write_str(enumitem.to_str()),
353 CharacterData::String(stringval) => f.write_str(stringval),
354 CharacterData::UnsignedInteger(uintval) => f.write_str(&uintval.to_string()),
355 CharacterData::Float(f64val) => f.write_str(&f64val.to_string()),
356 }
357 }
358}
359
360impl PartialEq for CharacterData {
362 fn eq(&self, other: &Self) -> bool {
363 self.cmp(other) == std::cmp::Ordering::Equal
364 }
365}
366
367impl Ord for CharacterData {
370 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
371 match (self, other) {
375 (CharacterData::Enum(a), CharacterData::Enum(b)) => a.to_str().cmp(b.to_str()),
376 (CharacterData::String(a), CharacterData::String(b)) => a.cmp(b),
377 (CharacterData::UnsignedInteger(a), CharacterData::UnsignedInteger(b)) => a.cmp(b),
378 (CharacterData::Float(a), CharacterData::Float(b)) => a.total_cmp(b),
379 (CharacterData::Enum(_), _) => std::cmp::Ordering::Less,
380 (CharacterData::String(_), CharacterData::Enum(_)) => std::cmp::Ordering::Greater,
381 (CharacterData::String(_), _) => std::cmp::Ordering::Less,
382 (CharacterData::UnsignedInteger(_), CharacterData::Enum(_)) => std::cmp::Ordering::Greater,
383 (CharacterData::UnsignedInteger(_), CharacterData::String(_)) => std::cmp::Ordering::Greater,
384 (CharacterData::UnsignedInteger(_), _) => std::cmp::Ordering::Less,
385 (CharacterData::Float(_), _) => std::cmp::Ordering::Greater,
386 }
387 }
388}
389
390impl PartialOrd for CharacterData {
391 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
392 Some(self.cmp(other))
393 }
394}
395
396impl Eq for CharacterData {}
397
398fn escape_text<'a>(input: &'a str) -> Cow<'a, str> {
399 if input.contains(['&', '>', '<', '\'', '"']) {
400 let mut escaped = String::with_capacity(input.len() + 6);
401
402 for c in input.chars() {
403 match c {
404 '<' => escaped.push_str("<"),
405 '>' => escaped.push_str(">"),
406 '&' => escaped.push_str("&"),
407 '"' => escaped.push_str("""),
408 '\'' => escaped.push_str("'"),
409 other => escaped.push(other),
410 }
411 }
412
413 Cow::Owned(escaped)
414 } else {
415 Cow::Borrowed(input)
416 }
417}
418
419#[cfg(test)]
420mod test {
421 use super::*;
422
423 fn dummy_validate(s: &[u8]) -> bool {
424 s.len() == 1 && (s[0] == b'0' || s[0] == b'1')
425 }
426
427 #[test]
428 fn check_value() {
429 let spec_enum = CharacterDataSpec::Enum {
430 items: &[(EnumItem::default, 0x3ffff), (EnumItem::preserve, 0x0ffff)],
431 };
432 let data = CharacterData::Enum(EnumItem::default);
433 assert!(CharacterData::check_value(
434 &data,
435 &spec_enum,
436 AutosarVersion::Autosar_00050
437 ));
438 let data = CharacterData::Enum(EnumItem::preserve);
439 assert!(!CharacterData::check_value(
440 &data,
441 &spec_enum,
442 AutosarVersion::Autosar_00050
443 ));
444 let data = CharacterData::Enum(EnumItem::Abstract);
445 assert!(!CharacterData::check_value(
446 &data,
447 &spec_enum,
448 AutosarVersion::Autosar_00050
449 ));
450 let data = CharacterData::Float(1.23);
451 assert!(!CharacterData::check_value(
452 &data,
453 &spec_enum,
454 AutosarVersion::Autosar_00050
455 ));
456
457 let spec_double = CharacterDataSpec::Float;
458 let data = CharacterData::Float(1.23);
459 assert!(CharacterData::check_value(
460 &data,
461 &spec_double,
462 AutosarVersion::Autosar_00050
463 ));
464 let data = CharacterData::String("1.23".to_string());
465 assert!(!CharacterData::check_value(
466 &data,
467 &spec_double,
468 AutosarVersion::Autosar_00050
469 ));
470
471 let spec_uint = CharacterDataSpec::UnsignedInteger;
472 let data = CharacterData::UnsignedInteger(123);
473 assert!(CharacterData::check_value(
474 &data,
475 &spec_uint,
476 AutosarVersion::Autosar_00050
477 ));
478 let data = CharacterData::String("123".to_string());
479 assert!(!CharacterData::check_value(
480 &data,
481 &spec_uint,
482 AutosarVersion::Autosar_00050
483 ));
484
485 let spec_string = CharacterDataSpec::String {
486 preserve_whitespace: false,
487 max_length: Some(10),
488 };
489 let data = CharacterData::String("123".to_string());
490 assert!(CharacterData::check_value(
491 &data,
492 &spec_string,
493 AutosarVersion::Autosar_00050
494 ));
495 let data = CharacterData::String("12345678901".to_string());
496 assert!(!CharacterData::check_value(
497 &data,
498 &spec_string,
499 AutosarVersion::Autosar_00050
500 ));
501 let data = CharacterData::UnsignedInteger(1);
502 assert!(!CharacterData::check_value(
503 &data,
504 &spec_string,
505 AutosarVersion::Autosar_00050
506 ));
507
508 let spec_pattern = CharacterDataSpec::Pattern {
509 check_fn: dummy_validate,
510 regex: r"0|1",
511 max_length: Some(1),
512 };
513 let data = CharacterData::String("0".to_string());
514 assert!(CharacterData::check_value(
515 &data,
516 &spec_pattern,
517 AutosarVersion::Autosar_00050
518 ));
519 let data = CharacterData::String("2".to_string());
520 assert!(!CharacterData::check_value(
521 &data,
522 &spec_pattern,
523 AutosarVersion::Autosar_00050
524 ));
525 }
526
527 #[test]
528 fn check_version_compatibility() {
529 let spec_enum = CharacterDataSpec::Enum {
530 items: &[(EnumItem::default, 0x0001), (EnumItem::preserve, 0x0002)],
531 };
532 let data = CharacterData::Enum(EnumItem::default);
533 let (result, _) = data.check_version_compatibility(&spec_enum, AutosarVersion::Autosar_4_0_1);
534 assert!(result);
535 let (result, _) = data.check_version_compatibility(&spec_enum, AutosarVersion::Autosar_00050);
536 assert!(!result);
537 let data = CharacterData::Enum(EnumItem::Abstract);
538 let (result, _) = data.check_version_compatibility(&spec_enum, AutosarVersion::Autosar_00050);
539 assert!(!result);
540 let data = CharacterData::UnsignedInteger(0);
541 let (result, _) = data.check_version_compatibility(&spec_enum, AutosarVersion::Autosar_00050);
542 assert!(!result);
543 }
544
545 #[test]
546 fn parse() {
547 let spec_enum = CharacterDataSpec::Enum {
548 items: &[(EnumItem::default, 0x3ffff), (EnumItem::preserve, 0x0ffff)],
549 };
550 let data = CharacterData::parse("default", &spec_enum, AutosarVersion::Autosar_00050).unwrap();
551 assert_eq!(data.enum_value().unwrap(), EnumItem::default);
552 let data = CharacterData::parse("preserve", &spec_enum, AutosarVersion::Autosar_00050);
553 assert!(data.is_none());
554 let data = CharacterData::parse("ABSTRACT", &spec_enum, AutosarVersion::Autosar_00050);
555 assert!(data.is_none());
556 let data = CharacterData::parse("", &spec_enum, AutosarVersion::Autosar_00050);
557 assert!(data.is_none());
558
559 let spec_double = CharacterDataSpec::Float;
560 let data = CharacterData::parse("2.0", &spec_double, AutosarVersion::Autosar_00050).unwrap();
561 assert_eq!(data.float_value().unwrap(), 2.0);
562 let data = CharacterData::parse("text", &spec_double, AutosarVersion::Autosar_00050);
563 assert!(data.is_none());
564
565 let spec_uint = CharacterDataSpec::UnsignedInteger;
566 let data = CharacterData::parse("2", &spec_uint, AutosarVersion::Autosar_00050).unwrap();
567 assert_eq!(data.unsigned_integer_value().unwrap(), 2);
568 let data = CharacterData::parse("text", &spec_uint, AutosarVersion::Autosar_00050);
569 assert!(data.is_none());
570
571 let spec_string = CharacterDataSpec::String {
572 preserve_whitespace: false,
573 max_length: Some(10),
574 };
575 let data = CharacterData::parse("text", &spec_string, AutosarVersion::Autosar_00050).unwrap();
576 assert_eq!(data.string_value().unwrap(), "text");
577 let data = CharacterData::parse("text text text", &spec_string, AutosarVersion::Autosar_00050);
578 assert!(data.is_none());
579
580 let spec_pattern = CharacterDataSpec::Pattern {
581 check_fn: dummy_validate,
582 regex: r"0|1",
583 max_length: Some(1),
584 };
585 let data = CharacterData::parse("0", &spec_pattern, AutosarVersion::Autosar_00050).unwrap();
586 assert_eq!(data.string_value().unwrap(), "0");
587 let data = CharacterData::parse("2", &spec_pattern, AutosarVersion::Autosar_00050);
588 assert!(data.is_none());
589 }
590
591 #[test]
592 fn serialize() {
593 let mut out = "".to_string();
594 let data = CharacterData::Enum(EnumItem::Abstract);
595 data.serialize_internal(&mut out);
596 assert_eq!(out, "ABSTRACT");
597 assert_eq!(format!("{data}"), "ABSTRACT");
598
599 let mut out = "".to_string();
600 let data = CharacterData::Float(1.23);
601 data.serialize_internal(&mut out);
602 assert_eq!(out, "1.23");
603 assert_eq!(format!("{data}"), "1.23");
604
605 let mut out = "".to_string();
606 let data = CharacterData::UnsignedInteger(0);
607 data.serialize_internal(&mut out);
608 assert_eq!(out, "0");
609 assert_eq!(format!("{data}"), "0");
610
611 let mut out = "".to_string();
612 let data = CharacterData::String("text".to_string());
613 data.serialize_internal(&mut out);
614 assert_eq!(out, "text");
615 assert_eq!(format!("{data}"), "text");
616
617 let mut out = "".to_string();
618 let data = CharacterData::String("special chars: <, >, &, \', \"".to_string());
619 data.serialize_internal(&mut out);
620 assert_eq!(out, "special chars: <, >, &, ', "");
621 assert_eq!(format!("{data}"), "special chars: <, >, &, \', \"");
622 }
623
624 #[test]
625 fn get_value() {
626 assert!(CharacterData::Enum(EnumItem::Abstract).enum_value().is_some());
627 assert!(CharacterData::Enum(EnumItem::Abstract).string_value().is_none());
628
629 assert!(CharacterData::Float(1.23).float_value().is_some());
630 assert!(CharacterData::Float(1.23).unsigned_integer_value().is_none());
631
632 assert!(CharacterData::String("x".to_string()).string_value().is_some());
633 assert!(CharacterData::String("x".to_string()).float_value().is_none());
634
635 assert!(CharacterData::UnsignedInteger(1).unsigned_integer_value().is_some());
636 assert!(CharacterData::UnsignedInteger(1).enum_value().is_none());
637 }
638
639 #[test]
640 fn parse_integer() {
641 let data = CharacterData::String("text".to_string());
642 let result = data.parse_integer::<u32>();
643 assert!(result.is_none());
644
645 let data = CharacterData::String("0x123412341234".to_string());
646 let result = data.parse_integer::<u32>();
647 assert!(result.is_none());
648
649 let data = CharacterData::String("0x1234".to_string());
650 let result = data.parse_integer::<u32>().unwrap();
651 assert_eq!(result, 0x1234);
652
653 let data = CharacterData::String("0X123456".to_string());
654 let result = data.parse_integer::<u32>().unwrap();
655 assert_eq!(result, 0x123456);
656
657 let data = CharacterData::String("0b1010".to_string());
658 let result = data.parse_integer::<u32>().unwrap();
659 assert_eq!(result, 10);
660
661 let data = CharacterData::String("0B101010".to_string());
662 let result = data.parse_integer::<u32>().unwrap();
663 assert_eq!(result, 42);
664
665 let data = CharacterData::String("0733".to_string());
666 let result = data.parse_integer::<u32>().unwrap();
667 assert_eq!(result, 475);
668
669 let data = CharacterData::String("0".to_string());
670 let result = data.parse_integer::<u32>().unwrap();
671 assert_eq!(result, 0);
672
673 let data = CharacterData::String("-55".to_string());
674 let result = data.parse_integer::<i32>().unwrap();
675 assert_eq!(result, -55);
676
677 let data = CharacterData::UnsignedInteger(0);
678 let result = data.parse_integer::<u32>().unwrap();
679 assert_eq!(result, 0);
680
681 let data = CharacterData::Float(0.0);
682 let result = data.parse_integer::<u32>();
683 assert!(result.is_none());
684 }
685
686 #[test]
687 fn parse_float() {
688 let data = CharacterData::String("text".to_string());
690 let result = data.parse_float();
691 assert!(result.is_none());
692
693 let data = CharacterData::String("0".to_string());
695 let result = data.parse_float().unwrap();
696 assert_eq!(result, 0.0);
697
698 let data = CharacterData::String("0xFFFFFFFFF".to_string());
700 let result = data.parse_float().unwrap();
701 assert_eq!(result, 68719476735.0);
702
703 let data = CharacterData::String("0x1.234".to_string());
705 let result = data.parse_float();
706 assert!(result.is_none());
707
708 let data = CharacterData::String("0.0001".to_string());
710 let result = data.parse_float().unwrap();
711 assert_eq!(result, 0.0001);
712
713 let data = CharacterData::String("1.234e5".to_string());
715 let result = data.parse_float().unwrap();
716 assert_eq!(result, 1.234e5);
717
718 let data = CharacterData::String("00.12".to_string());
720 let result = data.parse_float().unwrap();
721 assert_eq!(result, 0.12);
722
723 let data = CharacterData::String("NaN".to_string());
725 let result = data.parse_float().unwrap();
726 assert!(result.is_nan());
727
728 let data = CharacterData::String("INF".to_string());
730 let result = data.parse_float().unwrap();
731 assert!(result.is_infinite());
732
733 let data = CharacterData::String("0x1234".to_string());
735 let result = data.parse_float().unwrap();
736 assert_eq!(result, 4660.0);
737
738 let data = CharacterData::String("0X1234".to_string());
740 let result = data.parse_float().unwrap();
741 assert_eq!(result, 4660.0);
742
743 let data = CharacterData::String("0b1101".to_string());
745 let result = data.parse_float().unwrap();
746 assert_eq!(result, 13.0);
747
748 let data = CharacterData::String("0B1101".to_string());
750 let result = data.parse_float().unwrap();
751 assert_eq!(result, 13.0);
752
753 let data = CharacterData::String("0777".to_string());
755 let result = data.parse_float().unwrap();
756 assert_eq!(result, 511.0);
757
758 let data = CharacterData::UnsignedInteger(0);
760 let result = data.parse_float().unwrap();
761 assert_eq!(result, 0.0);
762
763 let data = CharacterData::Float(5.0);
765 let result = data.parse_float().unwrap();
766 assert_eq!(result, 5.0);
767
768 let data = CharacterData::Enum(EnumItem::Abstract);
770 let result = data.parse_float();
771 assert!(result.is_none());
772 }
773
774 #[test]
775 fn parse_bool() {
776 let data = CharacterData::String("true".to_string());
777 let result = data.parse_bool().unwrap();
778 assert!(result);
779
780 let data = CharacterData::String("1".to_string());
781 let result = data.parse_bool().unwrap();
782 assert!(result);
783
784 let data = CharacterData::String("false".to_string());
785 let result = data.parse_bool().unwrap();
786 assert!(!result);
787
788 let data = CharacterData::String("0".to_string());
789 let result = data.parse_bool().unwrap();
790 assert!(!result);
791
792 let data = CharacterData::String("text".to_string());
793 let result = data.parse_bool();
794 assert!(result.is_none());
795
796 let data = CharacterData::UnsignedInteger(0);
797 let result = data.parse_bool();
798 assert!(result.is_none());
799 }
800
801 #[test]
802 fn ordering() {
803 let enum1 = CharacterData::Enum(EnumItem::Abstract);
804 let enum2 = CharacterData::Enum(EnumItem::default);
805 assert!(enum1 < enum2);
806
807 let string1 = CharacterData::String("abcdef".to_string());
808 let string2 = CharacterData::String("text".to_string());
809 assert!(string1 < string2);
810
811 let integer1 = CharacterData::UnsignedInteger(123);
812 let integer2 = CharacterData::UnsignedInteger(456);
813 assert!(integer1 < integer2);
814
815 let float1 = CharacterData::Float(1.23);
816 let float2 = CharacterData::Float(4.56);
817 assert!(float1 < float2);
818
819 assert!(enum1 < string1);
821 assert!(enum1 < integer1);
822 assert!(enum1 < float1);
823 assert!(string1 > enum1);
824 assert!(string1 < integer1);
825 assert!(string1 < float1);
826 assert!(integer1 > enum1);
827 assert!(integer1 > string1);
828 assert!(integer1 < float1);
829 assert!(float1 > enum1);
830 assert!(float1 > string1);
831 assert!(float1 > integer1);
832
833 assert!(enum1.partial_cmp(&enum2).unwrap() == std::cmp::Ordering::Less);
835 }
836
837 #[test]
838 fn cdata_conversion() {
839 let cdata: CharacterData = 0.into();
840 assert_eq!(cdata, CharacterData::UnsignedInteger(0));
841
842 let cdata: CharacterData = (1.0).into();
843 assert_eq!(cdata, CharacterData::Float(1.0));
844
845 let cdata: CharacterData = "text".into();
846 assert_eq!(cdata, CharacterData::String("text".to_string()));
847
848 let cdata: CharacterData = String::from("text").into();
849 assert_eq!(cdata, CharacterData::String("text".to_string()));
850
851 let cdata: CharacterData = EnumItem::Abstract.into();
852 assert_eq!(cdata, CharacterData::Enum(EnumItem::Abstract));
853
854 let cdata: CharacterData = true.into();
855 assert_eq!(cdata, CharacterData::String("true".to_string()));
856 }
857}