Oregami
Repositories/oxedyne/fe2o3

oxedyne/fe2o3/fe2o3_syntax/src/msg.rs

90.8 KiB, 8 runs

created by r1870400018:1055, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1use crate::{
2 arg::Arg,
3 cmd::Cmd,
4 core::{
5 Syntax,
6 SyntaxRef,
7 },
8 key::Key,
9 val::{
10 Slots,
11 Val,
12 },
13};
14
15use oxedyne_fe2o3_core::{
16 prelude::*,
17 byte::{
18 Encoding,
19 IntoBytes,
20 ToBytes,
21 FromBytes,
22 },
23 map::{
24 MapRec,
25 Recursive,
26 },
27};
28use oxedyne_fe2o3_jdat::prelude::*;
29use oxedyne_fe2o3_num::{
30 float::Float64,
31 prelude::bigdecimal::ToPrimitive,
32};
33use oxedyne_fe2o3_text::split::StringSplitter;
34
35use std::{
36 collections::{
37 BTreeMap,
38 BTreeSet,
39 },
40 fmt,
41};
42
43/// Where the words of a text message came from, which decides how a string value is read.
44#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
45pub enum Source {
46 #[default]
47 Line, // a REPL line or a wire message: every value is decoded as a daticle
48 Argv, // a process's arguments, already split and unquoted by a shell
49}
50
51#[derive(Debug, PartialEq)]
52pub enum Collecting {
53 None,
54 Message,
55 MessageArg,
56 Command,
57 CommandArg,
58}
59
60/// Used to capture the outstanding values and active command and/or argument at the end of message processing.
61#[derive(Clone, Debug, Default)]
62pub struct MsgEndState {
63 pub vals: Vec<Kind>,
64 pub arg: Option<String>,
65 pub cmd: Option<String>,
66 pub help: bool, // a command line stopped at -h or --help
67}
68
69/// A `Syntax` specifies message structure for validation, while `Msg` is used for transmission
70/// and receipt of messages using the syntax. `Msg` constructors from binary and string formats
71/// cannot be associated methods because of the essential requirement for an embedded
72/// `SyntaxRef`.
73#[derive(Clone, Debug)]
74pub struct Msg {
75 pub syntax: SyntaxRef,
76 pub sname: String, // Syntax name
77 // Message contents
78 pub vals: Vec<Dat>,
79 pub args: BTreeMap<String, Vec<Dat>>, // one-to-one
80 pub cmds: BTreeMap<String, MsgCmd>, // one-to-one
81 // Decoding
82 pub end: MsgEndState,
83 // Encoding
84 pub enc: Encoding,
85}
86
87impl fmt::Display for Msg {
88 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89 let mut first = true;
90 for val in &self.vals {
91 if !first { ok!(write!(f, " ")); }
92 ok!(write!(f, "{:?}", val));
93 first = false;
94 }
95 for (k, argvals) in &self.args {
96 if !first { ok!(write!(f, " ")); }
97 // Written as a reader would type it, not as the message files it.
98 ok!(write!(f, "{}", self.arg_short_name(k)));
99 for val in argvals {
100 ok!(write!(f, " {:?}", val));
101 }
102 first = false;
103 }
104 // A command prints its own name, so printing the key as well said it
105 // twice.
106 for (_k, cmd) in &self.cmds {
107 if !first { ok!(write!(f, " ")); }
108 ok!(write!(f, "{}", cmd));
109 first = false;
110 }
111 Ok(())
112 }
113}
114
115impl ToBytes for Msg {
116
117 fn to_bytes(&self, mut buf: Vec<u8>) -> Outcome<Vec<u8>> {
118 let encoding = self.encoding();
119 buf.push(*encoding as u8);
120 match encoding {
121 Encoding::Binary => {
122 // Message values
123 buf.push(Dat::LIST_CODE);
124 buf = res!(Dat::vec_to_bytes(&self.vals, buf));
125 // Message arguments
126 buf = res!(Dat::C64(self.args.len() as u64).to_bytes(buf));
127 for (k, v) in &self.args {
128 if let Some(arg) = self.syntax().args.get_recursive(&Key::Str(k.clone())) {
129 buf = res!(Dat::U16(arg.id).to_bytes(buf));
130 buf.push(Dat::LIST_CODE);
131 buf = res!(Dat::vec_to_bytes(&v, buf));
132 }
133 }
134 // Commands
135 buf = res!(Dat::C64(self.cmds.len() as u64).to_bytes(buf));
136 for (k, msgcmd) in &self.cmds {
137 if let Some(cmd) = self.syntax().cmds.get_recursive(&Key::Str(k.clone())) {
138 buf = res!(Dat::U16(cmd.id).to_bytes(buf));
139 // Command values
140 buf.push(Dat::LIST_CODE);
141 buf = res!(Dat::vec_to_bytes(&msgcmd.vals, buf));
142 // Command arguments
143 buf = res!(Dat::C64(msgcmd.args.len() as u64).to_bytes(buf));
144 for (k, v) in &msgcmd.args {
145 if let Some(arg) = cmd.args.get_recursive(&Key::Str(k.clone())) {
146 buf = res!(Dat::U16(arg.id).to_bytes(buf));
147 buf.push(Dat::LIST_CODE);
148 buf = res!(Dat::vec_to_bytes(&v, buf));
149 }
150 }
151 // Only a command declaring a rest carries one, so the bytes of every
152 // other command are as they were.
153 if cmd.config().rest.is_some() {
154 match &msgcmd.rest {
155 Some(words) => {
156 buf = res!(Dat::Bool(true).to_bytes(buf));
157 buf.push(Dat::LIST_CODE);
158 buf = res!(Dat::vec_to_bytes(words, buf));
159 },
160 None => buf = res!(Dat::Bool(false).to_bytes(buf)),
161 }
162 }
163 }
164 }
165 },
166 Encoding::UTF8 => buf.extend_from_slice(self.to_string().as_bytes()),
167 _ => return Err(err!("Unimplemented message encoding {:?}.", encoding;
168 Unimplemented, Encode)),
169 }
170 debug!("{:02x?}", buf);
171 Ok(buf)
172 }
173}
174
175impl IntoBytes for Msg {
176
177 fn into_bytes(self, buf: Vec<u8>) -> Outcome<Vec<u8>> {
178 self.to_bytes(buf) // TODO check for potential optimisations
179 }
180}
181
182impl Msg {
183
184 pub fn new(syntax: SyntaxRef) -> Self {
185 let sname = syntax.config().name.clone();
186 Self {
187 syntax,
188 sname,
189 vals: Vec::new(),
190 args: BTreeMap::new(),
191 cmds: BTreeMap::new(),
192 end: MsgEndState::default(),
193 enc: Encoding::default(),
194 }
195 }
196
197 pub fn new_cmd<S: Into<String>>(&self, name: S) -> Outcome<MsgCmd> {
198 MsgCmd::new(self.syntaxref(), name)
199 }
200
201 pub fn syntaxref(&self) -> SyntaxRef { self.syntax.clone() }
202 pub fn syntax<'a>(&'a self) -> &'a Syntax { self.syntax.as_ref() }
203
204 pub fn encoding(&self) -> &Encoding { &self.enc }
205 pub fn set_encoding(&mut self, enc: Encoding) { self.enc = enc; }
206
207 fn get_syntax_arg<'a, S: Into<String>>(
208 &'a self,
209 arg_name: S,
210 )
211 -> Outcome<&'a Arg>
212 {
213 let arg_name = arg_name.into();
214 self.syntax().args.get_recursive(&Key::Str(arg_name.clone())).ok_or_else(|| err!(
215 "Cannot find this message argument '{}' in the syntax '{}'.",
216 arg_name, self.sname;
217 Missing))
218 }
219
220 fn arg_key<S: Into<String>>(&self, arg_name: S) -> String {
221 let arg_name = arg_name.into();
222 match self.syntax().args.get_recursive(&Key::Str(arg_name.clone())) {
223 Some(arg) => arg.canonical_name(),
224 None => arg_name,
225 }
226 }
227
228 fn arg_short_name<S: Into<String>>(&self, arg_name: S) -> String {
229 let arg_name = arg_name.into();
230 match self.syntax().args.get_recursive(&Key::Str(arg_name.clone())) {
231 Some(arg) => arg.short_name(),
232 None => arg_name,
233 }
234 }
235
236 pub fn add_cmd(
237 mut self,
238 msgcmd: MsgCmd,
239 )
240 -> Outcome<Self>
241 {
242 let name = msgcmd.name.clone();
243 if !self.syntax().cmds.contains_key(&Key::Str(name.clone())) {
244 return Err(err!(
245 "Can't find command '{}' in syntax '{}'.",
246 name, self.sname;
247 Invalid, Input));
248 }
249 self.cmds.insert(name, msgcmd);
250 Ok(self)
251 }
252
253 pub fn add_arg<S: Into<String>>(
254 mut self,
255 arg_name: S,
256 )
257 -> Outcome<Self>
258 {
259 let arg_name = arg_name.into();
260 // Make sure the argument exists in the syntax.
261 if !self.syntax().args.contains_key(&Key::Str(arg_name.clone())) {
262 return Err(err!(
263 "Can't find message argument '{}' in syntax '{}'.",
264 arg_name, self.sname;
265 Invalid, Input));
266 }
267 let key = self.arg_key(arg_name.clone());
268 // Check whether it has already been added to the Msg.
269 if self.args.contains_key(&key) {
270 return Err(err!(
271 "Argument '{}' has already been added to message.", arg_name;
272 Invalid, Input, Exists));
273 }
274 self.args.insert(key, Vec::new());
275 Ok(self)
276 }
277
278 pub fn add_msg_val(
279 self,
280 val: Dat,
281 )
282 -> Outcome<Self>
283 {
284 self.add_val::<String>(None, Some(val))
285 }
286
287 pub fn add_arg_val<S: Into<String>>(
288 self,
289 arg_name: S,
290 val: Option<Dat>,
291 )
292 -> Outcome<Self>
293 {
294 self.add_val(Some(arg_name), val)
295 }
296
297 pub fn add_val<S: Into<String>>(
298 mut self,
299 arg_opt: Option<S>,
300 val_opt: Option<Dat>,
301 )
302 -> Outcome<Self>
303 {
304 let arg_opt = arg_opt.map(|s| s.into());
305 let exp_vals: Vec<Val> = match &arg_opt {
306 Some(arg_name) => {
307 let arg = res!(self.get_syntax_arg(arg_name.clone()));
308 arg.config().vals.clone()
309 },
310 None => self.syntax().config().vals.clone(),
311 };
312 // File the value under the argument's one name, whichever of its names
313 // the caller wrote.
314 let arg_opt = arg_opt.map(|name| self.arg_key(name));
315
316 let v: &mut Vec<Dat> = match arg_opt {
317 Some(arg_name) => match self.args.get_mut(&arg_name) {
318 Some(v) => v,
319 None => {
320 self.args.insert(arg_name.clone(), Vec::new());
321 match self.args.get_mut(&arg_name) {
322 Some(v) => v,
323 None => return Err(err!(
324 "Argument '{}' was just created, but no longer present.", arg_name;
325 Bug, Unreachable)),
326 }
327 },
328 },
329 None => &mut self.vals,
330 };
331
332 let next = match Val::slot(&exp_vals, v.len()) {
333 Some(next) => next,
334 None => return Err(err!(
335 "Message already has all {} of its expected values.", v.len();
336 Invalid, Input, Exists)),
337 };
338
339 match val_opt {
340 Some(val) => {
341 if val.kind() == next.kind {
342 v.push(val);
343 } else {
344 return Err(err!(
345 "Message already has {} values, and the next one must be a {:?}, \
346 not a {:?}.", v.len(), next.kind, val.kind();
347 Invalid, Input));
348 }
349 },
350 None => (),
351 }
352
353 Ok(self)
354 }
355
356 pub fn get_vals(&self) -> Option<&Vec<Dat>> {
357 if self.vals.len() == 0 {
358 None
359 } else {
360 Some(&self.vals)
361 }
362 }
363
364 pub fn get_arg_vals<S: Into<String>>(&self, a: S) -> Option<&Vec<Dat>> {
365 match self.args.get(&self.arg_key(a)) {
366 Some(vals) => if vals.len() == 0 {
367 None
368 } else {
369 Some(&vals)
370 },
371 None => None,
372 }
373 }
374
375 pub fn get_arg_vals_mut<S: Into<String>>(&mut self, a: S) -> Option<&mut Vec<Dat>> {
376 let key = self.arg_key(a);
377 match self.args.get_mut(&key) {
378 Some(vals) => if vals.len() == 0 {
379 None
380 } else {
381 Some(vals)
382 },
383 None => None,
384 }
385 }
386
387 pub fn get_cmd<S: Into<String>>(&self, c: S) -> Option<&MsgCmd> {
388 self.cmds.get(&(c.into()))
389 }
390
391 pub fn get_cmd_mut<S: Into<String>>(&mut self, c: S) -> Option<&mut MsgCmd> {
392 self.cmds.get_mut(&(c.into()))
393 }
394
395 pub fn remove_cmd<S: Into<String>>(&mut self, c: S) -> Option<MsgCmd> {
396 let c = c.into();
397 self.cmds.remove(&c)
398 }
399
400 pub fn has_args(&self) -> bool {
401 self.args.len() > 0
402 }
403
404 pub fn has_arg<S: Into<String>>(&self, a: S) -> bool {
405 self.args.contains_key(&self.arg_key(a))
406 }
407
408 pub fn has_only_arg<S: Into<String>>(&self, a: S) -> Outcome<bool> {
409 let a = a.into();
410 let has = self.args.contains_key(&self.arg_key(a.clone()));
411 if self.args.len() > 1 {
412 Err(err!(
413 "The argument '{}' {}", a, if has {
414 "does not exist and there are other arguments."
415 } else {
416 "does exist but there are other arguments."
417 };
418 Input, Invalid, Excessive))
419 } else {
420 Ok(has)
421 }
422 }
423
424 pub fn has_cmd<S: Into<String>>(&self, c: S) -> bool {
425 self.cmds.contains_key(&(c.into()))
426 }
427
428 pub fn get_cmd_vals<S: Into<String>>(&self, c: S) -> Option<&Vec<Dat>> {
429 if let Some(msgcmd) = self.get_cmd(&(c.into())) {
430 return Some(&msgcmd.vals);
431 }
432 None
433 }
434
435 pub fn get_cmd_vals_mut<S: Into<String>>(&mut self, c: S) -> Option<&mut Vec<Dat>> {
436 if let Some(msgcmd) = self.get_cmd_mut(&(c.into())) {
437 return Some(&mut msgcmd.vals);
438 }
439 None
440 }
441
442 pub fn get_cmd_arg_vals<S: Into<String>>(
443 &self,
444 c: S,
445 a: S,
446 )
447 -> Option<&Vec<Dat>>
448 {
449 if let Some(msgcmd) = self.get_cmd(&(c.into())) {
450 return msgcmd.get_arg_vals(&(a.into()));
451 }
452 None
453 }
454
455 pub fn validate(&self) -> Outcome<()> {
456 let syntax = self.syntax();
457 if self.vals.len() != syntax.config().vals.len() {
458 return Err(err!(
459 "The syntax '{}' requires {} message values, the message has {}.",
460 syntax,
461 syntax.config().vals.len(),
462 self.vals.len();
463 Input, Invalid));
464 } else if self.args.len() < syntax.config().rargs.len() {
465 return Err(err!(
466 "The syntax '{}' requires {} message arguments, the message has {}.",
467 syntax,
468 syntax.config().rargs.len(),
469 self.args.len();
470 Input, Invalid));
471 }
472
473 res!(self.check_rargs(
474 fmt!("syntax '{}' message argument", syntax),
475 &syntax.config().rargs,
476 &syntax.args,
477 ));
478
479 Ok(())
480
481 }
482
483 fn check_rargs(
484 &self,
485 desc: String,
486 rargs: &Vec<String>,
487 args: &BTreeMap<Key, Recursive<Key, Arg>>,
488 )
489 -> Outcome<()>
490 {
491 for arg_name in rargs {
492 if let Some(arg) = args.get_recursive(&Key::Str(arg_name.clone())) {
493 let mut found = false;
494 for (k, _) in &self.args {
495 if *k == arg.canonical_name() {
496 found = true;
497 break;
498 }
499 }
500 if !found {
501 return Err(err!(
502 "The required {} '{}' was not found in the message.",
503 desc,
504 arg_name;
505 Input, Invalid, Missing));
506 }
507 }
508 }
509
510 Ok(())
511 }
512
513 // STRING IO
514 //
515 pub fn to_lines(&self) -> Vec<String> {
516 let mut lines = Vec::new();
517 if self.vals.len() > 0 {
518 lines.push(fmt!("Message values [{}]:", self.vals.len()));
519 for val in &self.vals {
520 lines.push(fmt!("{:?}", val));
521 }
522 } else {
523 lines.push(fmt!("No message values."));
524 }
525 if self.args.len() > 0 {
526 for (k, vals) in &self.args {
527 if vals.len() > 0 {
528 lines.push(fmt!("Message argument {:?} values [{}]:", k, self.args.len()));
529 for val in vals {
530 lines.push(fmt!("{:?}", val));
531 }
532 } else {
533 lines.push(fmt!("Message argument {:?} (no values).", k));
534 }
535 }
536 } else {
537 lines.push(fmt!("No message arguments."));
538 }
539 if self.cmds.len() > 0 {
540 for (kc, cmd) in &self.cmds {
541 if cmd.vals.len() > 0 {
542 lines.push(fmt!("Command {:?} values [{}]:", kc, cmd.vals.len()));
543 for val in &cmd.vals {
544 lines.push(fmt!("{:?}", val));
545 }
546 } else {
547 lines.push(fmt!("No command values."));
548 }
549 if cmd.args.len() > 0 {
550 for (ka, vals) in &cmd.args {
551 if vals.len() > 0 {
552 lines.push(fmt!(
553 "Command {:?} argument {:?} values [{}]:",
554 kc, ka, vals.len(),
555 ));
556 for val in vals {
557 lines.push(fmt!("{:?}", val));
558 }
559 } else {
560 lines.push(fmt!(
561 "Message command {:?} argument {:?} (no values).",
562 kc, ka,
563 ));
564 }
565 }
566 } else {
567 lines.push(fmt!("No command {:?} arguments.", kc));
568 }
569 }
570 } else {
571 lines.push(fmt!("No message commands."));
572 }
573 lines.push(fmt!("Message end state:"));
574 lines.push(fmt!(" Outstanding message value kinds: {:?}", self.end.vals));
575 if let Some(cmd_name) = &self.end.cmd {
576 lines.push(fmt!(" Active command: {}", cmd_name));
577 } else {
578 lines.push(fmt!(" No active command."));
579 }
580 if let Some(arg_name) = &self.end.arg {
581 lines.push(fmt!(" Active message or command argument: {}", arg_name));
582 } else {
583 lines.push(fmt!(" No active message or command argument."));
584 }
585 lines
586 }
587
588 /// During processing of a text message, arguments are removed from a list of required
589 /// arguments as they are received. If no more arguments are expected and this list is not
590 /// empty, an error needs to be raised indicating which required arguments were not received.
591 fn check_required_txt_args(
592 &self,
593 rargs: Vec<&str>,
594 active_cmd: &Option<&Cmd>,
595 )
596 -> Outcome<()>
597 {
598 if rargs.len() > 0 {
599 match active_cmd {
600 Some(cmd) => return Err(err!(
601 "The syntax '{}' requires the presence of the arguments {:?} \
602 for command '{}', but the following were not detected before the \
603 presence of a command: {:?}",
604 self.syntax().config().name, cmd.config().rargs, cmd.config().name, rargs;
605 Input, Missing)),
606 None => return Err(err!(
607 "The syntax '{}' requires the presence of the commandless \
608 arguments {:?}, but the following were not detected before the \
609 presence of a command: {:?}",
610 self.syntax().config().name, self.syntax().config().rargs, rargs;
611 Input, Missing)),
612 }
613 }
614 Ok(())
615 }
616
617 fn is_word_a_cmd(
618 &self,
619 word: &Key,
620 pos: usize,
621 similarity_threshold: Option<f64>,
622 argv: bool,
623 )
624 -> Outcome<&Cmd>
625 {
626 if let Some(cmd) = self.syntax().cmds.get_recursive(word) {
627 // We found it in the syntax, it's a command.
628 return Ok(&cmd);
629 }
630 let sname = &self.syntax().config().name;
631 if let (Some(threshold), Key::Str(word)) = (similarity_threshold, word) {
632 let names = self.syntax().cmds_in_order().into_iter()
633 .map(|c| c.config().name.clone()).collect::<Vec<_>>();
634 if let Some(suggestion) = Self::closest(word, &names, threshold) {
635 return Err(if argv {
636 // Argv is a person at a prompt, not a message parser; point them at
637 // help rather than reciting what a word is not.
638 err!(
639 "Did you mean '{}'? '{}' at position {} is not a command. Type \
640 '{} help' for the list.",
641 suggestion, word, pos, sname;
642 Input, Invalid, Suggestion)
643 } else {
644 err!(
645 "Did you mean '{}'? The word '{}' at position {} is not an \
646 argument, and neither is it a command of '{}'.",
647 suggestion, word, pos, sname;
648 Input, Invalid, Suggestion)
649 });
650 }
651 }
652 Err(if argv {
653 err!(
654 "'{}' at position {} is not a command. Type '{} help' for the list.",
655 word, pos, sname;
656 Input, Invalid)
657 } else {
658 err!(
659 "The word '{}' at position {} is not an argument, and neither is it a \
660 command of '{}'.",
661 word, pos, sname;
662 Input, Invalid)
663 })
664 }
665
666 /// The candidate nearest to the word by edit distance, if it is similar enough.
667 pub fn closest(
668 word: &str,
669 candidates: &[String],
670 threshold: f64,
671 )
672 -> Option<String>
673 {
674 let mut min_dist = word.chars().count();
675 let mut closest = None;
676 for cand in candidates {
677 let dist = levenshtein::levenshtein(word, cand);
678 if dist < min_dist {
679 min_dist = dist;
680 let ratio: f64 = 1.0 - (
681 dist as f64
682 / std::cmp::max(word.chars().count(), cand.chars().count()) as f64
683 );
684 if ratio > threshold {
685 closest = Some(cand.clone());
686 }
687 }
688 }
689 closest
690 }
691
692 /// If the given argument is on the given list of required arguments, the argument is removed
693 /// from the list.
694 fn revise_reqd_arg_list(
695 arg_name: &str,
696 rargs: &mut Vec<&str>,
697 ) {
698 for i in 0..rargs.len() {
699 if rargs[i] == arg_name {
700 rargs.remove(i);
701 return;
702 }
703 }
704 }
705
706 pub fn from_str(
707 &self,
708 msg: &str,
709 similarity_threshold: Option<f64>,
710 )
711 -> Outcome<Self>
712 {
713 let iter = StringSplitter::default()
714 .split(msg)
715 .into_iter().map(|x| x.to_val());
716 self.rx_text_iter(iter, similarity_threshold)
717 }
718
719 /// Takes a string iterator and interprets it as a syntax message. Returns a valid message,
720 /// or an error.
721 pub fn rx_text_iter<I: IntoIterator<Item=String>>(
722 &self,
723 seq: I,
724 similarity_threshold: Option<f64>,
725 )
726 -> Outcome<Self>
727 {
728 self.rx_words(seq, similarity_threshold, Source::Line)
729 }
730
731 /// Reads the words of a process's command line, which a shell has already split and
732 /// unquoted. A string value is taken as it stands, and a value that is required but absent
733 /// is an error rather than an outstanding value.
734 pub fn rx_argv<I: IntoIterator<Item=String>>(
735 &self,
736 seq: I,
737 similarity_threshold: Option<f64>,
738 )
739 -> Outcome<Self>
740 {
741 self.rx_words(seq, similarity_threshold, Source::Argv)
742 }
743
744 /// Does the word have the shape of an option? A dash and a letter, as in `-v` or `-abc`, or
745 /// two dashes and a name, as in `--dry-run` or `--dry-run=x`. A negative number does not, nor
746 /// `-`, `--`, or a word holding a space or a stop, such as `- fix typo` or `-x.txt`: a word
747 /// that could only be a value is read as one.
748 pub fn looks_like_option(word: &str) -> bool {
749 let name = |s: &str| {
750 let mut chars = s.chars();
751 match chars.next() {
752 Some(c) if c.is_ascii_alphabetic() => chars.all(|c| c.is_ascii_alphanumeric()
753 || c == '-' || c == '_'),
754 _ => false,
755 }
756 };
757 if let Some(long) = word.strip_prefix("--") {
758 return match long.split_once('=') {
759 Some((head, _)) => name(head),
760 None => name(long),
761 };
762 }
763 match word.strip_prefix('-') {
764 Some(short) => {
765 let mut chars = short.chars();
766 match chars.next() {
767 Some(c) if c.is_ascii_alphabetic() => chars.all(|c| c.is_ascii_alphanumeric()),
768 _ => false,
769 }
770 },
771 None => false,
772 }
773 }
774
775 /// Is the word one of the two that ask for help?
776 pub fn is_help_flag(word: &str) -> bool {
777 word == "-h" || word == "--help"
778 }
779
780 /// The argument a word names, and whether it is a message argument rather than one of the
781 /// active command's. On a command line only a hyphenated name counts, so a value that
782 /// happens to spell an argument's internal name stays a value.
783 fn find_arg<'a>(
784 syntax: &'a Syntax,
785 word: &str,
786 active_cmd: Option<&'a Cmd>,
787 src: Source,
788 )
789 -> Option<(&'a Arg, bool)>
790 {
791 if src == Source::Argv && !word.starts_with('-') {
792 return None;
793 }
794 let key = Key::Str(word.to_string());
795 match active_cmd {
796 Some(cmd) => match cmd.args.get_recursive(&key) {
797 Some(arg) => Some((arg, false)),
798 None => if src == Source::Argv {
799 // A message option may follow the command on a command line.
800 syntax.args.get_recursive(&key).map(|arg| (arg, true))
801 } else {
802 None
803 },
804 },
805 None => syntax.args.get_recursive(&key).map(|arg| (arg, true)),
806 }
807 }
808
809 fn owner_desc(
810 coll: &Collecting,
811 active_cmd: Option<&Cmd>,
812 active_arg: Option<&Arg>,
813 )
814 -> String
815 {
816 match coll {
817 Collecting::MessageArg | Collecting::CommandArg => match active_arg {
818 Some(arg) => fmt!("the option '{}'", arg.long_name()),
819 None => fmt!("an option"),
820 },
821 Collecting::Command => match active_cmd {
822 Some(cmd) => fmt!("the command '{}'", cmd.config().name),
823 None => fmt!("a command"),
824 },
825 _ => fmt!("the message"),
826 }
827 }
828
829 /// The refusal of a word a command has no value left for.
830 fn excess(cmd: &Cmd, word: &str, pos: usize) -> Error<ErrTag> {
831 match &cmd.config().excess {
832 Some(sentence) => err!(
833 "{} (found '{}' at position {}).", sentence, word, pos;
834 Input, Excessive),
835 None => err!(
836 "The word '{}' at position {} is more than the command '{}' takes.",
837 word, pos, cmd.config().name;
838 Input, Excessive),
839 }
840 }
841
842 fn push_val(
843 msgrx: &mut Msg,
844 coll: &Collecting,
845 active_cmd: Option<&Cmd>,
846 active_arg: Option<&Arg>,
847 d: Dat,
848 )
849 -> Outcome<()>
850 {
851 match coll {
852 Collecting::Message => msgrx.vals.push(d),
853 Collecting::MessageArg => if let Some(arg) = active_arg {
854 msgrx.args.entry(arg.canonical_name()).or_insert(Vec::new()).push(d);
855 },
856 Collecting::Command => if let Some(cmd) = active_cmd {
857 let ckey = cmd.config().name.clone();
858 let entry = msgrx.cmds.entry(ckey.clone())
859 .or_insert(res!(MsgCmd::new(msgrx.syntax.clone(), ckey)));
860 entry.vals.push(d);
861 },
862 Collecting::CommandArg => if let Some(cmd) = active_cmd {
863 let ckey = cmd.config().name.clone();
864 let entry = msgrx.cmds.entry(ckey.clone())
865 .or_insert(res!(MsgCmd::new(msgrx.syntax.clone(), ckey)));
866 if let Some(arg) = active_arg {
867 entry.args.entry(arg.canonical_name()).or_insert(Vec::new()).push(d);
868 }
869 },
870 Collecting::None => return Err(err!(
871 "A value was read while nothing was collecting values.";
872 Bug, Unexpected)),
873 }
874 Ok(())
875 }
876
877 /// Reads a word as a value of the expected kind. From a command line a string is the word
878 /// itself: decoding it would turn `42` into a number and `(x)` into a tuple, and leave
879 /// `don't` with an unbalanced quote.
880 pub fn decode_word(
881 word: &str,
882 val: &Val,
883 src: Source,
884 pos: usize,
885 owner: &str,
886 )
887 -> Outcome<Dat>
888 {
889 let kind = &val.kind;
890 if src == Source::Argv && *kind == Kind::Str {
891 return Ok(Dat::Str(word.to_string()));
892 }
893 let mut d = match Dat::decode_string(word) {
894 Ok(d) => d,
895 Err(e) => return Err(err!(e,
896 "The word '{}' at position {}, <{}> for {}, could not be read.",
897 word, pos, val.label(), owner;
898 Input, Invalid, Decode)),
899 };
900 // Coercion may be necessary for positive values of signed kinds.
901 match kind {
902 Kind::I8 => if let Dat::U8(v) = d {
903 d = Dat::I8(try_into!(i8, v));
904 },
905 Kind::I16 => match d {
906 Dat::I8(v) => d = Dat::I16(try_into!(i16, v)),
907 Dat::U8(v) => d = Dat::I16(try_into!(i16, v)),
908 Dat::U16(v) => d = Dat::I16(try_into!(i16, v)),
909 _ => (),
910 },
911 Kind::I32 => match d {
912 Dat::I8(v) => d = Dat::I32(try_into!(i32, v)),
913 Dat::I16(v) => d = Dat::I32(try_into!(i32, v)),
914 Dat::U8(v) => d = Dat::I32(try_into!(i32, v)),
915 Dat::U16(v) => d = Dat::I32(try_into!(i32, v)),
916 Dat::U32(v) => d = Dat::I32(try_into!(i32, v)),
917 _ => (),
918 },
919 Kind::I64 => match d {
920 Dat::I8(v) => d = Dat::I64(try_into!(i64, v)),
921 Dat::I16(v) => d = Dat::I64(try_into!(i64, v)),
922 Dat::I32(v) => d = Dat::I64(try_into!(i64, v)),
923 Dat::U8(v) => d = Dat::I64(try_into!(i64, v)),
924 Dat::U16(v) => d = Dat::I64(try_into!(i64, v)),
925 Dat::U32(v) => d = Dat::I64(try_into!(i64, v)),
926 Dat::U64(v) => d = Dat::I64(try_into!(i64, v)),
927 _ => (),
928 },
929 Kind::I128 => match d {
930 Dat::I8(v) => d = Dat::I128(try_into!(i128, v)),
931 Dat::I16(v) => d = Dat::I128(try_into!(i128, v)),
932 Dat::I32(v) => d = Dat::I128(try_into!(i128, v)),
933 Dat::I64(v) => d = Dat::I128(try_into!(i128, v)),
934 Dat::U8(v) => d = Dat::I128(try_into!(i128, v)),
935 Dat::U16(v) => d = Dat::I128(try_into!(i128, v)),
936 Dat::U32(v) => d = Dat::I128(try_into!(i128, v)),
937 Dat::U64(v) => d = Dat::I128(try_into!(i128, v)),
938 Dat::U128(v) => d = Dat::I128(try_into!(i128, v)),
939 _ => (),
940 },
941 Kind::U16 => match d {
942 Dat::U8(v) => d = Dat::U16(try_into!(u16, v)),
943 _ => (),
944 },
945 Kind::U32 => match d {
946 Dat::U8(v) => d = Dat::U32(try_into!(u32, v)),
947 Dat::U16(v) => d = Dat::U32(try_into!(u32, v)),
948 _ => (),
949 },
950 Kind::U64 => match d {
951 Dat::U8(v) => d = Dat::U64(try_into!(u64, v)),
952 Dat::U16(v) => d = Dat::U64(try_into!(u64, v)),
953 Dat::U32(v) => d = Dat::U64(try_into!(u64, v)),
954 _ => (),
955 },
956 Kind::U128 => match d {
957 Dat::U8(v) => d = Dat::U128(try_into!(u128, v)),
958 Dat::U16(v) => d = Dat::U128(try_into!(u128, v)),
959 Dat::U32(v) => d = Dat::U128(try_into!(u128, v)),
960 Dat::U64(v) => d = Dat::U128(try_into!(u128, v)),
961 _ => (),
962 },
963 Kind::F64 => match d {
964 Dat::U8(v) => d = Dat::F64(Float64(v as f64)),
965 Dat::U16(v) => d = Dat::F64(Float64(v as f64)),
966 Dat::U32(v) => d = Dat::F64(Float64(v as f64)),
967 Dat::U64(v) => d = Dat::F64(Float64(v as f64)),
968 Dat::I8(v) => d = Dat::F64(Float64(v as f64)),
969 Dat::I16(v) => d = Dat::F64(Float64(v as f64)),
970 Dat::I32(v) => d = Dat::F64(Float64(v as f64)),
971 Dat::I64(v) => d = Dat::F64(Float64(v as f64)),
972 Dat::F32(v) => d = Dat::F64(Float64(v.0 as f64)),
973 Dat::Adec(v) => {
974 // Convert BigDecimal to f64.
975 match v.to_f64() {
976 Some(f) => d = Dat::F64(Float64(f)),
977 None => return Err(err!(
978 "Cannot convert BigDecimal '{}' to f64: value out of range", v;
979 Input, Invalid, Conversion)),
980 }
981 },
982 _ => (),
983 },
984 _ => (),
985 }
986 if *kind == d.kind() || *kind == Kind::Unknown {
987 return Ok(d);
988 }
989 match res!(Self::coerce_to_expected_kind(kind, &d)) {
990 Some(converted) => Ok(converted),
991 None => Err(err!(
992 "The word '{}' at position {}, <{}> for {}, must be a {} but reads as a {}.",
993 word, pos, val.label(), owner, kind, d.kind();
994 Input, Invalid)),
995 }
996 }
997
998 /// Interprets a sequence of words as a message of the syntax.
999 pub fn rx_words<I: IntoIterator<Item=String>>(
1000 &self,
1001 seq: I,
1002 similarity_threshold: Option<f64>,
1003 src: Source,
1004 )
1005 -> Outcome<Self>
1006 {
1007 let syntax = self.syntax();
1008 let sname = syntax.config().name.clone();
1009 let argv = src == Source::Argv;
1010 let one_cmd = syntax.config().one_cmd;
1011 let mut msgrx = Msg::new(self.syntaxref());
1012 let mut active_cmd: Option<&Cmd> = None;
1013 let mut active_arg: Option<&Arg> = None;
1014 let mut msg_slots = Slots::new(&syntax.config().vals);
1015 let mut cmd_slots = Slots::new(&[]);
1016 let mut arg_slots = Slots::new(&[]);
1017 let mut collecting = if syntax.config().vals.is_empty() {
1018 Collecting::None
1019 } else {
1020 Collecting::Message
1021 };
1022 let mut rargs: Vec<&str> = syntax.config().rargs.iter().map(|s| s.as_str()).collect();
1023 let mut in_rest = false;
1024 let mut opts_done = false; // past a "--" that ends the options
1025
1026 for (i, word) in seq.into_iter().enumerate() {
1027 let pos = i + 1;
1028
1029 // Everything after "--" is the command's rest, whatever it looks like.
1030 if in_rest {
1031 if let Some(cmd) = active_cmd {
1032 if let Some(rest) = &cmd.config().rest {
1033 let d = res!(Self::decode_word(
1034 &word, rest, src, pos, &fmt!("the command '{}'", cmd.config().name)));
1035 if let Some(msgcmd) = msgrx.cmds.get_mut(&cmd.config().name) {
1036 msgcmd.rest.get_or_insert_with(Vec::new).push(d);
1037 }
1038 }
1039 }
1040 continue;
1041 }
1042
1043 // An option still taking values, whose next word the VAL block decides.
1044 let opt_open = matches!(collecting, Collecting::MessageArg | Collecting::CommandArg)
1045 && arg_slots.current().is_some();
1046
1047 if argv && !opt_open {
1048 if let Some(cmd) = active_cmd {
1049 let owner = fmt!("the command '{}'", cmd.config().name);
1050 match cmd_slots.current() {
1051 // After a "--" that ends the options, and once a repeating verbatim
1052 // value is being filled, every word is a value as it stands.
1053 Some(val) if opts_done
1054 || (val.verbatim && val.arity.repeats() && cmd_slots.begun()) =>
1055 {
1056 let d = res!(Self::decode_word(&word, val, src, pos, &owner));
1057 collecting = Collecting::Command;
1058 active_arg = None;
1059 res!(Self::push_val(&mut msgrx, &collecting, active_cmd, None, d));
1060 cmd_slots.accept();
1061 continue;
1062 },
1063 None if opts_done => return Err(Self::excess(cmd, &word, pos)),
1064 _ => (),
1065 }
1066 }
1067 }
1068
1069 let word_key = Key::Str(word.clone());
1070 let is_rest_mark = word == "--"
1071 && active_cmd.map_or(false, |c| c.config().rest.is_some());
1072 let found_arg = Self::find_arg(syntax, &word, active_cmd, src);
1073 // With one command per message, a command's name after the command is a value.
1074 let is_cmd_word = syntax.cmds.contains_key(&word_key)
1075 && !(one_cmd && active_cmd.is_some());
1076 let is_help = argv && found_arg.is_none() && Self::is_help_flag(&word);
1077 let dash_dash = argv && word == "--";
1078 // A verbatim value takes a word shaped like an option that is not one of the
1079 // command's own, a help flag or a "--".
1080 let as_typed = argv && active_cmd.is_some() && !opt_open && !is_help && !dash_dash
1081 && cmd_slots.current().map_or(false, |v| v.verbatim);
1082 let dashy = argv && found_arg.is_none() && Self::looks_like_option(&word) && !as_typed;
1083
1084 // VAL block
1085 if collecting != Collecting::None {
1086 let for_arg = matches!(collecting, Collecting::MessageArg | Collecting::CommandArg);
1087 let slots = match collecting {
1088 Collecting::Message => &mut msg_slots,
1089 Collecting::Command => &mut cmd_slots,
1090 _ => &mut arg_slots,
1091 };
1092 match slots.current() {
1093 Some(val) => {
1094 // An option's value that is still owed takes a word that merely looks
1095 // like an option, such as '--reason -x', and "--" and a help flag too.
1096 let owed = for_arg && !slots.satisfied();
1097 // On the wire or at a prompt a command's name fills a value still
1098 // owed, as `chat help` always has; it starts the next command only
1099 // once the values are given.
1100 let marker = found_arg.is_some()
1101 || (is_cmd_word && (argv || slots.satisfied()))
1102 || is_rest_mark
1103 || ((dashy || dash_dash) && !owed);
1104 if !marker {
1105 let owner = Self::owner_desc(&collecting, active_cmd, active_arg);
1106 let d = res!(Self::decode_word(&word, val, src, pos, &owner));
1107 res!(Self::push_val(&mut msgrx, &collecting, active_cmd, active_arg, d));
1108 slots.accept();
1109 continue;
1110 }
1111 if slots.satisfied() || (one_cmd && collecting == Collecting::Command)
1112 || is_help || dash_dash
1113 {
1114 // The values may stop here, or, with one command per message, be
1115 // given after the options. The word is read below.
1116 if for_arg {
1117 active_arg = None;
1118 }
1119 collecting = Collecting::None;
1120 } else {
1121 let owner = Self::owner_desc(&collecting, active_cmd, active_arg);
1122 let wanted = slots.wanting().unwrap_or(val);
1123 return Err(match &wanted.missing {
1124 Some(sentence) => err!(
1125 "{} (found '{}' at position {}).", sentence, word, pos;
1126 Input, Missing),
1127 None => err!(
1128 "The syntax '{}' expects <{}> for {} at position {}, but \
1129 found '{}'.",
1130 sname, wanted.label(), owner, pos, word;
1131 Input, Missing),
1132 });
1133 }
1134 },
1135 None => {
1136 // Expected values exhausted.
1137 collecting = Collecting::None;
1138 active_arg = None;
1139 },
1140 }
1141 }
1142
1143 if is_help {
1144 // Asked where an option could stand, so the page is the answer, whatever the
1145 // rest of the line holds.
1146 msgrx.end = MsgEndState {
1147 cmd: active_cmd.map(|c| c.config().name.clone()),
1148 help: true,
1149 ..Default::default()
1150 };
1151 return Ok(msgrx);
1152 }
1153
1154 if is_rest_mark {
1155 in_rest = true;
1156 if let Some(cmd) = active_cmd {
1157 if let Some(msgcmd) = msgrx.cmds.get_mut(&cmd.config().name) {
1158 msgcmd.rest = Some(Vec::new());
1159 }
1160 }
1161 continue;
1162 }
1163
1164 // ARG block
1165 if let Some((arg, is_msg_arg)) = found_arg {
1166 let canon = arg.canonical_name();
1167 if is_msg_arg {
1168 if msgrx.args.contains_key(&canon) {
1169 return Err(err!(
1170 "The message argument '{}' at position {} in the syntax '{}' \
1171 has already been given.",
1172 word, pos, sname;
1173 Input, Invalid));
1174 }
1175 msgrx.args.insert(canon.clone(), Vec::new());
1176 collecting = Collecting::MessageArg;
1177 } else if let Some(cmd) = active_cmd {
1178 if let Some(cmdrx) = msgrx.get_cmd_mut(&cmd.config().name) {
1179 if cmdrx.has_arg(&canon) {
1180 return Err(err!(
1181 "The argument '{}' at position {} for command '{}' in the \
1182 syntax '{}' has already been given.",
1183 word, pos, cmd.config().name, sname;
1184 Input, Invalid));
1185 }
1186 cmdrx.args.insert(canon.clone(), Vec::new());
1187 }
1188 collecting = Collecting::CommandArg;
1189 }
1190 Self::revise_reqd_arg_list(&canon, &mut rargs);
1191 active_arg = Some(arg);
1192 arg_slots = Slots::new(&arg.config().vals);
1193 continue;
1194 }
1195
1196 if dash_dash {
1197 // The end of the options: every word after it is one of the command's values.
1198 if active_cmd.is_none() {
1199 return Err(err!(
1200 "The '--' at position {} ends the options, but no command has been \
1201 named.", pos;
1202 Input, Invalid));
1203 }
1204 opts_done = true;
1205 collecting = Collecting::Command;
1206 active_arg = None;
1207 continue;
1208 }
1209
1210 if dashy {
1211 let mut names = Vec::new();
1212 if let Some(cmd) = active_cmd {
1213 for arg in cmd.args_in_order() {
1214 names.append(&mut arg.hyphenated_names());
1215 }
1216 }
1217 for arg in syntax.args_in_order() {
1218 names.append(&mut arg.hyphenated_names());
1219 }
1220 let whose = match active_cmd {
1221 Some(cmd) => fmt!("the command '{}'", cmd.config().name),
1222 None => fmt!("'{}'", sname),
1223 };
1224 return Err(match similarity_threshold
1225 .and_then(|t| Self::closest(&word, &names, t))
1226 {
1227 Some(suggestion) => err!(
1228 "Did you mean '{}'? The option '{}' at position {} is not one \
1229 that {} takes.",
1230 suggestion, word, pos, whose;
1231 Input, Invalid, Suggestion),
1232 None => err!(
1233 "The option '{}' at position {} is not one that {} takes.",
1234 word, pos, whose;
1235 Input, Invalid),
1236 });
1237 }
1238
1239 if one_cmd {
1240 if let Some(cmd) = active_cmd {
1241 // Values may come after options, so a bare word fills the next one.
1242 if let Some(val) = cmd_slots.current() {
1243 let owner = fmt!("the command '{}'", cmd.config().name);
1244 let d = res!(Self::decode_word(&word, val, src, pos, &owner));
1245 collecting = Collecting::Command;
1246 res!(Self::push_val(&mut msgrx, &collecting, active_cmd, None, d));
1247 cmd_slots.accept();
1248 continue;
1249 }
1250 return Err(Self::excess(cmd, &word, pos));
1251 }
1252 }
1253
1254 // CMD block
1255 let cmd = res!(self.is_word_a_cmd(&word_key, pos, similarity_threshold, argv));
1256 msgrx.cmds.insert(
1257 cmd.config().name.clone(),
1258 res!(MsgCmd::new(self.syntaxref(), cmd.config().name.clone())),
1259 );
1260 active_cmd = Some(cmd);
1261 active_arg = None;
1262 collecting = Collecting::Command;
1263 cmd_slots = Slots::new(&cmd.config().vals);
1264 res!(self.check_required_txt_args(rargs, &None));
1265 // Reset rargs for the command.
1266 rargs = cmd.config().rargs.iter().map(|s| s.as_str()).collect();
1267 }
1268
1269 if argv {
1270 // From a command line nothing more is coming, so what is owed is missing.
1271 let mut owed: Vec<(&Val, String)> = Vec::new();
1272 if let Some(arg) = active_arg {
1273 if let Some(val) = arg_slots.wanting() {
1274 owed.push((val, fmt!("the option '{}'", arg.long_name())));
1275 }
1276 }
1277 if let Some(val) = msg_slots.wanting() {
1278 owed.push((val, fmt!("'{}'", sname)));
1279 }
1280 if let Some(cmd) = active_cmd {
1281 if let Some(val) = cmd_slots.wanting() {
1282 owed.push((val, fmt!("the command '{}'", cmd.config().name)));
1283 }
1284 if let (Some(rest), Some(msgcmd)) =
1285 (&cmd.config().rest, msgrx.cmds.get(&cmd.config().name))
1286 {
1287 if let Some(words) = &msgcmd.rest {
1288 if words.is_empty() && !rest.arity.may_be_empty() {
1289 owed.push((rest, fmt!("the command '{}' after '--'", cmd.config().name)));
1290 }
1291 }
1292 }
1293 }
1294 if let Some((val, owner)) = owed.first() {
1295 return Err(match &val.missing {
1296 Some(sentence) => err!("{}", sentence; Input, Missing),
1297 None => err!("{} needs <{}>.", Self::capitalise(owner), val.label();
1298 Input, Missing),
1299 });
1300 }
1301 }
1302
1303 res!(self.check_required_txt_args(rargs, &active_cmd));
1304
1305 msgrx.end = MsgEndState {
1306 vals: match collecting {
1307 Collecting::Message => msg_slots.outstanding(),
1308 Collecting::Command => cmd_slots.outstanding(),
1309 Collecting::MessageArg |
1310 Collecting::CommandArg => arg_slots.outstanding(),
1311 Collecting::None => Vec::new(),
1312 },
1313 arg: active_arg.map(|a| a.canonical_name()),
1314 cmd: active_cmd.map(|c| c.config().name.clone()),
1315 help: false,
1316 };
1317 msgrx.enc = Encoding::UTF8;
1318
1319 Ok(msgrx)
1320 }
1321
1322 fn capitalise(s: &str) -> String {
1323 let mut chars = s.chars();
1324 match chars.next() {
1325 Some(c) => c.to_uppercase().chain(chars).collect(),
1326 None => String::new(),
1327 }
1328 }
1329
1330 // BINARY IO
1331 //
1332 /// Decodes and validates a syntax `Msg`. A message is prepended with the encoding type,
1333 /// currently either a UTF-8 string or a custom binary format.
1334 /// ````ignore
1335 /// +--- Encoding variant (u8)
1336 /// | +--- encoded message, either UTF-8 or binary
1337 /// | _______|______
1338 /// v / \
1339 /// +---+---+---+---+---+
1340 /// | | | ... | |
1341 /// +---+---+---+---+---+
1342 /// ````
1343 /// # Binary message format
1344 /// ````ignore
1345 /// +-- number of message values (Dat::C64)
1346 /// | +-- number of message arguments (C64)
1347 /// | message values | +-- index of first msg arg (U16)
1348 /// | (Dats) | | +-- number of msg arg vals for i1
1349 /// | ______|______ | | |
1350 /// v / \ v v v
1351 /// +---+---+---+---+---+---+---+---+---+---+---+---+---+---+--
1352 /// | v | v msg vals | a |i1 | n | n arg vals |i2 | n | ..
1353 /// +---+---+---+---+---+---+---+---+---+---+---+---+---+---+--
1354 ///
1355 /// number of commands --+ +-- index of first cmd
1356 /// | |
1357 /// v v
1358 /// -+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+--
1359 /// n arg vals |ia | n | n arg vals | c |i1 | v | v cmd vals
1360 /// -+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+--
1361 ///
1362 /// +-- number of cmd args for cmd i1
1363 /// | +-- index of first cmd arg for cmd i1
1364 /// | | +-- number of cmd arg vals or cmd i1
1365 /// | | |
1366 /// v v v
1367 /// -+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+--
1368 /// | a |j1 | n | n arg vals |j2 | n | n arg vals |ja | n |
1369 /// -+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+--
1370 ///
1371 ///
1372 ///
1373 /// -+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+--
1374 /// n arg vals |i2 | v | v cmd vals | a |j1 | n | n cmd vals ...
1375 /// -+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+--
1376 ///
1377 /// .. and so on for all remaining commands
1378 /// ````
1379 ///
1380 pub fn from_bytes(
1381 &self,
1382 buf: &[u8],
1383 similarity_threshold: Option<f64>,
1384 )
1385 -> Outcome<Self>
1386 {
1387 if buf.len() <= 1 {
1388 return Err(err!("No bytes to decode."; Input, Missing));
1389 }
1390 let msgrx = match Encoding::from(buf[0]) {
1391 Encoding::Binary => res!(self.from_bytes_binary(&buf[1..])),
1392 Encoding::UTF8 => {
1393 let msg_str = res!(std::str::from_utf8(&buf[1..]), Decode, UTF8);
1394 res!(self.from_str(msg_str, similarity_threshold))
1395 },
1396 _ => return Err(err!("Unknown message encoding."; Unknown, Encode)),
1397 };
1398 Ok(msgrx)
1399 }
1400
1401 pub fn from_bytes_binary(
1402 &self,
1403 buf: &[u8],
1404 )
1405 -> Outcome<Self>
1406 {
1407 let mut msgrx = Msg::new(self.syntaxref());
1408 let mut n: usize = 0;
1409 let mut last_arg: Option<String>;
1410 let mut last_cmd: Option<String> = None;
1411 let mut rargs: Vec<&str> = Vec::new();
1412 for arg_name in &self.syntax().config().rargs {
1413 rargs.push(arg_name);
1414 }
1415 // Message values
1416 let (dat, nb) = res!(Dat::from_bytes(&buf));
1417 debug!("Daticle from bytes: {:?}", dat);
1418 n += nb;
1419 let vals = try_extract_dat!(dat, List);
1420 res!(self.check_expected_vals(
1421 &self.syntax().config().vals,
1422 &vals,
1423 &None,
1424 ));
1425 msgrx.vals = vals;
1426 // Message arguments
1427 let (args_map, nb, last_arg2) = res!(self.rx_binary_args(
1428 Collecting::MessageArg,
1429 &self.syntax().config().rargs,
1430 &self.syntax().args,
1431 &buf[n..],
1432 &None,
1433 ));
1434 n += nb;
1435 res!(self.check_required_bin_args(
1436 &self.syntax().config().rargs,
1437 &args_map.iter().map(|(k, _)| k.clone()).collect::<Vec<String>>(),
1438 &None,
1439 ));
1440 msgrx.args = args_map;
1441 last_arg = last_arg2;
1442 // Commands
1443 if let (Dat::C64(c), nb) = res!(Dat::from_bytes(&buf[n..])) {
1444 n += nb;
1445 let ncmd = c as usize;
1446 for i in 0..ncmd {
1447 if let (Dat::U16(cmd_id), nb) = res!(Dat::from_bytes(&buf[n..])) {
1448 n += nb;
1449 if let Some(cmd) = self.syntax().cmds.get_recursive(&Key::Id(cmd_id)) {
1450 let mut msgcmd = res!(MsgCmd::new(
1451 self.syntaxref(),
1452 cmd.config().name.clone(),
1453 ));
1454 // Command values
1455 if let (Dat::List(vals), nb) = res!(Dat::from_bytes(&buf[n..])) {
1456 n += nb;
1457 res!(self.check_expected_vals(
1458 &cmd.config().vals,
1459 &vals,
1460 &Some(&cmd),
1461 ));
1462 msgcmd.vals = vals;
1463 }
1464 // Command arguments
1465 let (map, nb, last_arg2) = res!(self.rx_binary_args(
1466 Collecting::CommandArg,
1467 &cmd.config().rargs,
1468 &cmd.args,
1469 &buf[n..],
1470 &Some(&cmd),
1471 ));
1472 n += nb;
1473 msgcmd.args = map;
1474 last_arg = last_arg2;
1475 if cmd.config().rest.is_some() {
1476 let (dat, nb) = res!(Dat::from_bytes(&buf[n..]));
1477 n += nb;
1478 if let Dat::Bool(true) = dat {
1479 let (dat, nb) = res!(Dat::from_bytes(&buf[n..]));
1480 n += nb;
1481 msgcmd.rest = Some(try_extract_dat!(dat, List));
1482 }
1483 }
1484 msgrx.cmds.insert(cmd.config().name.clone(), msgcmd);
1485 if i == ncmd - 1 {
1486 last_cmd = Some(cmd.config().name.clone());
1487 }
1488 } else {
1489 return Err(err!(
1490 "The binary message refers to a command with \
1491 id {} but no such command exists in the '{}' syntax.",
1492 cmd_id, self.syntax().config().name;
1493 Input, Invalid));
1494 }
1495 }
1496 }
1497 }
1498
1499 msgrx.end = MsgEndState {
1500 arg: last_arg,
1501 cmd: last_cmd,
1502 ..Default::default()
1503 };
1504 msgrx.enc = Encoding::Binary;
1505
1506 Ok(msgrx)
1507 }
1508
1509 fn rx_binary_args(
1510 &self,
1511 coll: Collecting,
1512 rargs: &Vec<String>,
1513 args: &BTreeMap<Key, Recursive<Key, Arg>>,
1514 buf: &[u8],
1515 active_cmd: &Option<&Cmd>,
1516 )
1517 -> Outcome<(
1518 BTreeMap<String, Vec<Dat>>,
1519 usize,
1520 Option<String>,
1521 )>
1522 {
1523 let mut n: usize = 0;
1524 let mut last_arg: Option<String> = None;
1525 let (dat, nb) = res!(Dat::from_bytes(&buf));
1526 n += nb;
1527 let a = try_extract_dat!(dat, C64);
1528 let narg = a as usize;
1529 if narg < rargs.len() {
1530 return Err(err!(
1531 "The syntax '{}' requires {} {} argument(s), found {}.",
1532 self.syntax().config().name,
1533 rargs.len(),
1534 Self::msg_or_cmd_string(active_cmd),
1535 narg;
1536 Input, Missing));
1537 }
1538 let mut map = BTreeMap::new();
1539 for i in 0..narg {
1540 let (dat, nb) = res!(Dat::from_bytes(&buf[n..]));
1541 n += nb;
1542 let arg_id = try_extract_dat!(dat, U16);
1543 if let Some(arg) = args.get_recursive(&Key::Id(arg_id)) {
1544
1545 // Collect the argument values.
1546 let (dat, nb) = res!(Dat::from_bytes(&buf[n..]));
1547 n += nb;
1548 let vals = try_extract_dat!(dat, List);
1549 res!(self.check_expected_vals(
1550 &arg.config().vals,
1551 &vals,
1552 active_cmd,
1553 ));
1554
1555 // Insert the values into the map.
1556 map.insert(arg.canonical_name(), vals);
1557
1558 // Remember the last argument for return to the caller.
1559 if i == narg - 1 {
1560 last_arg = Some(arg.canonical_name());
1561 }
1562 } else {
1563 return Err(err!(
1564 "The binary message refers to a {:?} with \
1565 id {} but no such argument exists in the syntax '{}'.",
1566 coll, arg_id, self.syntax().config().name;
1567 Input, Invalid));
1568 }
1569 }
1570 res!(self.check_required_bin_args(
1571 rargs,
1572 &map.iter().map(|(k, _)| k.clone()).collect::<Vec<String>>(),
1573 active_cmd,
1574 ));
1575 Ok((map, n, last_arg))
1576 }
1577
1578 /// Unlike text messages, binary messages allow us to know up-front what is coming, so we can
1579 /// check required arguments differently.
1580 fn check_required_bin_args(
1581 &self,
1582 required_args: &Vec<String>,
1583 actual_args: &Vec<String>,
1584 active_cmd: &Option<&Cmd>,
1585 )
1586 -> Outcome<()>
1587 {
1588 let mut required_args: BTreeSet<String> =
1589 required_args.clone().into_iter().collect();
1590 for arg in actual_args {
1591 required_args.remove(arg);
1592 }
1593 if required_args.len() > 0 {
1594 return Err(err!(
1595 "The syntax '{}' expects {} arguments '{:?}' which \
1596 were not found.",
1597 self.syntax().config().name,
1598 Self::msg_or_cmd_string(active_cmd),
1599 required_args;
1600 Input, Missing));
1601 }
1602 Ok(())
1603 }
1604
1605 fn check_expected_vals(
1606 &self,
1607 expected_vals: &Vec<Val>,
1608 actual_vals: &Vec<Dat>,
1609 active_cmd: &Option<&Cmd>,
1610 )
1611 -> Outcome<()>
1612 {
1613 if !Val::count_fits(expected_vals, actual_vals.len()) {
1614 return Err(err!(
1615 "The syntax '{}' expects {} {} value(s), found {}.",
1616 self.syntax().config().name,
1617 expected_vals.len(),
1618 Self::msg_or_cmd_string(active_cmd),
1619 actual_vals.len();
1620 Input, Missing));
1621 }
1622 for (i, actual) in actual_vals.iter().enumerate() {
1623 if let Some(expected) = Val::slot(expected_vals, i) {
1624 if expected.kind != Kind::Unknown && expected.kind != actual.kind() {
1625 return Err(err!(
1626 "The syntax '{}' expects {} value {} to be a '{:?}', \
1627 {:?} was found.",
1628 self.syntax().config().name,
1629 Self::msg_or_cmd_string(active_cmd),
1630 actual,
1631 expected.kind,
1632 actual.kind();
1633 Input, Missing));
1634 }
1635 }
1636 }
1637 Ok(())
1638 }
1639
1640 fn msg_or_cmd_string(active_cmd: &Option<&Cmd>) -> String {
1641 match active_cmd {
1642 Some(cmd) => fmt!("'{}'", cmd.config().name),
1643 None => fmt!("message"),
1644 }
1645 }
1646
1647 /// Coerce a Dat value to an expected Kind.
1648 ///
1649 /// This handles conversions from default JDAT string parsing to specific typed variants.
1650 /// For example, "(2,6)" is parsed as Dat::Tup2(Box<[Dat; 2]>) but may need to become
1651 /// Dat::Tup2u8([u8; 2]) based on the syntax specification.
1652 fn coerce_to_expected_kind(expected: &Kind, actual: &Dat) -> Outcome<Option<Dat>> {
1653 match (expected, actual) {
1654 // Tup2 conversions.
1655 (Kind::Tup2u8, Dat::Tup2(boxed)) => {
1656 if let (Some(a), Some(b)) = (boxed[0].get_u8(), boxed[1].get_u8()) {
1657 Ok(Some(Dat::Tup2u8([a, b])))
1658 } else {
1659 Ok(None)
1660 }
1661 }
1662 (Kind::Tup2u16, Dat::Tup2(boxed)) => {
1663 if let (Some(a), Some(b)) = (boxed[0].get_u16(), boxed[1].get_u16()) {
1664 Ok(Some(Dat::Tup2u16([a, b])))
1665 } else {
1666 Ok(None)
1667 }
1668 }
1669 (Kind::Tup2u32, Dat::Tup2(boxed)) => {
1670 if let (Some(a), Some(b)) = (boxed[0].get_u32(), boxed[1].get_u32()) {
1671 Ok(Some(Dat::Tup2u32([a, b])))
1672 } else {
1673 Ok(None)
1674 }
1675 }
1676 (Kind::Tup2u64, Dat::Tup2(boxed)) => {
1677 if let (Some(a), Some(b)) = (boxed[0].get_u64(), boxed[1].get_u64()) {
1678 Ok(Some(Dat::Tup2u64([a, b])))
1679 } else {
1680 Ok(None)
1681 }
1682 }
1683 (Kind::Tup2i8, Dat::Tup2(boxed)) => {
1684 if let (Some(a), Some(b)) = (boxed[0].get_i8(), boxed[1].get_i8()) {
1685 Ok(Some(Dat::Tup2i8([a, b])))
1686 } else {
1687 Ok(None)
1688 }
1689 }
1690 (Kind::Tup2i16, Dat::Tup2(boxed)) => {
1691 if let (Some(a), Some(b)) = (boxed[0].get_i16(), boxed[1].get_i16()) {
1692 Ok(Some(Dat::Tup2i16([a, b])))
1693 } else {
1694 Ok(None)
1695 }
1696 }
1697 (Kind::Tup2i32, Dat::Tup2(boxed)) => {
1698 if let (Some(a), Some(b)) = (boxed[0].get_i32(), boxed[1].get_i32()) {
1699 Ok(Some(Dat::Tup2i32([a, b])))
1700 } else {
1701 Ok(None)
1702 }
1703 }
1704 (Kind::Tup2i64, Dat::Tup2(boxed)) => {
1705 if let (Some(a), Some(b)) = (boxed[0].get_i64(), boxed[1].get_i64()) {
1706 Ok(Some(Dat::Tup2i64([a, b])))
1707 } else {
1708 Ok(None)
1709 }
1710 }
1711
1712 // Tup3 conversions.
1713 (Kind::Tup3u8, Dat::Tup3(boxed)) => {
1714 if let (Some(a), Some(b), Some(c)) =
1715 (boxed[0].get_u8(), boxed[1].get_u8(), boxed[2].get_u8()) {
1716 Ok(Some(Dat::Tup3u8([a, b, c])))
1717 } else {
1718 Ok(None)
1719 }
1720 }
1721 (Kind::Tup3u16, Dat::Tup3(boxed)) => {
1722 if let (Some(a), Some(b), Some(c)) =
1723 (boxed[0].get_u16(), boxed[1].get_u16(), boxed[2].get_u16()) {
1724 Ok(Some(Dat::Tup3u16([a, b, c])))
1725 } else {
1726 Ok(None)
1727 }
1728 }
1729 (Kind::Tup3u32, Dat::Tup3(boxed)) => {
1730 if let (Some(a), Some(b), Some(c)) =
1731 (boxed[0].get_u32(), boxed[1].get_u32(), boxed[2].get_u32()) {
1732 Ok(Some(Dat::Tup3u32([a, b, c])))
1733 } else {
1734 Ok(None)
1735 }
1736 }
1737 (Kind::Tup3u64, Dat::Tup3(boxed)) => {
1738 if let (Some(a), Some(b), Some(c)) =
1739 (boxed[0].get_u64(), boxed[1].get_u64(), boxed[2].get_u64()) {
1740 Ok(Some(Dat::Tup3u64([a, b, c])))
1741 } else {
1742 Ok(None)
1743 }
1744 }
1745 (Kind::Tup3i8, Dat::Tup3(boxed)) => {
1746 if let (Some(a), Some(b), Some(c)) =
1747 (boxed[0].get_i8(), boxed[1].get_i8(), boxed[2].get_i8()) {
1748 Ok(Some(Dat::Tup3i8([a, b, c])))
1749 } else {
1750 Ok(None)
1751 }
1752 }
1753 (Kind::Tup3i16, Dat::Tup3(boxed)) => {
1754 if let (Some(a), Some(b), Some(c)) =
1755 (boxed[0].get_i16(), boxed[1].get_i16(), boxed[2].get_i16()) {
1756 Ok(Some(Dat::Tup3i16([a, b, c])))
1757 } else {
1758 Ok(None)
1759 }
1760 }
1761 (Kind::Tup3i32, Dat::Tup3(boxed)) => {
1762 if let (Some(a), Some(b), Some(c)) =
1763 (boxed[0].get_i32(), boxed[1].get_i32(), boxed[2].get_i32()) {
1764 Ok(Some(Dat::Tup3i32([a, b, c])))
1765 } else {
1766 Ok(None)
1767 }
1768 }
1769 (Kind::Tup3i64, Dat::Tup3(boxed)) => {
1770 if let (Some(a), Some(b), Some(c)) =
1771 (boxed[0].get_i64(), boxed[1].get_i64(), boxed[2].get_i64()) {
1772 Ok(Some(Dat::Tup3i64([a, b, c])))
1773 } else {
1774 Ok(None)
1775 }
1776 }
1777
1778 // Tup4 conversions.
1779 (Kind::Tup4u8, Dat::Tup4(boxed)) => {
1780 match Self::extract_u8_array::<4>(boxed) {
1781 Some(arr) => Ok(Some(Dat::Tup4u8(arr))),
1782 None => Ok(None)
1783 }
1784 }
1785 (Kind::Tup4u16, Dat::Tup4(boxed)) => {
1786 match Self::extract_u16_array::<4>(boxed) {
1787 Some(arr) => Ok(Some(Dat::Tup4u16(arr))),
1788 None => Ok(None)
1789 }
1790 }
1791 (Kind::Tup4u32, Dat::Tup4(boxed)) => {
1792 match Self::extract_u32_array::<4>(boxed) {
1793 Some(arr) => Ok(Some(Dat::Tup4u32(arr))),
1794 None => Ok(None)
1795 }
1796 }
1797 (Kind::Tup4u64, Dat::Tup4(boxed)) => {
1798 match Self::extract_u64_array::<4>(boxed) {
1799 Some(arr) => Ok(Some(Dat::Tup4u64(arr))),
1800 None => Ok(None)
1801 }
1802 }
1803 (Kind::Tup4i8, Dat::Tup4(boxed)) => {
1804 match Self::extract_i8_array::<4>(boxed) {
1805 Some(arr) => Ok(Some(Dat::Tup4i8(arr))),
1806 None => Ok(None)
1807 }
1808 }
1809 (Kind::Tup4i16, Dat::Tup4(boxed)) => {
1810 match Self::extract_i16_array::<4>(boxed) {
1811 Some(arr) => Ok(Some(Dat::Tup4i16(arr))),
1812 None => Ok(None)
1813 }
1814 }
1815 (Kind::Tup4i32, Dat::Tup4(boxed)) => {
1816 match Self::extract_i32_array::<4>(boxed) {
1817 Some(arr) => Ok(Some(Dat::Tup4i32(arr))),
1818 None => Ok(None)
1819 }
1820 }
1821 (Kind::Tup4i64, Dat::Tup4(boxed)) => {
1822 match Self::extract_i64_array::<4>(boxed) {
1823 Some(arr) => Ok(Some(Dat::Tup4i64(arr))),
1824 None => Ok(None)
1825 }
1826 }
1827
1828 // Tup5 conversions.
1829 (Kind::Tup5u8, Dat::Tup5(boxed)) => {
1830 match Self::extract_u8_array::<5>(boxed) {
1831 Some(arr) => Ok(Some(Dat::Tup5u8(arr))),
1832 None => Ok(None)
1833 }
1834 }
1835 (Kind::Tup5u16, Dat::Tup5(boxed)) => {
1836 match Self::extract_u16_array::<5>(boxed) {
1837 Some(arr) => Ok(Some(Dat::Tup5u16(arr))),
1838 None => Ok(None)
1839 }
1840 }
1841 (Kind::Tup5u32, Dat::Tup5(boxed)) => {
1842 match Self::extract_u32_array::<5>(boxed) {
1843 Some(arr) => Ok(Some(Dat::Tup5u32(arr))),
1844 None => Ok(None)
1845 }
1846 }
1847 (Kind::Tup5u64, Dat::Tup5(boxed)) => {
1848 match Self::extract_u64_array::<5>(boxed) {
1849 Some(arr) => Ok(Some(Dat::Tup5u64(arr))),
1850 None => Ok(None)
1851 }
1852 }
1853 (Kind::Tup5i8, Dat::Tup5(boxed)) => {
1854 match Self::extract_i8_array::<5>(boxed) {
1855 Some(arr) => Ok(Some(Dat::Tup5i8(arr))),
1856 None => Ok(None)
1857 }
1858 }
1859 (Kind::Tup5i16, Dat::Tup5(boxed)) => {
1860 match Self::extract_i16_array::<5>(boxed) {
1861 Some(arr) => Ok(Some(Dat::Tup5i16(arr))),
1862 None => Ok(None)
1863 }
1864 }
1865 (Kind::Tup5i32, Dat::Tup5(boxed)) => {
1866 match Self::extract_i32_array::<5>(boxed) {
1867 Some(arr) => Ok(Some(Dat::Tup5i32(arr))),
1868 None => Ok(None)
1869 }
1870 }
1871 (Kind::Tup5i64, Dat::Tup5(boxed)) => {
1872 match Self::extract_i64_array::<5>(boxed) {
1873 Some(arr) => Ok(Some(Dat::Tup5i64(arr))),
1874 None => Ok(None)
1875 }
1876 }
1877
1878 // Tup6 conversions.
1879 (Kind::Tup6u8, Dat::Tup6(boxed)) => {
1880 match Self::extract_u8_array::<6>(boxed) {
1881 Some(arr) => Ok(Some(Dat::Tup6u8(arr))),
1882 None => Ok(None)
1883 }
1884 }
1885 (Kind::Tup6u16, Dat::Tup6(boxed)) => {
1886 match Self::extract_u16_array::<6>(boxed) {
1887 Some(arr) => Ok(Some(Dat::Tup6u16(arr))),
1888 None => Ok(None)
1889 }
1890 }
1891 (Kind::Tup6u32, Dat::Tup6(boxed)) => {
1892 match Self::extract_u32_array::<6>(boxed) {
1893 Some(arr) => Ok(Some(Dat::Tup6u32(arr))),
1894 None => Ok(None)
1895 }
1896 }
1897 (Kind::Tup6u64, Dat::Tup6(boxed)) => {
1898 match Self::extract_u64_array::<6>(boxed) {
1899 Some(arr) => Ok(Some(Dat::Tup6u64(arr))),
1900 None => Ok(None)
1901 }
1902 }
1903 (Kind::Tup6i8, Dat::Tup6(boxed)) => {
1904 match Self::extract_i8_array::<6>(boxed) {
1905 Some(arr) => Ok(Some(Dat::Tup6i8(arr))),
1906 None => Ok(None)
1907 }
1908 }
1909 (Kind::Tup6i16, Dat::Tup6(boxed)) => {
1910 match Self::extract_i16_array::<6>(boxed) {
1911 Some(arr) => Ok(Some(Dat::Tup6i16(arr))),
1912 None => Ok(None)
1913 }
1914 }
1915 (Kind::Tup6i32, Dat::Tup6(boxed)) => {
1916 match Self::extract_i32_array::<6>(boxed) {
1917 Some(arr) => Ok(Some(Dat::Tup6i32(arr))),
1918 None => Ok(None)
1919 }
1920 }
1921 (Kind::Tup6i64, Dat::Tup6(boxed)) => {
1922 match Self::extract_i64_array::<6>(boxed) {
1923 Some(arr) => Ok(Some(Dat::Tup6i64(arr))),
1924 None => Ok(None)
1925 }
1926 }
1927
1928 // Tup7 conversions.
1929 (Kind::Tup7u8, Dat::Tup7(boxed)) => {
1930 match Self::extract_u8_array::<7>(boxed) {
1931 Some(arr) => Ok(Some(Dat::Tup7u8(arr))),
1932 None => Ok(None)
1933 }
1934 }
1935 (Kind::Tup7u16, Dat::Tup7(boxed)) => {
1936 match Self::extract_u16_array::<7>(boxed) {
1937 Some(arr) => Ok(Some(Dat::Tup7u16(arr))),
1938 None => Ok(None)
1939 }
1940 }
1941 (Kind::Tup7u32, Dat::Tup7(boxed)) => {
1942 match Self::extract_u32_array::<7>(boxed) {
1943 Some(arr) => Ok(Some(Dat::Tup7u32(arr))),
1944 None => Ok(None)
1945 }
1946 }
1947 (Kind::Tup7u64, Dat::Tup7(boxed)) => {
1948 match Self::extract_u64_array::<7>(boxed) {
1949 Some(arr) => Ok(Some(Dat::Tup7u64(arr))),
1950 None => Ok(None)
1951 }
1952 }
1953 (Kind::Tup7i8, Dat::Tup7(boxed)) => {
1954 match Self::extract_i8_array::<7>(boxed) {
1955 Some(arr) => Ok(Some(Dat::Tup7i8(arr))),
1956 None => Ok(None)
1957 }
1958 }
1959 (Kind::Tup7i16, Dat::Tup7(boxed)) => {
1960 match Self::extract_i16_array::<7>(boxed) {
1961 Some(arr) => Ok(Some(Dat::Tup7i16(arr))),
1962 None => Ok(None)
1963 }
1964 }
1965 (Kind::Tup7i32, Dat::Tup7(boxed)) => {
1966 match Self::extract_i32_array::<7>(boxed) {
1967 Some(arr) => Ok(Some(Dat::Tup7i32(arr))),
1968 None => Ok(None)
1969 }
1970 }
1971 (Kind::Tup7i64, Dat::Tup7(boxed)) => {
1972 match Self::extract_i64_array::<7>(boxed) {
1973 Some(arr) => Ok(Some(Dat::Tup7i64(arr))),
1974 None => Ok(None)
1975 }
1976 }
1977
1978 // Tup8 conversions.
1979 (Kind::Tup8u8, Dat::Tup8(boxed)) => {
1980 match Self::extract_u8_array::<8>(boxed) {
1981 Some(arr) => Ok(Some(Dat::Tup8u8(arr))),
1982 None => Ok(None)
1983 }
1984 }
1985 (Kind::Tup8u16, Dat::Tup8(boxed)) => {
1986 match Self::extract_u16_array::<8>(boxed) {
1987 Some(arr) => Ok(Some(Dat::Tup8u16(arr))),
1988 None => Ok(None)
1989 }
1990 }
1991 (Kind::Tup8u32, Dat::Tup8(boxed)) => {
1992 match Self::extract_u32_array::<8>(boxed) {
1993 Some(arr) => Ok(Some(Dat::Tup8u32(arr))),
1994 None => Ok(None)
1995 }
1996 }
1997 (Kind::Tup8u64, Dat::Tup8(boxed)) => {
1998 match Self::extract_u64_array::<8>(boxed) {
1999 Some(arr) => Ok(Some(Dat::Tup8u64(arr))),
2000 None => Ok(None)
2001 }
2002 }
2003 (Kind::Tup8i8, Dat::Tup8(boxed)) => {
2004 match Self::extract_i8_array::<8>(boxed) {
2005 Some(arr) => Ok(Some(Dat::Tup8i8(arr))),
2006 None => Ok(None)
2007 }
2008 }
2009 (Kind::Tup8i16, Dat::Tup8(boxed)) => {
2010 match Self::extract_i16_array::<8>(boxed) {
2011 Some(arr) => Ok(Some(Dat::Tup8i16(arr))),
2012 None => Ok(None)
2013 }
2014 }
2015 (Kind::Tup8i32, Dat::Tup8(boxed)) => {
2016 match Self::extract_i32_array::<8>(boxed) {
2017 Some(arr) => Ok(Some(Dat::Tup8i32(arr))),
2018 None => Ok(None)
2019 }
2020 }
2021 (Kind::Tup8i64, Dat::Tup8(boxed)) => {
2022 match Self::extract_i64_array::<8>(boxed) {
2023 Some(arr) => Ok(Some(Dat::Tup8i64(arr))),
2024 None => Ok(None)
2025 }
2026 }
2027
2028 // Tup9 conversions.
2029 (Kind::Tup9u8, Dat::Tup9(boxed)) => {
2030 match Self::extract_u8_array::<9>(boxed) {
2031 Some(arr) => Ok(Some(Dat::Tup9u8(arr))),
2032 None => Ok(None)
2033 }
2034 }
2035 (Kind::Tup9u16, Dat::Tup9(boxed)) => {
2036 match Self::extract_u16_array::<9>(boxed) {
2037 Some(arr) => Ok(Some(Dat::Tup9u16(arr))),
2038 None => Ok(None)
2039 }
2040 }
2041 (Kind::Tup9u32, Dat::Tup9(boxed)) => {
2042 match Self::extract_u32_array::<9>(boxed) {
2043 Some(arr) => Ok(Some(Dat::Tup9u32(arr))),
2044 None => Ok(None)
2045 }
2046 }
2047 (Kind::Tup9u64, Dat::Tup9(boxed)) => {
2048 match Self::extract_u64_array::<9>(boxed) {
2049 Some(arr) => Ok(Some(Dat::Tup9u64(arr))),
2050 None => Ok(None)
2051 }
2052 }
2053 (Kind::Tup9i8, Dat::Tup9(boxed)) => {
2054 match Self::extract_i8_array::<9>(boxed) {
2055 Some(arr) => Ok(Some(Dat::Tup9i8(arr))),
2056 None => Ok(None)
2057 }
2058 }
2059 (Kind::Tup9i16, Dat::Tup9(boxed)) => {
2060 match Self::extract_i16_array::<9>(boxed) {
2061 Some(arr) => Ok(Some(Dat::Tup9i16(arr))),
2062 None => Ok(None)
2063 }
2064 }
2065 (Kind::Tup9i32, Dat::Tup9(boxed)) => {
2066 match Self::extract_i32_array::<9>(boxed) {
2067 Some(arr) => Ok(Some(Dat::Tup9i32(arr))),
2068 None => Ok(None)
2069 }
2070 }
2071 (Kind::Tup9i64, Dat::Tup9(boxed)) => {
2072 match Self::extract_i64_array::<9>(boxed) {
2073 Some(arr) => Ok(Some(Dat::Tup9i64(arr))),
2074 None => Ok(None)
2075 }
2076 }
2077
2078 // Tup10 conversions.
2079 (Kind::Tup10u8, Dat::Tup10(boxed)) => {
2080 match Self::extract_u8_array::<10>(boxed) {
2081 Some(arr) => Ok(Some(Dat::Tup10u8(arr))),
2082 None => Ok(None)
2083 }
2084 }
2085 (Kind::Tup10u16, Dat::Tup10(boxed)) => {
2086 match Self::extract_u16_array::<10>(boxed) {
2087 Some(arr) => Ok(Some(Dat::Tup10u16(arr))),
2088 None => Ok(None)
2089 }
2090 }
2091 (Kind::Tup10u32, Dat::Tup10(boxed)) => {
2092 match Self::extract_u32_array::<10>(boxed) {
2093 Some(arr) => Ok(Some(Dat::Tup10u32(arr))),
2094 None => Ok(None)
2095 }
2096 }
2097 (Kind::Tup10u64, Dat::Tup10(boxed)) => {
2098 match Self::extract_u64_array::<10>(boxed) {
2099 Some(arr) => Ok(Some(Dat::Tup10u64(arr))),
2100 None => Ok(None)
2101 }
2102 }
2103 (Kind::Tup10i8, Dat::Tup10(boxed)) => {
2104 match Self::extract_i8_array::<10>(boxed) {
2105 Some(arr) => Ok(Some(Dat::Tup10i8(arr))),
2106 None => Ok(None)
2107 }
2108 }
2109 (Kind::Tup10i16, Dat::Tup10(boxed)) => {
2110 match Self::extract_i16_array::<10>(boxed) {
2111 Some(arr) => Ok(Some(Dat::Tup10i16(arr))),
2112 None => Ok(None)
2113 }
2114 }
2115 (Kind::Tup10i32, Dat::Tup10(boxed)) => {
2116 match Self::extract_i32_array::<10>(boxed) {
2117 Some(arr) => Ok(Some(Dat::Tup10i32(arr))),
2118 None => Ok(None)
2119 }
2120 }
2121 (Kind::Tup10i64, Dat::Tup10(boxed)) => {
2122 match Self::extract_i64_array::<10>(boxed) {
2123 Some(arr) => Ok(Some(Dat::Tup10i64(arr))),
2124 None => Ok(None)
2125 }
2126 }
2127
2128 // No conversion needed or possible.
2129 _ => Ok(None)
2130 }
2131 }
2132
2133 // Helper functions to extract typed arrays from Dat arrays.
2134 fn extract_u8_array<const N: usize>(dats: &[Dat; N]) -> Option<[u8; N]> {
2135 let mut result = [0u8; N];
2136 for i in 0..N {
2137 result[i] = ok!(dats[i].get_u8());
2138 }
2139 Some(result)
2140 }
2141
2142 fn extract_u16_array<const N: usize>(dats: &[Dat; N]) -> Option<[u16; N]> {
2143 let mut result = [0u16; N];
2144 for i in 0..N {
2145 result[i] = ok!(dats[i].get_u16());
2146 }
2147 Some(result)
2148 }
2149
2150 fn extract_u32_array<const N: usize>(dats: &[Dat; N]) -> Option<[u32; N]> {
2151 let mut result = [0u32; N];
2152 for i in 0..N {
2153 result[i] = ok!(dats[i].get_u32());
2154 }
2155 Some(result)
2156 }
2157
2158 fn extract_u64_array<const N: usize>(dats: &[Dat; N]) -> Option<[u64; N]> {
2159 let mut result = [0u64; N];
2160 for i in 0..N {
2161 result[i] = ok!(dats[i].get_u64());
2162 }
2163 Some(result)
2164 }
2165
2166 fn extract_i8_array<const N: usize>(dats: &[Dat; N]) -> Option<[i8; N]> {
2167 let mut result = [0i8; N];
2168 for i in 0..N {
2169 result[i] = ok!(dats[i].get_i8());
2170 }
2171 Some(result)
2172 }
2173
2174 fn extract_i16_array<const N: usize>(dats: &[Dat; N]) -> Option<[i16; N]> {
2175 let mut result = [0i16; N];
2176 for i in 0..N {
2177 result[i] = ok!(dats[i].get_i16());
2178 }
2179 Some(result)
2180 }
2181
2182 fn extract_i32_array<const N: usize>(dats: &[Dat; N]) -> Option<[i32; N]> {
2183 let mut result = [0i32; N];
2184 for i in 0..N {
2185 result[i] = ok!(dats[i].get_i32());
2186 }
2187 Some(result)
2188 }
2189
2190 fn extract_i64_array<const N: usize>(dats: &[Dat; N]) -> Option<[i64; N]> {
2191 let mut result = [0i64; N];
2192 for i in 0..N {
2193 result[i] = ok!(dats[i].get_i64());
2194 }
2195 Some(result)
2196 }
2197}
2198
2199#[derive(Clone, Debug)]
2200pub struct MsgCmd {
2201 pub syntax: SyntaxRef,
2202 pub sname: String, // Syntax name.
2203 pub name: String, // Command name.
2204 pub vals: Vec<Dat>,
2205 pub args: BTreeMap<String, Vec<Dat>>, // one-to-one
2206 pub rest: Option<Vec<Dat>>, // after "--", when it was given
2207}
2208
2209impl fmt::Display for MsgCmd {
2210 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2211 ok!(write!(f, "{}", self.name));
2212 for val in &self.vals {
2213 ok!(write!(f, " {:?}", val));
2214 }
2215 for (k, argvals) in &self.args {
2216 // Written as a reader would type it, not as the command files it.
2217 ok!(write!(f, " {}", self.arg_short_name(k)));
2218 for val in argvals {
2219 ok!(write!(f, " {:?}", val));
2220 }
2221 }
2222 if let Some(words) = &self.rest {
2223 ok!(write!(f, " --"));
2224 for val in words {
2225 ok!(write!(f, " {:?}", val));
2226 }
2227 }
2228 Ok(())
2229 }
2230}
2231
2232impl MsgCmd {
2233
2234 pub fn new<S: Into<String>>(
2235 syntax: SyntaxRef,
2236 name: S,
2237 )
2238 -> Outcome<Self>
2239 {
2240 let name = name.into();
2241 let sname = syntax.config().name.clone();
2242 res!(syntax.cmds.get_recursive(&Key::Str(name.clone()))
2243 .ok_or_else(|| err!(
2244 "Cannot find this message command '{}' in the syntax '{}'.",
2245 name.clone(), sname;
2246 Invalid, Mismatch))
2247 );
2248 Ok(Self {
2249 syntax,
2250 sname,
2251 name,
2252 vals: Vec::new(),
2253 args: BTreeMap::new(),
2254 rest: None,
2255 })
2256 }
2257
2258 pub fn syntax<'a>(&'a self) -> &'a Syntax { self.syntax.as_ref() }
2259
2260 fn get_syntax_cmd<'a>(
2261 &'a self,
2262 )
2263 -> Outcome<&'a Cmd>
2264 {
2265 self.syntax().cmds.get_recursive(&Key::Str(self.name.clone())).ok_or_else(|| err!(
2266 "Cannot find this message command '{}' in the syntax '{}'.",
2267 self.name, self.sname;
2268 Invalid, Mismatch))
2269 }
2270
2271 fn get_syntax_arg<'a, S: Into<String>>(
2272 &'a self,
2273 arg_name: S,
2274 )
2275 -> Outcome<&'a Arg>
2276 {
2277 let arg_name = arg_name.into();
2278 res!(self.get_syntax_cmd()).args.get_recursive(&Key::Str(arg_name.clone()))
2279 .ok_or_else(|| err!(
2280 "Cannot find this command '{}' argument '{}' in the syntax '{}'.",
2281 self.name, arg_name, self.sname;
2282 Invalid, Mismatch))
2283 }
2284
2285 fn arg_key<S: Into<String>>(&self, arg_name: S) -> String {
2286 let arg_name = arg_name.into();
2287 match self.get_syntax_cmd() {
2288 Ok(cmd) => match cmd.args.get_recursive(&Key::Str(arg_name.clone())) {
2289 Some(arg) => arg.canonical_name(),
2290 None => arg_name,
2291 },
2292 Err(_) => arg_name,
2293 }
2294 }
2295
2296 fn arg_short_name<S: Into<String>>(&self, arg_name: S) -> String {
2297 let arg_name = arg_name.into();
2298 match self.get_syntax_cmd() {
2299 Ok(cmd) => match cmd.args.get_recursive(&Key::Str(arg_name.clone())) {
2300 Some(arg) => arg.short_name(),
2301 None => arg_name,
2302 },
2303 Err(_) => arg_name,
2304 }
2305 }
2306
2307 pub fn add_arg<S: Into<String>>(
2308 mut self,
2309 arg_name: S,
2310 )
2311 -> Outcome<Self>
2312 {
2313 let arg_name = arg_name.into();
2314 // Make sure the argument exists in the syntax.
2315 if !res!(self.get_syntax_cmd()).args.contains_key(&Key::Str(arg_name.clone())) {
2316 return Err(err!(
2317 "Can't find command '{}' argument '{}' in syntax '{}'.",
2318 self.name, arg_name, self.sname;
2319 Invalid, Input));
2320 }
2321 let key = self.arg_key(arg_name.clone());
2322 // Check whether it has already been added to the MsgCmd.
2323 if self.args.contains_key(&key) {
2324 return Err(err!(
2325 "Command '{}' argument '{}' has already been added to message.",
2326 self.name, arg_name;
2327 Invalid, Input, Exists));
2328 }
2329 self.args.insert(key, Vec::new());
2330 Ok(self)
2331 }
2332
2333 pub fn add_cmd_val(
2334 self,
2335 val: Dat,
2336 )
2337 -> Outcome<Self>
2338 {
2339 self.add_val::<String>(None, Some(val))
2340 }
2341
2342 pub fn add_arg_val<S: Into<String>>(
2343 self,
2344 arg_name: S,
2345 val: Option<Dat>,
2346 )
2347 -> Outcome<Self>
2348 {
2349 self.add_val(Some(arg_name), val)
2350 }
2351
2352 pub fn add_val<S: Into<String>>(
2353 mut self,
2354 arg_opt: Option<S>,
2355 val_opt: Option<Dat>,
2356 )
2357 -> Outcome<Self>
2358 {
2359 let arg_opt = arg_opt.map(|s| s.into());
2360 let (exp_vals, arg_name): (Vec<Val>, String) = match &arg_opt {
2361 Some(arg_name) => {
2362 let arg = res!(self.get_syntax_arg(arg_name.clone()));
2363 (arg.config().vals.clone(), fmt!("argument '{}' ", arg_name))
2364 },
2365 None => (res!(self.get_syntax_cmd()).config().vals.clone(), fmt!("")),
2366 };
2367 // File the value under the argument's one name, whichever of its names
2368 // the caller wrote.
2369 let arg_opt = arg_opt.map(|name| self.arg_key(name));
2370
2371 let v: &mut Vec<Dat> = match arg_opt {
2372 Some(arg_name) => match self.args.get_mut(&arg_name) {
2373 Some(v) => v,
2374 None => {
2375 self.args.insert(arg_name.clone(), Vec::new());
2376 match self.args.get_mut(&arg_name) {
2377 Some(v) => v,
2378 None => return Err(err!(
2379 "Argument '{}' was just created, but no longer present.", arg_name;
2380 Bug, Unreachable)),
2381 }
2382 },
2383 },
2384 None => &mut self.vals,
2385 };
2386
2387 let next = match Val::slot(&exp_vals, v.len()) {
2388 Some(next) => next,
2389 None => return Err(err!(
2390 "Command '{}' {}already has all {} of its \
2391 expected values.", self.name, arg_name, v.len();
2392 Invalid, Input, Exists)),
2393 };
2394
2395 match val_opt {
2396 Some(val) => {
2397 if next.kind == Kind::Unknown || val.kind() == next.kind {
2398 v.push(val);
2399 } else {
2400 return Err(err!(
2401 "Command '{}' {}already has {} values, and \
2402 the next one must be a {:?}, not a {:?}.",
2403 self.name, arg_name, v.len(), next.kind, val.kind();
2404 Invalid, Input));
2405 }
2406 },
2407 None => (),
2408 }
2409
2410 Ok(self)
2411 }
2412
2413 pub fn get_vals(&self) -> Option<&Vec<Dat>> {
2414 if self.vals.len() == 0 {
2415 None
2416 } else {
2417 Some(&self.vals)
2418 }
2419 }
2420
2421 pub fn get_vals_mut(&mut self) -> Option<&mut Vec<Dat>> {
2422 if self.vals.len() == 0 {
2423 None
2424 } else {
2425 Some(&mut self.vals)
2426 }
2427 }
2428
2429 pub fn get_arg_vals<S: Into<String>>(&self, a: S) -> Option<&Vec<Dat>> {
2430 match self.args.get(&self.arg_key(a)) {
2431 Some(vals) => if vals.len() == 0 {
2432 None
2433 } else {
2434 Some(&vals)
2435 },
2436 None => None,
2437 }
2438 }
2439
2440 pub fn get_arg_vals_mut<S: Into<String>>(&mut self, a: S) -> Option<&mut Vec<Dat>> {
2441 let key = self.arg_key(a);
2442 match self.args.get_mut(&key) {
2443 Some(vals) => {
2444 if vals.len() == 0 {
2445 None
2446 } else {
2447 Some(vals)
2448 }
2449 },
2450 None => None,
2451 }
2452 }
2453
2454 pub fn has_arg<S: Into<String>>(&self, a: S) -> bool {
2455 self.args.contains_key(&self.arg_key(a))
2456 }
2457
2458 /// The words given after "--", or `None` when there was no "--".
2459 pub fn get_rest(&self) -> Option<&Vec<Dat>> { self.rest.as_ref() }
2460
2461 /// The command's values, each of which must be a string, as a command line gives them.
2462 pub fn str_vals(&self) -> Outcome<Vec<&str>> {
2463 Self::strs(&self.vals, &fmt!("command '{}'", self.name))
2464 }
2465
2466 /// The values of one of the command's arguments, each of which must be a string.
2467 pub fn str_arg_vals<S: Into<String>>(&self, a: S) -> Outcome<Vec<&str>> {
2468 let a = a.into();
2469 match self.args.get(&self.arg_key(a.clone())) {
2470 Some(vals) => Self::strs(vals, &fmt!("command '{}' argument '{}'", self.name, a)),
2471 None => Ok(Vec::new()),
2472 }
2473 }
2474
2475 fn strs<'a>(vals: &'a [Dat], owner: &str) -> Outcome<Vec<&'a str>> {
2476 let mut out = Vec::with_capacity(vals.len());
2477 for (i, val) in vals.iter().enumerate() {
2478 match val {
2479 Dat::Str(s) => out.push(s.as_str()),
2480 other => return Err(err!(
2481 "Value {} of the {} is a {:?}, not a string.", i + 1, owner, other.kind();
2482 Input, Mismatch)),
2483 }
2484 }
2485 Ok(out)
2486 }
2487
2488 pub fn has_args(&self) -> bool {
2489 self.args.len() > 0
2490 }
2491
2492 pub fn has_only_arg<S: Into<String>>(&self, a: S) -> Outcome<bool> {
2493 let a = a.into();
2494 let has = self.args.contains_key(&self.arg_key(a.clone()));
2495 if self.args.len() > 1 {
2496 Err(err!(
2497 "The argument '{}' {}", a, if has {
2498 "does not exist and there are other arguments."
2499 } else {
2500 "does exist but there are other arguments."
2501 };
2502 Input, Invalid, Excessive))
2503 } else {
2504 Ok(has)
2505 }
2506 }
2507}