1use alloc::boxed::Box;
28use alloc::string::String;
29use alloc::vec::Vec;
30
31use crate::value::{Value, ValueType};
32
33#[derive(Debug, Clone, PartialEq, Eq)]
35pub struct ParseError {
36 pub message: String,
37 pub position: usize,
38}
39
40impl core::fmt::Display for ParseError {
41 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
42 write!(f, "parse error at {}: {}", self.position, self.message)
43 }
44}
45
46struct Parser<'a> {
48 input: &'a str,
49 pos: usize,
50}
51
52impl<'a> Parser<'a> {
53 fn new(input: &'a str) -> Self {
54 Self { input, pos: 0 }
55 }
56
57 fn remaining(&self) -> &'a str {
58 &self.input[self.pos..]
59 }
60
61 fn is_eof(&self) -> bool {
62 self.pos >= self.input.len()
63 }
64
65 fn peek(&self) -> Option<char> {
66 self.remaining().chars().next()
67 }
68
69 fn advance(&mut self, n: usize) {
70 self.pos += n;
71 }
72
73 fn skip_whitespace(&mut self) {
74 while let Some(c) = self.peek() {
75 if c.is_ascii_whitespace() {
76 self.advance(c.len_utf8());
77 } else {
78 break;
79 }
80 }
81 }
82
83 fn expect_char(&mut self, expected: char) -> Result<(), ParseError> {
84 match self.peek() {
85 Some(c) if c == expected => {
86 self.advance(c.len_utf8());
87 Ok(())
88 }
89 Some(c) => Err(self.error(alloc::format!("expected '{}', got '{}'", expected, c))),
90 None => Err(self.error(alloc::format!("expected '{}', got EOF", expected))),
91 }
92 }
93
94 fn starts_with(&self, s: &str) -> bool {
95 self.remaining().starts_with(s)
96 }
97
98 fn error(&self, message: String) -> ParseError {
99 ParseError {
100 message,
101 position: self.pos,
102 }
103 }
104
105 fn parse_value(&mut self) -> Result<Value, ParseError> {
107 self.skip_whitespace();
108
109 if self.is_eof() {
110 return Err(self.error(String::from("unexpected EOF")));
111 }
112
113 match self.peek().unwrap() {
114 '"' => self.parse_string(),
115 '\'' => self.parse_char(),
116 '(' => self.parse_tuple(),
117 '[' => self.parse_list(),
118 '{' => self.parse_record_body(String::new()),
119 c if c == '-' || c.is_ascii_digit() => self.parse_number(),
120 _ => self.parse_keyword_or_named(),
121 }
122 }
123
124 fn parse_string(&mut self) -> Result<Value, ParseError> {
125 self.expect_char('"')?;
126 let mut s = String::new();
127 loop {
128 match self.peek() {
129 None => return Err(self.error(String::from("unterminated string"))),
130 Some('"') => {
131 self.advance(1);
132 return Ok(Value::String(s));
133 }
134 Some('\\') => {
135 self.advance(1);
136 match self.peek() {
137 Some('n') => {
138 self.advance(1);
139 s.push('\n');
140 }
141 Some('r') => {
142 self.advance(1);
143 s.push('\r');
144 }
145 Some('t') => {
146 self.advance(1);
147 s.push('\t');
148 }
149 Some('\\') => {
150 self.advance(1);
151 s.push('\\');
152 }
153 Some('"') => {
154 self.advance(1);
155 s.push('"');
156 }
157 Some(c) => {
158 return Err(self.error(alloc::format!("unknown escape '\\{}'", c)))
159 }
160 None => return Err(self.error(String::from("unterminated escape"))),
161 }
162 }
163 Some(c) => {
164 self.advance(c.len_utf8());
165 s.push(c);
166 }
167 }
168 }
169 }
170
171 fn parse_char(&mut self) -> Result<Value, ParseError> {
172 self.expect_char('\'')?;
173 let c = match self.peek() {
174 None => return Err(self.error(String::from("unterminated char"))),
175 Some('\\') => {
176 self.advance(1);
177 match self.peek() {
178 Some('n') => {
179 self.advance(1);
180 '\n'
181 }
182 Some('r') => {
183 self.advance(1);
184 '\r'
185 }
186 Some('t') => {
187 self.advance(1);
188 '\t'
189 }
190 Some('\\') => {
191 self.advance(1);
192 '\\'
193 }
194 Some('\'') => {
195 self.advance(1);
196 '\''
197 }
198 Some(c) => {
199 return Err(self.error(alloc::format!("unknown char escape '\\{}'", c)))
200 }
201 None => return Err(self.error(String::from("unterminated char escape"))),
202 }
203 }
204 Some(c) => {
205 self.advance(c.len_utf8());
206 c
207 }
208 };
209 self.expect_char('\'')?;
210 Ok(Value::Char(c))
211 }
212
213 fn parse_number(&mut self) -> Result<Value, ParseError> {
214 let start = self.pos;
215 if self.peek() == Some('-') {
217 self.advance(1);
218 }
219 while let Some(c) = self.peek() {
221 if c.is_ascii_digit() {
222 self.advance(1);
223 } else {
224 break;
225 }
226 }
227 let has_dot = if self.peek() == Some('.') {
229 self.advance(1);
230 while let Some(c) = self.peek() {
231 if c.is_ascii_digit() {
232 self.advance(1);
233 } else {
234 break;
235 }
236 }
237 true
238 } else {
239 false
240 };
241
242 let num_str = &self.input[start..self.pos];
243
244 let remaining = self.remaining();
246 let suffixes: &[(&str, u8)] = &[
247 ("u8", 1),
248 ("u16", 2),
249 ("u32", 3),
250 ("u64", 4),
251 ("s8", 5),
252 ("s16", 6),
253 ("s32", 7),
254 ("s64", 8),
255 ("f32", 9),
256 ("f64", 10),
257 ];
258
259 for &(suffix, id) in suffixes {
260 if remaining.starts_with(suffix) {
261 let after = remaining
263 .get(suffix.len()..suffix.len() + 1)
264 .and_then(|s| s.chars().next());
265 if after.is_none_or(|c| !c.is_ascii_alphanumeric()) {
266 self.advance(suffix.len());
267 return self.make_number(num_str, id, has_dot);
268 }
269 }
270 }
271
272 Err(self.error(alloc::format!(
273 "number '{}' missing type suffix (e.g. u32, s64, f32)",
274 num_str
275 )))
276 }
277
278 fn make_number(
279 &self,
280 num_str: &str,
281 suffix_id: u8,
282 _has_dot: bool,
283 ) -> Result<Value, ParseError> {
284 let pos = self.pos;
285 let err = |msg: String| ParseError {
286 message: msg,
287 position: pos,
288 };
289
290 match suffix_id {
291 1 => {
292 let v: u8 = num_str.parse().map_err(|e| err(alloc::format!("{}", e)))?;
294 Ok(Value::U8(v))
295 }
296 2 => {
297 let v: u16 = num_str.parse().map_err(|e| err(alloc::format!("{}", e)))?;
299 Ok(Value::U16(v))
300 }
301 3 => {
302 let v: u32 = num_str.parse().map_err(|e| err(alloc::format!("{}", e)))?;
304 Ok(Value::U32(v))
305 }
306 4 => {
307 let v: u64 = num_str.parse().map_err(|e| err(alloc::format!("{}", e)))?;
309 Ok(Value::U64(v))
310 }
311 5 => {
312 let v: i8 = num_str.parse().map_err(|e| err(alloc::format!("{}", e)))?;
314 Ok(Value::S8(v))
315 }
316 6 => {
317 let v: i16 = num_str.parse().map_err(|e| err(alloc::format!("{}", e)))?;
319 Ok(Value::S16(v))
320 }
321 7 => {
322 let v: i32 = num_str.parse().map_err(|e| err(alloc::format!("{}", e)))?;
324 Ok(Value::S32(v))
325 }
326 8 => {
327 let v: i64 = num_str.parse().map_err(|e| err(alloc::format!("{}", e)))?;
329 Ok(Value::S64(v))
330 }
331 9 => {
332 let v: f32 = num_str.parse().map_err(|e| err(alloc::format!("{}", e)))?;
334 Ok(Value::F32(v))
335 }
336 10 => {
337 let v: f64 = num_str.parse().map_err(|e| err(alloc::format!("{}", e)))?;
339 Ok(Value::F64(v))
340 }
341 _ => Err(err(String::from("invalid suffix id"))),
342 }
343 }
344
345 fn parse_tuple(&mut self) -> Result<Value, ParseError> {
346 self.expect_char('(')?;
347 self.skip_whitespace();
348 if self.peek() == Some(')') {
349 self.advance(1);
350 return Ok(Value::Tuple(Vec::new()));
351 }
352 let items = self.parse_comma_list(')')?;
353 Ok(Value::Tuple(items))
354 }
355
356 fn parse_list(&mut self) -> Result<Value, ParseError> {
357 self.expect_char('[')?;
358 self.skip_whitespace();
359 if self.peek() == Some(']') {
360 self.advance(1);
361 self.skip_whitespace();
363 let elem_type = if self.peek() == Some('<') {
364 self.advance(1);
365 let t = self.parse_value_type()?;
366 self.expect_char('>')?;
367 t
368 } else {
369 return Err(self.error(String::from(
370 "empty list requires type annotation: []<TYPE>",
371 )));
372 };
373 return Ok(Value::List {
374 elem_type,
375 items: Vec::new(),
376 });
377 }
378 let items = self.parse_comma_list(']')?;
379 let elem_type = items
380 .first()
381 .map(|v| v.infer_type())
382 .unwrap_or(ValueType::S32);
383 Ok(Value::List { elem_type, items })
384 }
385
386 fn parse_value_type(&mut self) -> Result<ValueType, ParseError> {
389 self.skip_whitespace();
390 let primitives: &[(&str, ValueType)] = &[
392 ("bool", ValueType::Bool),
393 ("u8", ValueType::U8),
394 ("u16", ValueType::U16),
395 ("u32", ValueType::U32),
396 ("u64", ValueType::U64),
397 ("s8", ValueType::S8),
398 ("s16", ValueType::S16),
399 ("s32", ValueType::S32),
400 ("s64", ValueType::S64),
401 ("f32", ValueType::F32),
402 ("f64", ValueType::F64),
403 ("char", ValueType::Char),
404 ("string", ValueType::String),
405 ("flags", ValueType::Flags),
406 ];
407 for (name, ty) in primitives {
408 if self.starts_with(name)
409 && !self.is_ident_continue_at(name.len())
410 && self
411 .remaining()
412 .get(name.len()..name.len() + 1)
413 .is_none_or(|s| s != "<")
414 {
415 self.advance(name.len());
416 return Ok(ty.clone());
417 }
418 }
419 if self.starts_with("list<") {
420 self.advance(5);
421 let inner = self.parse_value_type()?;
422 self.skip_whitespace();
423 self.expect_char('>')?;
424 return Ok(ValueType::List(Box::new(inner)));
425 }
426 if self.starts_with("option<") {
427 self.advance(7);
428 let inner = self.parse_value_type()?;
429 self.skip_whitespace();
430 self.expect_char('>')?;
431 return Ok(ValueType::Option(Box::new(inner)));
432 }
433 if self.starts_with("result<") {
434 self.advance(7);
435 let ok = self.parse_value_type()?;
436 self.skip_whitespace();
437 self.expect_char(',')?;
438 self.skip_whitespace();
439 let err = self.parse_value_type()?;
440 self.skip_whitespace();
441 self.expect_char('>')?;
442 return Ok(ValueType::Result {
443 ok: Box::new(ok),
444 err: Box::new(err),
445 });
446 }
447 if self.starts_with("tuple<") {
448 self.advance(6);
449 self.skip_whitespace();
450 if self.peek() == Some('>') {
452 self.advance(1);
453 return Ok(ValueType::Tuple(Vec::new()));
454 }
455 let mut types = Vec::new();
456 loop {
457 self.skip_whitespace();
458 types.push(self.parse_value_type()?);
459 self.skip_whitespace();
460 match self.peek() {
461 Some(',') => {
462 self.advance(1);
463 }
464 Some('>') => {
465 self.advance(1);
466 return Ok(ValueType::Tuple(types));
467 }
468 Some(c) => {
469 return Err(self.error(alloc::format!("expected ',' or '>', got '{}'", c)))
470 }
471 None => return Err(self.error(String::from("expected '>', got EOF"))),
472 }
473 }
474 }
475 let name = self.parse_ident()?;
479 Ok(ValueType::Record(name))
480 }
481
482 fn parse_comma_list(&mut self, end_char: char) -> Result<Vec<Value>, ParseError> {
484 let mut items = Vec::new();
485 loop {
486 self.skip_whitespace();
487 if self.peek() == Some(end_char) {
488 self.advance(1);
489 return Ok(items);
490 }
491 items.push(self.parse_value()?);
492 self.skip_whitespace();
493 match self.peek() {
494 Some(',') => {
495 self.advance(1);
496 }
497 Some(c) if c == end_char => {}
498 Some(c) => {
499 return Err(self.error(alloc::format!(
500 "expected ',' or '{}', got '{}'",
501 end_char,
502 c
503 )))
504 }
505 None => return Err(self.error(alloc::format!("expected '{}', got EOF", end_char))),
506 }
507 }
508 }
509
510 fn parse_keyword_or_named(&mut self) -> Result<Value, ParseError> {
512 if self.starts_with("true") && !self.is_ident_continue_at(4) {
514 self.advance(4);
515 return Ok(Value::Bool(true));
516 }
517 if self.starts_with("false") && !self.is_ident_continue_at(5) {
518 self.advance(5);
519 return Ok(Value::Bool(false));
520 }
521 if self.starts_with("none<") {
522 self.advance(5);
523 let inner_type = self.parse_value_type()?;
524 self.skip_whitespace();
525 self.expect_char('>')?;
526 return Ok(Value::Option {
527 inner_type,
528 value: None,
529 });
530 }
531 if self.starts_with("some<") {
532 self.advance(5);
533 let inner_type = self.parse_value_type()?;
534 self.skip_whitespace();
535 self.expect_char('>')?;
536 self.expect_char('(')?;
537 let inner = self.parse_value()?;
538 self.skip_whitespace();
539 self.expect_char(')')?;
540 return Ok(Value::Option {
541 inner_type,
542 value: Some(Box::new(inner)),
543 });
544 }
545 if self.starts_with("ok<") {
546 self.advance(3);
547 let ok_type = self.parse_value_type()?;
548 self.skip_whitespace();
549 self.expect_char(',')?;
550 self.skip_whitespace();
551 let err_type = self.parse_value_type()?;
552 self.skip_whitespace();
553 self.expect_char('>')?;
554 self.expect_char('(')?;
555 let inner = self.parse_value()?;
556 self.skip_whitespace();
557 self.expect_char(')')?;
558 return Ok(Value::Result {
559 ok_type,
560 err_type,
561 value: Ok(Box::new(inner)),
562 });
563 }
564 if self.starts_with("err<") {
565 self.advance(4);
566 let ok_type = self.parse_value_type()?;
567 self.skip_whitespace();
568 self.expect_char(',')?;
569 self.skip_whitespace();
570 let err_type = self.parse_value_type()?;
571 self.skip_whitespace();
572 self.expect_char('>')?;
573 self.expect_char('(')?;
574 let inner = self.parse_value()?;
575 self.skip_whitespace();
576 self.expect_char(')')?;
577 return Ok(Value::Result {
578 ok_type,
579 err_type,
580 value: Err(Box::new(inner)),
581 });
582 }
583 if self.starts_with("flags(0x") {
584 self.advance(8);
585 let start = self.pos;
586 while let Some(c) = self.peek() {
587 if c.is_ascii_hexdigit() {
588 self.advance(1);
589 } else {
590 break;
591 }
592 }
593 let hex_str = &self.input[start..self.pos];
594 let v = u64::from_str_radix(hex_str, 16)
595 .map_err(|e| self.error(alloc::format!("invalid flags hex: {}", e)))?;
596 self.expect_char(')')?;
597 return Ok(Value::Flags(v));
598 }
599
600 if self.starts_with("::") {
603 self.advance(2);
604 let case_name = self.parse_ident()?;
605 let payload = self.parse_optional_payload()?;
606 return Ok(Value::Variant {
607 type_name: String::new(),
608 case_name,
609 tag: 0,
610 payload,
611 });
612 }
613
614 let ident = self.parse_ident()?;
615 self.skip_whitespace();
616
617 match self.peek() {
618 Some('{') => self.parse_record_body(ident),
619 Some(':') if self.starts_with("::") => {
620 self.advance(2);
621 let case_name = self.parse_ident()?;
622 let payload = self.parse_optional_payload()?;
623 Ok(Value::Variant {
624 type_name: ident,
625 case_name,
626 tag: 0,
627 payload,
628 })
629 }
630 _ => Err(self.error(alloc::format!(
631 "unexpected identifier '{}' (expected {{ or ::)",
632 ident
633 ))),
634 }
635 }
636
637 fn parse_record_body(&mut self, type_name: String) -> Result<Value, ParseError> {
638 self.expect_char('{')?;
639 self.skip_whitespace();
640 if self.peek() == Some('}') {
641 self.advance(1);
642 return Ok(Value::Record {
643 type_name,
644 fields: Vec::new(),
645 });
646 }
647 let mut fields = Vec::new();
648 loop {
649 self.skip_whitespace();
650 if self.peek() == Some('}') {
651 self.advance(1);
652 return Ok(Value::Record { type_name, fields });
653 }
654 let name = self.parse_ident()?;
655 self.skip_whitespace();
656 self.expect_char(':')?;
657 self.skip_whitespace();
658 let value = self.parse_value()?;
659 fields.push((name, value));
660 self.skip_whitespace();
661 match self.peek() {
662 Some(',') => {
663 self.advance(1);
664 }
665 Some('}') => {}
666 Some(c) => {
667 return Err(self.error(alloc::format!("expected ',' or '}}', got '{}'", c)))
668 }
669 None => return Err(self.error(String::from("expected '}', got EOF"))),
670 }
671 }
672 }
673
674 fn parse_optional_payload(&mut self) -> Result<Vec<Value>, ParseError> {
675 self.skip_whitespace();
676 if self.peek() == Some('(') {
677 self.advance(1);
678 self.skip_whitespace();
679 if self.peek() == Some(')') {
680 self.advance(1);
681 return Ok(Vec::new());
682 }
683 let items = self.parse_comma_list(')')?;
684 Ok(items)
685 } else {
686 Ok(Vec::new())
687 }
688 }
689
690 fn parse_ident(&mut self) -> Result<String, ParseError> {
691 let start = self.pos;
692 match self.peek() {
693 Some(c) if c.is_ascii_alphabetic() || c == '_' => {
694 self.advance(c.len_utf8());
695 }
696 _ => return Err(self.error(String::from("expected identifier"))),
697 }
698 while let Some(c) = self.peek() {
699 if c.is_ascii_alphanumeric() || c == '_' || c == '-' {
700 self.advance(c.len_utf8());
701 } else {
702 break;
703 }
704 }
705 Ok(String::from(&self.input[start..self.pos]))
706 }
707
708 fn is_ident_continue_at(&self, offset: usize) -> bool {
710 self.remaining()
711 .get(offset..offset + 1)
712 .and_then(|s| s.chars().next())
713 .is_some_and(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-')
714 }
715}
716
717pub fn parse_value(input: &str) -> Result<Value, ParseError> {
719 let mut parser = Parser::new(input);
720 let value = parser.parse_value()?;
721 parser.skip_whitespace();
722 if !parser.is_eof() {
723 return Err(parser.error(alloc::format!("trailing input: '{}'", parser.remaining())));
724 }
725 Ok(value)
726}
727
728impl core::str::FromStr for Value {
729 type Err = ParseError;
730
731 fn from_str(s: &str) -> Result<Self, Self::Err> {
732 parse_value(s)
733 }
734}
735
736#[cfg(test)]
737mod tests {
738 use super::*;
739 use alloc::string::ToString;
740 use alloc::vec;
741
742 #[test]
743 fn test_bool() {
744 assert_eq!(parse_value("true").unwrap(), Value::Bool(true));
745 assert_eq!(parse_value("false").unwrap(), Value::Bool(false));
746 }
747
748 #[test]
749 fn test_numbers() {
750 assert_eq!(parse_value("42u8").unwrap(), Value::U8(42));
751 assert_eq!(parse_value("1000u16").unwrap(), Value::U16(1000));
752 assert_eq!(parse_value("123456u32").unwrap(), Value::U32(123456));
753 assert_eq!(parse_value("99u64").unwrap(), Value::U64(99));
754 assert_eq!(parse_value("-5s8").unwrap(), Value::S8(-5));
755 assert_eq!(parse_value("-100s16").unwrap(), Value::S16(-100));
756 assert_eq!(parse_value("0s32").unwrap(), Value::S32(0));
757 assert_eq!(parse_value("-1s64").unwrap(), Value::S64(-1));
758 assert_eq!(parse_value("3.14f32").unwrap(), Value::F32(3.14));
759 assert_eq!(parse_value("2.718f64").unwrap(), Value::F64(2.718));
760 assert_eq!(parse_value("1.0f32").unwrap(), Value::F32(1.0));
761 }
762
763 #[test]
764 fn test_string() {
765 assert_eq!(
766 parse_value("\"hello\"").unwrap(),
767 Value::String(String::from("hello"))
768 );
769 assert_eq!(
770 parse_value("\"a\\nb\"").unwrap(),
771 Value::String(String::from("a\nb"))
772 );
773 assert_eq!(
774 parse_value("\"a\\\"b\"").unwrap(),
775 Value::String(String::from("a\"b"))
776 );
777 assert_eq!(parse_value("\"\"").unwrap(), Value::String(String::new()));
778 }
779
780 #[test]
781 fn test_char() {
782 assert_eq!(parse_value("'x'").unwrap(), Value::Char('x'));
783 assert_eq!(parse_value("'\\n'").unwrap(), Value::Char('\n'));
784 assert_eq!(parse_value("'\\''").unwrap(), Value::Char('\''));
785 }
786
787 #[test]
788 fn test_tuple() {
789 assert_eq!(parse_value("()").unwrap(), Value::Tuple(Vec::new()));
790 assert_eq!(
791 parse_value("(42u32, \"hi\")").unwrap(),
792 Value::Tuple(vec![Value::U32(42), Value::String(String::from("hi"))])
793 );
794 }
795
796 #[test]
797 fn test_list() {
798 assert_eq!(
799 parse_value("[]<u8>").unwrap(),
800 Value::List {
801 elem_type: ValueType::U8,
802 items: Vec::new()
803 }
804 );
805 assert_eq!(
806 parse_value("[1u8, 2u8, 3u8]").unwrap(),
807 Value::List {
808 elem_type: ValueType::U8,
809 items: vec![Value::U8(1), Value::U8(2), Value::U8(3)]
810 }
811 );
812 }
813
814 #[test]
815 fn test_option() {
816 assert_eq!(
817 parse_value("none<u32>").unwrap(),
818 Value::Option {
819 inner_type: ValueType::U32,
820 value: None
821 }
822 );
823 assert_eq!(
824 parse_value("none<list<u8>>").unwrap(),
825 Value::Option {
826 inner_type: ValueType::List(Box::new(ValueType::U8)),
827 value: None
828 }
829 );
830 assert_eq!(
831 parse_value("some<u32>(42u32)").unwrap(),
832 Value::Option {
833 inner_type: ValueType::U32,
834 value: Some(Box::new(Value::U32(42)))
835 }
836 );
837 }
838
839 #[test]
840 fn test_result() {
841 assert_eq!(
842 parse_value("ok<u32, string>(1u32)").unwrap(),
843 Value::Result {
844 ok_type: ValueType::U32,
845 err_type: ValueType::String,
846 value: Ok(Box::new(Value::U32(1)))
847 }
848 );
849 assert_eq!(
850 parse_value("err<u32, string>(\"bad\")").unwrap(),
851 Value::Result {
852 ok_type: ValueType::U32,
853 err_type: ValueType::String,
854 value: Err(Box::new(Value::String(String::from("bad"))))
855 }
856 );
857 }
858
859 #[test]
860 fn test_record() {
861 let v = parse_value("actor-state{greeting: \"Hello\", count: 0u32}").unwrap();
862 assert_eq!(
863 v,
864 Value::Record {
865 type_name: String::from("actor-state"),
866 fields: vec![
867 (
868 String::from("greeting"),
869 Value::String(String::from("Hello"))
870 ),
871 (String::from("count"), Value::U32(0)),
872 ],
873 }
874 );
875 }
876
877 #[test]
878 fn test_variant() {
879 let v = parse_value("color::rgb(255u8, 0u8, 128u8)").unwrap();
880 assert_eq!(
881 v,
882 Value::Variant {
883 type_name: String::from("color"),
884 case_name: String::from("rgb"),
885 tag: 0,
886 payload: vec![Value::U8(255), Value::U8(0), Value::U8(128)],
887 }
888 );
889
890 let v = parse_value("status::active").unwrap();
892 assert_eq!(
893 v,
894 Value::Variant {
895 type_name: String::from("status"),
896 case_name: String::from("active"),
897 tag: 0,
898 payload: Vec::new(),
899 }
900 );
901 }
902
903 #[test]
904 fn test_variant_empty_type() {
905 let v = parse_value("::my-case(1u32)").unwrap();
906 assert_eq!(
907 v,
908 Value::Variant {
909 type_name: String::new(),
910 case_name: String::from("my-case"),
911 tag: 0,
912 payload: vec![Value::U32(1)],
913 }
914 );
915 }
916
917 #[test]
918 fn test_flags() {
919 assert_eq!(parse_value("flags(0xff)").unwrap(), Value::Flags(0xff));
920 assert_eq!(parse_value("flags(0x0)").unwrap(), Value::Flags(0));
921 }
922
923 #[test]
924 fn test_round_trip() {
925 let values = vec![
926 Value::Bool(true),
927 Value::U32(42),
928 Value::S64(-100),
929 Value::F32(3.14),
930 Value::String(String::from("hello \"world\"\nbye")),
931 Value::Char('\t'),
932 Value::Tuple(vec![Value::U8(1), Value::Bool(false)]),
933 Value::List {
934 elem_type: ValueType::S32,
935 items: vec![Value::S32(1), Value::S32(2)],
936 },
937 Value::Option {
938 inner_type: ValueType::String,
939 value: Some(Box::new(Value::String(String::from("hi")))),
940 },
941 Value::Option {
942 inner_type: ValueType::S32,
943 value: None,
944 },
945 Value::Result {
946 ok_type: ValueType::U32,
947 err_type: ValueType::String,
948 value: Ok(Box::new(Value::U32(99))),
949 },
950 Value::Record {
951 type_name: String::from("point"),
952 fields: vec![
953 (String::from("x"), Value::S32(10)),
954 (String::from("y"), Value::S32(20)),
955 ],
956 },
957 Value::Variant {
958 type_name: String::from("expr"),
959 case_name: String::from("num"),
960 tag: 1,
961 payload: vec![Value::S64(42)],
962 },
963 Value::Flags(0xdeadbeef),
964 ];
965
966 for val in &values {
967 let text = alloc::format!("{}", val);
968 let parsed = parse_value(&text).unwrap_or_else(|e| {
969 panic!("Failed to parse '{}': {}", text, e);
970 });
971 let reparsed_text = alloc::format!("{}", parsed);
973 assert_eq!(text, reparsed_text, "Round-trip failed for: {}", text);
974 }
975 }
976
977 #[test]
978 fn test_nested_record() {
979 let input = "outer{inner: point{x: 1s32, y: 2s32}, name: \"test\"}";
980 let v = parse_value(input).unwrap();
981 let output = alloc::format!("{}", v);
982 assert_eq!(input, output);
983 }
984
985 #[test]
986 fn test_cgrf_round_trip() {
987 let values = vec![
990 Value::Option {
991 inner_type: ValueType::List(Box::new(ValueType::U8)),
992 value: None,
993 },
994 Value::Result {
995 ok_type: ValueType::Tuple(vec![]),
996 err_type: ValueType::String,
997 value: Ok(Box::new(Value::Tuple(vec![]))),
998 },
999 Value::List {
1000 elem_type: ValueType::U8,
1001 items: Vec::new(),
1002 },
1003 Value::Record {
1004 type_name: String::from("host-function-call"),
1005 fields: vec![
1006 (
1007 String::from("interface"),
1008 Value::String(String::from("theater:simple/runtime")),
1009 ),
1010 (
1011 String::from("function"),
1012 Value::String(String::from("shutdown")),
1013 ),
1014 (
1015 String::from("input"),
1016 Value::Option {
1017 inner_type: ValueType::List(Box::new(ValueType::U8)),
1018 value: None,
1019 },
1020 ),
1021 (
1022 String::from("output"),
1023 Value::Result {
1024 ok_type: ValueType::Tuple(vec![]),
1025 err_type: ValueType::String,
1026 value: Ok(Box::new(Value::Tuple(vec![]))),
1027 },
1028 ),
1029 ],
1030 },
1031 ];
1032
1033 for val in &values {
1034 let original_bytes = crate::encode(val).unwrap();
1035 let text = alloc::format!("{}", val);
1036 let parsed = parse_value(&text).unwrap_or_else(|e| {
1037 panic!("Failed to parse '{}': {}", text, e);
1038 });
1039 let reparsed_bytes = crate::encode(&parsed).unwrap();
1040 assert_eq!(
1041 original_bytes, reparsed_bytes,
1042 "CGRF bytes differ after round-trip for: {}",
1043 text
1044 );
1045 }
1046 }
1047
1048 #[test]
1049 fn test_trailing_comma() {
1050 assert_eq!(
1052 parse_value("(1u32, 2u32,)").unwrap(),
1053 Value::Tuple(vec![Value::U32(1), Value::U32(2)])
1054 );
1055 assert_eq!(
1056 parse_value("[1u8,]").unwrap(),
1057 Value::List {
1058 elem_type: ValueType::U8,
1059 items: vec![Value::U8(1)]
1060 }
1061 );
1062 }
1063}