1use std::fmt;
6use std::prelude::v1::*;
7
8use crate::error::{Error, ErrorKind, ErrorOrigin, Result};
9
10use cglue::{repr_cstring::ReprCString, vec::CVec};
11
12use core::convert::TryFrom;
13use hashbrown::HashMap;
14
15#[repr(C)]
37#[derive(Debug, Clone)]
38#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
39pub struct Args {
40 args: CVec<ArgEntry>,
44}
45
46#[derive(Debug, Clone)]
47#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
48pub struct ArgEntry {
49 key: ReprCString,
50 value: ReprCString,
51}
52
53impl<T: Into<ReprCString>> From<(T, T)> for ArgEntry {
54 fn from((key, value): (T, T)) -> Self {
55 Self {
56 key: key.into(),
57 value: value.into(),
58 }
59 }
60}
61
62impl fmt::Display for Args {
63 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72 let mut result = Vec::new();
73
74 if let Some(default) = self.get_default() {
75 result.push(default.to_string());
76 }
77
78 result.extend(
79 self.args
80 .iter()
81 .filter(|e| &*e.key != "default")
82 .map(|ArgEntry { key, value }| {
83 if value.contains(',') || value.contains('=') {
84 format!("{}=\"{}\"", key, value)
85 } else {
86 format!("{}={}", key, value)
87 }
88 })
89 .collect::<Vec<_>>(),
90 );
91
92 write!(f, "{}", result.join(","))
93 }
94}
95
96impl std::str::FromStr for Args {
97 type Err = crate::error::Error;
98
99 fn from_str(s: &str) -> Result<Self> {
112 let split = split_str_args(s, ',').collect::<Vec<_>>();
113
114 let mut map = HashMap::new();
115 for (i, kv) in split.iter().enumerate() {
116 let kvsplit = split_str_args(kv, '=').collect::<Vec<_>>();
117 if kvsplit.len() == 2 {
118 map.insert(kvsplit[0].to_string(), kvsplit[1].to_string());
119 } else if i == 0 && !kv.is_empty() {
120 map.insert("default".to_string(), kv.to_string());
121 }
122 }
123
124 Ok(Self {
125 args: map.into_iter().map(<_>::into).collect::<Vec<_>>().into(),
126 })
127 }
128}
129
130impl Default for Args {
131 fn default() -> Self {
133 Self {
134 args: Default::default(),
135 }
136 }
137}
138
139impl Args {
140 pub fn new() -> Self {
142 Self::default()
143 }
144
145 pub fn with_default(value: &str) -> Self {
147 Self::new().insert("default", value)
148 }
149
150 pub fn insert(mut self, key: &str, value: &str) -> Self {
165 if let Some(a) = self.args.iter_mut().find(|a| &*a.key == key) {
166 a.value = value.into();
167 } else {
168 self.args.push((key, value).into());
169 }
170 self
171 }
172
173 pub fn get(&self, key: &str) -> Option<&str> {
176 self.args
177 .iter()
178 .filter(|a| &*a.key == key)
179 .map(|a| &*a.value)
180 .next()
181 }
182
183 pub fn get_default(&self) -> Option<&str> {
188 self.get("default")
189 }
190}
191
192impl TryFrom<&str> for Args {
193 type Error = Error;
194
195 fn try_from(args: &str) -> Result<Self> {
196 args.parse()
197 }
198}
199
200impl TryFrom<String> for Args {
201 type Error = Error;
202
203 fn try_from(args: String) -> Result<Self> {
204 args.parse()
205 }
206}
207
208impl From<Args> for String {
209 fn from(args: Args) -> Self {
210 args.to_string()
211 }
212}
213
214#[derive(Debug)]
227pub struct ArgsValidator {
228 args: Vec<ArgDescriptor>,
229}
230
231impl Default for ArgsValidator {
232 fn default() -> Self {
233 Self::new()
234 }
235}
236
237impl ArgsValidator {
238 pub fn new() -> Self {
240 Self { args: Vec::new() }
241 }
242
243 pub fn arg(mut self, arg: ArgDescriptor) -> Self {
245 self.args.push(arg);
246 self
247 }
248
249 pub fn validate(&self, args: &Args) -> Result<()> {
250 for arg in args.args.iter() {
252 if !self.args.iter().any(|a| a.name == *arg.key) {
253 return Err(Error(ErrorOrigin::ArgsValidator, ErrorKind::ArgNotExists)
254 .log_error(format!("argument {} does not exist", &*arg.key)));
255 }
256 }
257
258 for arg in self.args.iter() {
259 if arg.required && args.get(&arg.name).is_none() {
261 return Err(
262 Error(ErrorOrigin::ArgsValidator, ErrorKind::RequiredArgNotFound).log_error(
263 format!("argument {} is required but could not be found", arg.name),
264 ),
265 );
266 }
267
268 if let Some(validator) = &arg.validator {
270 if let Some(value) = args.get(&arg.name) {
271 if let Err(err) = validator(value) {
272 return Err(Error(ErrorOrigin::ArgsValidator, ErrorKind::ArgValidation)
273 .log_error(format!("argument {} is invalid: {}", arg.name, err)));
274 }
275 }
276 }
277 }
278
279 Ok(())
280 }
281}
282
283impl fmt::Display for ArgsValidator {
284 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
285 for (idx, arg) in self.args.iter().enumerate() {
286 if idx < self.args.len() - 1 {
287 writeln!(f, "{}", arg).ok();
288 } else {
289 write!(f, "{}", arg).ok();
290 }
291 }
292 Ok(())
293 }
294}
295
296pub type ArgValidator = Box<dyn Fn(&str) -> ::std::result::Result<(), &'static str>>;
297
298pub struct ArgDescriptor {
311 pub name: String,
312 pub description: Option<String>,
313 pub required: bool,
314 pub validator: Option<ArgValidator>,
315}
316
317impl ArgDescriptor {
318 pub fn new(name: &str) -> Self {
320 Self {
321 name: name.to_owned(),
322 description: None,
323 required: false,
324 validator: None,
325 }
326 }
327
328 pub fn description(mut self, description: &str) -> Self {
332 self.description = Some(description.to_owned());
333 self
334 }
335
336 pub fn required(mut self, required: bool) -> Self {
340 self.required = required;
341 self
342 }
343
344 pub fn validator(mut self, validator: ArgValidator) -> Self {
361 self.validator = Some(validator);
362 self
363 }
364}
365
366impl fmt::Display for ArgDescriptor {
367 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
368 write!(
369 f,
370 "{}: {}{}",
371 self.name,
372 self.description
373 .as_ref()
374 .unwrap_or(&"no description available".to_owned()),
375 if self.required { " (required)" } else { "" },
376 )
377 }
378}
379
380impl fmt::Debug for ArgDescriptor {
381 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
382 write!(
383 f,
384 "{}: {}{}",
385 self.name,
386 self.description
387 .as_ref()
388 .unwrap_or(&"no description available".to_owned()),
389 if self.required { " (required)" } else { "" },
390 )
391 }
392}
393
394pub fn split_str_args(inp: &str, split_char: char) -> impl Iterator<Item = &str> {
426 let mut prev_char = '\0';
427 let mut quotation_char = None;
428
429 const VALID_QUOTES: &str = "\"'`";
430 assert!(!VALID_QUOTES.contains(split_char));
431
432 inp.split(move |c| {
433 let mut ret = false;
434
435 if VALID_QUOTES.contains(c) && prev_char != '\\' {
437 match quotation_char {
439 Some(qc) if qc == c => {
440 quotation_char = None;
441 }
442 None => quotation_char = Some(c),
443 _ => (),
444 }
445 }
446
447 if quotation_char.is_none() && c == split_char {
448 ret = true;
449 }
450
451 prev_char = c;
452 ret
453 })
454 .map(|s| {
455 if let Some(c) = s.chars().next().and_then(|a| {
456 if s.ends_with(a) && VALID_QUOTES.contains(a) {
457 Some(a)
458 } else {
459 None
460 }
461 }) {
462 s.split_once(c)
463 .and_then(|(_, a)| a.rsplit_once(c))
464 .map(|(a, _)| a)
465 .unwrap_or("")
466 } else {
467 s
468 }
469 })
470}
471
472pub fn parse_vatcache(args: &Args) -> Result<Option<(usize, u64)>> {
473 match args.get("vatcache").unwrap_or("default") {
474 "default" => Ok(Some((0, 0))),
475 "none" => Ok(None),
476 size => Ok(Some(parse_vatcache_args(size)?)),
477 }
478}
479
480fn parse_vatcache_args(vargs: &str) -> Result<(usize, u64)> {
481 let mut sp = vargs.splitn(2, ';');
482 let (size, time) = (
483 sp.next().ok_or_else(|| {
484 Error(ErrorOrigin::OsLayer, ErrorKind::Configuration)
485 .log_error("Failed to parse VAT size")
486 })?,
487 sp.next().unwrap_or("0"),
488 );
489 let size = usize::from_str_radix(size, 16).map_err(|_| {
490 Error(ErrorOrigin::OsLayer, ErrorKind::Configuration).log_error("Failed to parse VAT size")
491 })?;
492 let time = time.parse::<u64>().map_err(|_| {
493 Error(ErrorOrigin::OsLayer, ErrorKind::Configuration)
494 .log_error("Failed to parse VAT validity time")
495 })?;
496 Ok((size, time))
497}
498
499#[cfg(test)]
500mod tests {
501 use super::*;
502
503 #[test]
504 pub fn from_str() {
505 let argstr = "opt1=test1,opt2=test2,opt3=test3";
506 let args: Args = argstr.parse().unwrap();
507 assert_eq!(args.get("opt1").unwrap(), "test1");
508 assert_eq!(args.get("opt2").unwrap(), "test2");
509 assert_eq!(args.get("opt3").unwrap(), "test3");
510 }
511
512 #[test]
513 pub fn from_str_default() {
514 let argstr = "test0,opt1=test1,opt2=test2,opt3=test3";
515 let args: Args = argstr.parse().unwrap();
516 assert_eq!(args.get_default().unwrap(), "test0");
517 assert_eq!(args.get("opt1").unwrap(), "test1");
518 assert_eq!(args.get("opt2").unwrap(), "test2");
519 assert_eq!(args.get("opt3").unwrap(), "test3");
520 }
521
522 #[test]
523 pub fn from_str_default2() {
524 let argstr = "opt1=test1,test0";
525 let args: Args = argstr.parse().unwrap();
526 assert_eq!(args.get_default(), None);
527 assert_eq!(args.get("opt1").unwrap(), "test1");
528 }
529
530 #[test]
531 pub fn builder() {
532 let args = Args::new().insert("arg1", "test1").insert("arg2", "test2");
533 assert_eq!(args.get("arg1").unwrap(), "test1");
534 assert_eq!(args.get("arg2").unwrap(), "test2");
535 }
536
537 #[test]
538 pub fn parse_empty() {
539 let argstr = "opt1=test1,test0";
540 let _: Args = argstr.parse().unwrap();
541 }
542
543 #[test]
544 pub fn to_string() {
545 let argstr = "opt1=test1,opt2=test2,opt3=test3";
546 let args: Args = argstr.parse().unwrap();
547 let args2: Args = args.to_string().parse().unwrap();
548 assert_eq!(args2.get_default(), None);
549 assert_eq!(args2.get("opt1").unwrap(), "test1");
550 assert_eq!(args2.get("opt2").unwrap(), "test2");
551 assert_eq!(args2.get("opt3").unwrap(), "test3");
552 }
553
554 #[test]
555 pub fn to_string_with_default() {
556 let argstr = "test0,opt1=test1,opt2=test2,opt3=test3";
557 let args: Args = argstr.parse().unwrap();
558 let args2: Args = args.to_string().parse().unwrap();
559 assert_eq!(args2.get_default().unwrap(), "test0");
560 assert_eq!(args2.get("opt1").unwrap(), "test1");
561 assert_eq!(args2.get("opt2").unwrap(), "test2");
562 assert_eq!(args2.get("opt3").unwrap(), "test3");
563 }
564
565 #[test]
566 pub fn double_quotes() {
567 let argstr = "opt1=test1,test0,opt2=\"test2,test3\"";
568 let args: Args = argstr.parse().unwrap();
569 let args2: Args = args.to_string().parse().unwrap();
570 assert_eq!(args2.get("opt1").unwrap(), "test1");
571 assert_eq!(args2.get("opt2").unwrap(), "test2,test3");
572 }
573
574 #[test]
575 pub fn double_quotes_eq() {
576 let argstr = "opt1=test1,test0,opt2=\"test2,test3=test4\"";
577 let args: Args = argstr.parse().unwrap();
578 let args2: Args = args.to_string().parse().unwrap();
579 assert_eq!(args2.get("opt1").unwrap(), "test1");
580 assert_eq!(args2.get("opt2").unwrap(), "test2,test3=test4");
581 }
582
583 #[test]
584 pub fn slashes() {
585 let argstr = "device=vmware://,remote=rpc://insecure:computername.local";
586 let args: Args = argstr.parse().unwrap();
587 let args2: Args = args.to_string().parse().unwrap();
588 assert_eq!(args2.get("device").unwrap(), "vmware://");
589 assert_eq!(
590 args2.get("remote").unwrap(),
591 "rpc://insecure:computername.local"
592 );
593 }
594
595 #[test]
596 pub fn slashes_quotes_split() {
597 let v: Vec<_> = split_str_args(
598 "url1=\"uri://ip=test:test@test,test\",url2=\"test:test@test.de,test2:test2@test2.de\"",
599 ',',
600 )
601 .collect();
602 assert_eq!(
603 v,
604 [
605 "url1=\"uri://ip=test:test@test,test\"",
606 "url2=\"test:test@test.de,test2:test2@test2.de\""
607 ]
608 );
609 }
610
611 #[test]
612 pub fn slashes_quotes() {
613 let argstr = "device=\"RAWUDP://ip=127.0.0.1\"";
614 let args: Args = argstr.parse().unwrap();
615 let args2: Args = args.to_string().parse().unwrap();
616 assert_eq!(args2.get("device").unwrap(), "RAWUDP://ip=127.0.0.1");
617 }
618
619 #[test]
620 pub fn slashes_mixed_quotes() {
621 let argstr = "device=`RAWUDP://ip=127.0.0.1`";
622 let args: Args = argstr.parse().unwrap();
623 assert_eq!(args.get("device").unwrap(), "RAWUDP://ip=127.0.0.1");
624
625 let arg2str = args.to_string();
626 assert_eq!(arg2str, "device=\"RAWUDP://ip=127.0.0.1\"");
627
628 let args2: Args = arg2str.parse().unwrap();
629 assert_eq!(args2.get("device").unwrap(), "RAWUDP://ip=127.0.0.1");
630 }
631
632 #[test]
633 pub fn slashes_quotes_complex() {
634 let argstr =
635 "url1=\"uri://ip=test:test@test,test\",url2=\"test:test@test.de,test2:test2@test2.de\"";
636 let args: Args = argstr.parse().unwrap();
637 let args2: Args = args.to_string().parse().unwrap();
638 assert_eq!(args2.get("url1").unwrap(), "uri://ip=test:test@test,test");
639 assert_eq!(
640 args2.get("url2").unwrap(),
641 "test:test@test.de,test2:test2@test2.de"
642 );
643 }
644
645 #[test]
646 pub fn validator_success() {
647 let validator = ArgsValidator::new()
648 .arg(ArgDescriptor::new("default"))
649 .arg(ArgDescriptor::new("opt1"));
650
651 let argstr = "test0,opt1=test1";
652 let args: Args = argstr.parse().unwrap();
653
654 assert_eq!(validator.validate(&args), Ok(()));
655 }
656
657 #[test]
658 pub fn validator_success_optional() {
659 let validator = ArgsValidator::new().arg(ArgDescriptor::new("opt1").required(false));
660
661 let args: Args = "".parse().unwrap();
662
663 assert_eq!(validator.validate(&args), Ok(()));
664 }
665
666 #[test]
667 pub fn validator_error_required() {
668 let validator = ArgsValidator::new().arg(ArgDescriptor::new("opt1").required(true));
669
670 let args: Args = "".parse().unwrap();
671
672 assert_eq!(
673 validator.validate(&args),
674 Err(Error(
675 ErrorOrigin::ArgsValidator,
676 ErrorKind::RequiredArgNotFound
677 ))
678 );
679 }
680
681 #[test]
682 pub fn validator_error_notexist() {
683 let validator = ArgsValidator::new().arg(ArgDescriptor::new("opt1"));
684
685 let argstr = "opt2=arg2";
686 let args: Args = argstr.parse().unwrap();
687
688 assert_eq!(
689 validator.validate(&args),
690 Err(Error(ErrorOrigin::ArgsValidator, ErrorKind::ArgNotExists))
691 );
692 }
693
694 #[test]
695 pub fn validator_validate_success() {
696 let validator =
697 ArgsValidator::new().arg(ArgDescriptor::new("default").validator(Box::new(|arg| {
698 match arg == "valid_option" {
699 true => Ok(()),
700 false => Err("argument must be 'valid_option'"),
701 }
702 })));
703
704 let argstr = "default=valid_option";
705 let args: Args = argstr.parse().unwrap();
706
707 assert_eq!(validator.validate(&args), Ok(()));
708 }
709
710 #[test]
711 pub fn validator_validate_fail() {
712 let validator =
713 ArgsValidator::new().arg(ArgDescriptor::new("default").validator(Box::new(|arg| {
714 match arg == "valid_option" {
715 true => Ok(()),
716 false => Err("argument must be 'valid_option'"),
717 }
718 })));
719
720 let argstr = "invalid_option";
721 let args: Args = argstr.parse().unwrap();
722
723 assert_eq!(
724 validator.validate(&args),
725 Err(Error(ErrorOrigin::ArgsValidator, ErrorKind::ArgValidation))
726 );
727 }
728}