1use std::borrow::Cow;
2use std::fmt::Debug;
3use std::marker::PhantomData;
4
5use super::FailManager;
6use super::OptStyleManager;
7use super::Policy;
8use super::PolicySettings;
9use super::Return;
10use super::UserStyle;
11use crate::args;
12use crate::args::ArgInfo;
13use crate::args::Args;
14use crate::ctx::Ctx;
15use crate::ctx::Invoker;
16use crate::guess::InvokeGuess;
17use crate::opt::Opt;
18use crate::opt::OptParser;
19use crate::parser::Action;
20use crate::set::OptValidator;
21use crate::set::SetChecker;
22use crate::set::SetOpt;
23use crate::trace;
24use crate::Error;
25
26pub struct FwdPolicy<S, Chk> {
182 strict: bool,
183
184 overload: bool,
185
186 prepolicy: bool,
187
188 checker: Chk,
189
190 style_manager: OptStyleManager,
191
192 marker_s: PhantomData<S>,
193}
194
195impl<S, Chk> Clone for FwdPolicy<S, Chk>
196where
197 Chk: Clone,
198{
199 fn clone(&self) -> Self {
200 Self {
201 strict: self.strict,
202 overload: self.overload,
203 prepolicy: self.prepolicy,
204 checker: self.checker.clone(),
205 style_manager: self.style_manager.clone(),
206 marker_s: self.marker_s,
207 }
208 }
209}
210
211impl<S, Chk> Debug for FwdPolicy<S, Chk>
212where
213 Chk: Debug,
214{
215 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
216 f.debug_struct("FwdPolicy")
217 .field("strict", &self.strict)
218 .field("overload", &self.overload)
219 .field("prepolicy", &self.prepolicy)
220 .field("checker", &self.checker)
221 .field("style_manager", &self.style_manager)
222 .finish()
223 }
224}
225
226impl<S, Chk> Default for FwdPolicy<S, Chk>
227where
228 Chk: Default,
229{
230 fn default() -> Self {
231 Self {
232 strict: true,
233 overload: false,
234 prepolicy: false,
235 style_manager: OptStyleManager::default(),
236 checker: Chk::default(),
237 marker_s: PhantomData,
238 }
239 }
240}
241
242impl<S, Chk> FwdPolicy<S, Chk>
243where
244 Chk: Default,
245{
246 pub fn new(strict: bool, style: OptStyleManager) -> Self {
247 Self {
248 strict,
249 style_manager: style,
250 ..Default::default()
251 }
252 }
253}
254
255impl<S, Chk> FwdPolicy<S, Chk> {
256 pub fn with_strict(mut self, strict: bool) -> Self {
259 self.strict = strict;
260 self
261 }
262
263 pub fn with_styles(mut self, styles: Vec<UserStyle>) -> Self {
264 self.style_manager.set(styles);
265 self
266 }
267
268 pub fn with_checker(mut self, checker: Chk) -> Self {
269 self.checker = checker;
270 self
271 }
272
273 pub fn with_overload(mut self, overload: bool) -> Self {
274 self.overload = overload;
275 self
276 }
277
278 pub fn with_prepolicy(mut self, prepolicy: bool) -> Self {
279 self.prepolicy = prepolicy;
280 self
281 }
282
283 pub fn set_checker(&mut self, checker: Chk) -> &mut Self {
284 self.checker = checker;
285 self
286 }
287
288 pub fn checker(&self) -> &Chk {
289 &self.checker
290 }
291
292 pub fn checker_mut(&mut self) -> &mut Chk {
293 &mut self.checker
294 }
295
296 pub(crate) fn noa_cmd() -> usize {
297 1
298 }
299
300 pub(crate) fn noa_main() -> usize {
301 0
302 }
303
304 pub(crate) fn noa_pos(idx: usize) -> usize {
305 idx
306 }
307
308 pub(crate) fn filter<T, E: Into<Error>>(
309 prepolicy: bool,
310 res: Result<T, E>,
311 ) -> Result<Option<T>, Error> {
312 let res = res.map_err(Into::into);
313
314 if !prepolicy {
315 res.map(|v| Some(v))
316 } else {
317 match res {
318 Ok(val) => Ok(Some(val)),
319 Err(e) => {
320 if e.is_failure() {
321 Ok(None)
322 } else {
323 Err(e)
324 }
325 }
326 }
327 }
328 }
329}
330
331impl<Set, Chk> PolicySettings for FwdPolicy<Set, Chk> {
332 fn style_manager(&self) -> &OptStyleManager {
333 &self.style_manager
334 }
335
336 fn style_manager_mut(&mut self) -> &mut OptStyleManager {
337 &mut self.style_manager
338 }
339
340 fn strict(&self) -> bool {
341 self.strict
342 }
343
344 fn styles(&self) -> &[UserStyle] {
345 &self.style_manager
346 }
347
348 fn no_delay(&self) -> Option<&[String]> {
349 None
350 }
351
352 fn overload(&self) -> bool {
353 self.overload
354 }
355
356 fn prepolicy(&self) -> bool {
357 self.prepolicy
358 }
359
360 fn set_strict(&mut self, strict: bool) -> &mut Self {
361 self.strict = strict;
362 self
363 }
364
365 fn set_styles(&mut self, styles: Vec<UserStyle>) -> &mut Self {
366 self.style_manager.set(styles);
367 self
368 }
369
370 fn set_no_delay(&mut self, _: impl Into<String>) -> &mut Self {
371 self
372 }
373
374 fn set_overload(&mut self, overload: bool) -> &mut Self {
375 self.overload = overload;
376 self
377 }
378
379 fn set_prepolicy(&mut self, prepolicy: bool) -> &mut Self {
380 self.prepolicy = prepolicy;
381 self
382 }
383}
384
385impl<S, Chk> FwdPolicy<S, Chk>
386where
387 SetOpt<S>: Opt,
388 Chk: SetChecker<S>,
389 S: crate::set::Set + OptParser + OptValidator,
390{
391 pub(crate) fn parse_impl<'a>(
392 &mut self,
393 set: &mut <Self as Policy>::Set,
394 inv: &mut <Self as Policy>::Inv<'_>,
395 orig: &'a Args,
396 ctx: &mut Ctx<'a>,
397 ) -> Result<(), <Self as Policy>::Error> {
398 self.checker().pre_check(set).map_err(Into::into)?;
399
400 let overload = self.overload();
401 let pre = self.prepolicy();
402 let opt_styles = &self.style_manager;
403 let args: Vec<_> = orig.iter().map(|v| v.as_os_str()).collect();
404 let total = args.len();
405 let mut lefts = vec![];
406 let mut opt_fail = FailManager::default();
407 let mut iter2 = args::iter2(&args).enumerate();
408
409 trace!("parsing {ctx:?} using fwd policy");
410 ctx.set_args(args.clone());
411 while let Some((idx, (opt, next))) = iter2.next() {
412 let mut matched = false;
413 let mut consume = false;
414 let mut stopped = false;
415 let mut like_opt = false;
416
417 if let Ok(ArgInfo { name, value }) = ArgInfo::parse(opt) {
418 trace!(
419 "guess name: {:?} value: {:?} & next: {:?}",
420 name,
421 value,
422 next
423 );
424 if let Some(true) = Self::filter(pre, set.check(&name))? {
425 let arg = value.clone();
426 let next = next.map(|v| Cow::Borrowed(*v));
427 let mut guess = InvokeGuess {
428 idx,
429 arg,
430 set,
431 inv,
432 total,
433 ctx,
434 next,
435 fail: &mut opt_fail,
436 name: Some(name.clone()),
437 };
438
439 like_opt = true;
440 for style in opt_styles.iter() {
441 if let Some(Some(ret)) =
442 Self::filter(pre, guess.guess_and_invoke(style, overload))?
443 {
444 (matched, consume) = (ret.matched, ret.consume);
445 }
446 if matched {
447 match guess.ctx.policy_act() {
448 Action::Stop => {
449 stopped = true;
450 guess.ctx.reset_policy_act();
451 break;
452 }
453 Action::Quit => return Ok(()),
454 Action::Null => {}
455 }
456 break;
457 }
458 }
459 if !pre && !stopped && !matched && self.strict() {
465 return Err(opt_fail.cause(Error::sp_not_found(name)));
466 }
467 }
468 if !like_opt {
469 trace!("`{:?}` not like option", opt);
470 }
471 }
472 if stopped {
473 lefts.extend(iter2.map(|(_, (a, _))| *a));
475 break;
476 }
477 if matched && consume {
479 iter2.next();
480 } else if !matched {
481 lefts.push(*opt);
483 }
484 }
485
486 opt_fail.process_check(self.checker().opt_check(set))?;
487
488 let args = lefts;
489 let total = args.len();
490 let mut pos_fail = FailManager::default();
491 let mut cmd_fail = FailManager::default();
492
493 ctx.set_args(args.clone());
494 if total > 0 {
496 let name = crate::str::osstr_to_str_i(&args, Self::noa_cmd());
497 let mut guess = InvokeGuess {
498 set,
499 inv,
500 total,
501 name,
502 ctx,
503 arg: None,
504 next: None,
505 fail: &mut cmd_fail,
506 idx: Self::noa_cmd(),
507 };
508
509 trace!("guess Cmd = {:?}", guess.name);
510 Self::filter(pre, guess.guess_and_invoke(&UserStyle::Cmd, overload))?;
511 if let Action::Quit = ctx.policy_act() {
512 return Ok(());
513 }
514 cmd_fail.process_check(self.checker().cmd_check(set))?;
515
516 let mut guess = InvokeGuess {
517 set,
518 inv,
519 total,
520 ctx,
521 name: None,
522 arg: None,
523 next: None,
524 fail: &mut pos_fail,
525 idx: Self::noa_cmd(),
526 };
527
528 for idx in 1..total {
529 guess.idx = Self::noa_pos(idx);
530 guess.name = crate::str::osstr_to_str_i(&args, Self::noa_pos(idx));
531 trace!("guess Pos argument = {:?} @ {}", guess.name, guess.idx);
532 Self::filter(pre, guess.guess_and_invoke(&UserStyle::Pos, overload))?;
533 match guess.ctx.policy_act() {
534 Action::Stop => {
535 guess.ctx.reset_policy_act();
536 break;
537 }
538 Action::Quit => return Ok(()),
539 Action::Null => {}
540 }
541 }
542 } else {
543 cmd_fail.process_check(self.checker().cmd_check(set))?;
544 }
545
546 pos_fail.process_check(self.checker().pos_check(set))?;
547
548 let name = crate::str::osstr_to_str_i(&ctx.args, Self::noa_main());
549 let mut main_fail = FailManager::default();
550 let mut guess = InvokeGuess {
551 set,
552 inv,
553 total,
554 name,
555 ctx,
556 arg: None,
557 next: None,
558 fail: &mut main_fail,
559 idx: Self::noa_main(),
560 };
561
562 trace!("guess Main {:?}", guess.name);
563 Self::filter(pre, guess.guess_and_invoke(&UserStyle::Main, overload))?;
564 main_fail.process_check(self.checker().post_check(set))?;
565 Ok(())
566 }
567}
568
569impl<S, Chk> Policy for FwdPolicy<S, Chk>
570where
571 SetOpt<S>: Opt,
572 Chk: SetChecker<S>,
573 S: crate::set::Set + OptParser + OptValidator,
574{
575 type Ret = Return;
576
577 type Set = S;
578
579 type Inv<'a> = Invoker<'a, S>;
580
581 type Error = Error;
582
583 fn parse(
584 &mut self,
585 set: &mut Self::Set,
586 inv: &mut Self::Inv<'_>,
587
588 orig: Args,
589 ) -> Result<Self::Ret, Self::Error> {
590 let mut ctx = Ctx::default().with_orig(orig.clone());
591
592 match self.parse_impl(set, inv, &orig, &mut ctx) {
593 Ok(_) => Ok(Return::new(ctx)),
594 Err(e) => {
595 if e.is_failure() {
596 Ok(Return::new(ctx).with_failure(e))
597 } else {
598 Err(e)
599 }
600 }
601 }
602 }
603}
604
605#[cfg(test)]
606mod test {
607
608 use std::any::TypeId;
609 use std::ffi::OsStr;
610
611 use crate::opt::Cmd;
612 use crate::opt::ConfigBuildInfer;
613 use crate::opt::Pos;
614 use crate::prelude::*;
615 use crate::Error;
616
617 #[test]
618 fn testing() {
619 assert!(testing_prepolicy().is_ok());
620 assert!(testing_non_prepolicy().is_ok());
621 }
622
623 #[allow(clippy::too_many_arguments)]
624 fn check_opt_val<T: std::fmt::Debug + PartialEq + ErasedTy + 'static>(
625 opt: &AOpt,
626 uid: Uid,
627 name: &str,
628 vals: Option<Vec<T>>,
629 force: bool,
630 action: &Action,
631 type_id: &TypeId,
632 index: Option<&Index>,
633 alias: Option<Vec<&str>>,
634 ) -> Result<(), Error> {
635 let opt_uid = opt.uid();
636
637 assert_eq!(opt_uid, uid);
638 assert_eq!(opt.name(), name, "name not equal -{}({})-", opt_uid, name);
639 assert_eq!(
640 opt.force(),
641 force,
642 "option force required not equal -{}({})-: {}",
643 opt_uid,
644 name,
645 force
646 );
647 assert_eq!(opt.action(), action, "action not equal for {}", opt_uid);
648 assert_eq!(
649 opt.r#type(),
650 type_id,
651 "type_id not equal for {}({})",
652 opt_uid,
653 opt.name(),
654 );
655 assert_eq!(opt.index(), index, "option index not equal: {:?}", index);
656 if let Ok(opt_vals) = opt.vals::<T>() {
657 if let Some(vals) = vals {
658 assert_eq!(
659 opt_vals.len(),
660 vals.len(),
661 "value length not equal for {}",
662 opt_uid
663 );
664 for (l, r) in opt_vals.iter().zip(vals.iter()) {
665 assert_eq!(
666 l, r,
667 "option value not equal -{}- : {:?} != {:?}",
668 opt_uid, l, r
669 );
670 }
671 }
672 } else {
673 assert!(
674 vals.is_none(),
675 "found none, option value not equal: {:?}",
676 vals
677 );
678 }
679 if let Some(opt_alias) = opt.alias() {
680 if let Some(alias) = alias {
681 assert_eq!(opt_alias.len(), alias.len());
682 for name in alias {
683 assert!(
684 opt_alias.iter().any(|n| n == name),
685 "alias => {:?} <--> {}",
686 &opt_alias,
687 name,
688 );
689 }
690 }
691 } else {
692 assert!(alias.is_none());
693 }
694 Ok(())
695 }
696
697 fn testing_non_prepolicy() -> Result<(), Error> {
698 let mut policy = AFwdPolicy::default();
699 let mut set = AHCSet::default();
700 let mut inv = AInvoker::default();
701 let args = Args::from([
702 "app",
703 "--copt",
704 "--iopt=63",
705 "--/dopt",
706 "set", "--iopt",
708 "-42",
709 "+eopt",
710 "-/fopt",
711 "8", "16", "average", "--りょう",
715 "88",
716 "--jopt",
717 "2",
718 "--iopt-alias1",
719 "0",
720 "--nopt=8.99",
721 "--hopt",
722 "48",
723 "--qopt=cpp",
724 "--alias-k=4",
725 "-l2.79",
726 "--nopt",
727 "3.12",
728 "--开关",
729 "-olily",
730 "program", "software", "反转", "--值=恍恍惚惚",
734 "--qopt",
735 "rust",
736 "翻转", ]);
738
739 set.validator_mut().add_prefix("+");
741 set.add_opt("--aopt=b")?;
743 set.add_opt("--/bopt=b")?.run()?;
744 set.add_opt("--copt=b!")?.set_action(Action::Cnt);
745 set.add_opt("--/dopt=b!")?.run()?;
746 set.add_opt("--eopt=b")?.add_alias("+eopt").run()?;
747 set.add_opt("--/fopt=b")?.add_alias("-/fopt").run()?;
748
749 set.add_opt("--gopt=i")?.run()?;
751 set.add_opt("--hopt=i!")?.run()?;
752 inv.entry(set.add_opt("--iopt=i")?.add_alias("--iopt-alias1").run()?)
753 .on(|set, ctx| {
754 assert_eq!(
755 set["--hopt"].val::<i64>().ok(),
756 None,
757 "Option can set in any order, not access it in option"
758 );
759 Ok(Some(ctx.value::<i64>()? + 21))
760 });
761
762 set.add_opt("--jopt=u")?.set_force(false).run()?;
764 set.add_opt("--kopt=u")?
765 .set_action(Action::Set)
766 .add_alias("--alias-k")
767 .run()?;
768
769 set.add_opt("--lopt=f!")?.add_alias("-l").run()?;
771 set.add_opt("--mopt=f")?.set_value_t(1.02f64).run()?;
772 set.add_opt("--nopt=f")?.set_action(Action::Set).run()?;
773
774 set.add_opt("--oopt=s!")?.add_alias("-o");
776 set.add_opt("--popt=s")?.run()?;
777 inv.entry(set.add_opt("--qopt=s")?.run()?)
778 .on(|_, ctx| Ok(Some(ctx.value::<String>()?)))
779 .then(
780 |uid: Uid, set: &mut AHCSet, raw: Option<&OsStr>, val: Option<String>| {
781 if let Some(val) = val {
782 set["--popt"].accessor_mut().push(val);
784 if let Some(raw) = raw {
785 set[uid].rawvals_mut()?.push(raw.to_os_string());
786 }
787 Ok(true)
788 } else {
789 Ok(false)
790 }
791 },
792 );
793
794 set.add_opt("--开关=b")?;
796 set.add_opt("--值=s")?;
797 set.add_opt("--りょう=i")?;
798 set.add_opt("test_cmd=c")?;
799
800 let set_uid = set.add_opt("set=c")?.run()?;
801 let bpos_uid = set
802 .add_opt("bpos=p@[2,3]")?
803 .set_pos_type_only::<u64>()
804 .run()?;
805 let cpos_uid = set
806 .add_opt("cpos@4..5".infer::<Pos<String>>())?
807 .set_validator(ValValidator::contains2(vec!["average", "plus"]))
808 .run()?;
809 let dpos_uid = set.add_opt("dpos=p@5..7")?.set_action(Action::Set).run()?;
810 let epos_uid = set.add_opt("epos=p@7..")?.run()?;
811
812 inv.entry(set.add_opt("main=m")?.run()?)
813 .on(move |set, ctx| {
814 let copt = &set["--copt"];
815 let dopt = &set["--/dopt"];
816 let bpos = &set["bpos"];
817 let cpos = &set[cpos_uid];
818 let dpos = &set[dpos_uid];
819 let epos = &set["epos"];
820 let idx = ctx.idx()?;
821 let name = ctx.name()?;
822
823 assert_eq!(idx, 0);
824 assert_eq!(name.map(|v| v.as_ref()), Some("app"));
825 check_opt_val::<String>(
826 epos,
827 epos_uid,
828 "epos",
829 Some(vec!["反转".to_owned(), "翻转".to_owned()]),
830 false,
831 &Action::App,
832 &TypeId::of::<Pos>(),
833 Some(&Index::Range(7, None)),
834 None,
835 )?;
836 check_opt_val::<String>(
837 dpos,
838 dpos_uid,
839 "dpos",
840 Some(vec!["program -- software".to_owned()]),
841 false,
842 &Action::Set,
843 &TypeId::of::<Pos>(),
844 Some(&Index::Range(5, Some(7))),
845 None,
846 )?;
847 check_opt_val(
848 cpos,
849 cpos_uid,
850 "cpos",
851 Some(vec![2.31]),
852 false,
853 &Action::App,
854 &TypeId::of::<Pos<String>>(),
855 Some(&Index::Range(4, Some(5))),
856 None,
857 )?;
858 check_opt_val::<u64>(
859 bpos,
860 bpos_uid,
861 "bpos",
862 Some(vec![32, 64]),
863 false,
864 &Action::App,
865 &TypeId::of::<Pos<u64>>(),
866 Some(&Index::list(vec![2, 3])),
867 None,
868 )?;
869 check_opt_val::<u64>(
870 copt,
871 2,
872 "--copt",
873 Some(vec![1]),
874 true,
875 &Action::Cnt,
876 &TypeId::of::<bool>(),
877 None,
878 None,
879 )?;
880 check_opt_val(
881 dopt,
882 3,
883 "--/dopt",
884 Some(vec![true]),
885 true,
886 &Action::Set,
887 &TypeId::of::<bool>(),
888 None,
889 None,
890 )?;
891 Ok(Some(true))
892 });
893 inv.entry(epos_uid).on(|set, ctx| {
894 let ropt = &set["--开关"];
895 let sopt = &set["--值"];
896 let topt = &set["--りょう"];
897 let idx = ctx.idx()?;
898 let val = ctx.value::<String>()?;
899
900 check_opt_val::<i64>(
901 topt,
902 19,
903 "--りょう",
904 Some(vec![88]),
905 false,
906 &Action::App,
907 &TypeId::of::<i64>(),
908 None,
909 None,
910 )?;
911 check_opt_val::<String>(
912 sopt,
913 18,
914 "--值",
915 Some(vec![String::from("恍恍惚惚")]),
916 false,
917 &Action::App,
918 &TypeId::of::<String>(),
919 None,
920 None,
921 )?;
922 check_opt_val(
923 ropt,
924 17,
925 "--开关",
926 Some(vec![true]),
927 false,
928 &Action::Set,
929 &TypeId::of::<bool>(),
930 None,
931 None,
932 )?;
933 assert!(idx == 7 || idx == 8);
934 Ok(Some(val))
935 });
936 inv.entry(dpos_uid).on(|set, ctx| {
937 let oopt = &set["--oopt"];
938 let popt = &set["--popt"];
939 let qopt = &set["--qopt"];
940 let idx = ctx.idx()?;
941 let val = ctx.value::<String>()?;
942
943 check_opt_val::<String>(
944 qopt,
945 16,
946 "--qopt",
947 None,
948 false,
949 &Action::App,
950 &TypeId::of::<String>(),
951 None,
952 None,
953 )?;
954 check_opt_val(
955 popt,
956 15,
957 "--popt",
958 Some(vec![String::from("cpp"), String::from("rust")]),
959 false,
960 &Action::App,
961 &TypeId::of::<String>(),
962 None,
963 None,
964 )?;
965 check_opt_val(
966 oopt,
967 14,
968 "--oopt",
969 Some(vec![String::from("lily")]),
970 true,
971 &Action::App,
972 &TypeId::of::<String>(),
973 None,
974 Some(vec![("-o")]),
975 )?;
976 assert!(idx == 5 || idx == 6);
977 match set["dpos"].val::<String>() {
978 Ok(last_val) => Ok(Some(format!("{} -- {}", last_val, val))),
979 Err(_) => Ok(Some(val)),
980 }
981 });
982 inv.entry(cpos_uid).on(|set, ctx| {
983 let lopt = &set["--lopt"];
984 let mopt = &set["--mopt"];
985 let nopt = &set["--nopt"];
986 let idx = ctx.idx()?;
987 let val = ctx.value::<String>()?;
988
989 check_opt_val(
990 nopt,
991 13,
992 "--nopt",
993 Some(vec![3.12]),
994 false,
995 &Action::Set,
996 &TypeId::of::<f64>(),
997 None,
998 None,
999 )?;
1000 check_opt_val::<f64>(
1001 mopt,
1002 12,
1003 "--mopt",
1004 Some(vec![1.02]),
1005 false,
1006 &Action::App,
1007 &TypeId::of::<f64>(),
1008 None,
1009 None,
1010 )?;
1011 check_opt_val::<f64>(
1012 lopt,
1013 11,
1014 "--lopt",
1015 Some(vec![2.79]),
1016 true,
1017 &Action::App,
1018 &TypeId::of::<f64>(),
1019 None,
1020 Some(vec![("-l")]),
1021 )?;
1022 assert!(idx == 4);
1023
1024 let mut sum = 0.0;
1025
1026 for uid in [lopt, mopt, nopt].iter().map(|v| v.uid()) {
1027 sum += set[uid].val::<f64>()?;
1028 }
1029
1030 match val.as_str() {
1031 "average" => Ok(Some(sum / 3.0)),
1032 "plus" => Ok(Some(sum)),
1033 _ => Ok(None),
1034 }
1035 });
1036 inv.entry(bpos_uid).on(|set, ctx| {
1037 let jopt = &set["--jopt"];
1038 let kopt = &set["--kopt"];
1039 let idx = ctx.idx()?;
1040 let val = ctx.value::<u64>()?;
1041
1042 check_opt_val::<u64>(
1043 jopt,
1044 9,
1045 "--jopt",
1046 Some(vec![2]),
1047 false,
1048 &Action::App,
1049 &TypeId::of::<u64>(),
1050 None,
1051 None,
1052 )?;
1053 check_opt_val::<u64>(
1054 kopt,
1055 10,
1056 "--kopt",
1057 Some(vec![4]),
1058 false,
1059 &Action::Set,
1060 &TypeId::of::<u64>(),
1061 None,
1062 None,
1063 )?;
1064 assert!(idx == 2 || idx == 3);
1065 Ok(Some(val * set["--alias-k"].val::<u64>()?))
1066 });
1067 inv.entry(set_uid).on(move |set, ctx| {
1068 let uid = ctx.uid()?;
1069 let aopt = &set[0];
1070 let bopt = &set["--/bopt"];
1071 let apos = &set[uid];
1072 let eopt = &set["+eopt"];
1073 let fopt = &set["--/fopt=b"];
1074 let gopt = &set["--gopt"];
1075 let hopt = &set["--hopt"];
1076 let iopt = &set["--iopt"];
1077 let name = ctx.name()?;
1078 let value = ctx.value::<String>()?;
1079
1080 assert_eq!(name.map(|v| v.as_ref()), Some("set"));
1081 check_opt_val::<i64>(
1082 iopt,
1083 8,
1084 "--iopt",
1085 Some(vec![84, -21, 21]),
1086 false,
1087 &Action::App,
1088 &TypeId::of::<i64>(),
1089 None,
1090 Some(vec![("--iopt-alias1")]),
1091 )?;
1092 check_opt_val::<i64>(
1093 hopt,
1094 7,
1095 "--hopt",
1096 Some(vec![48]),
1097 true,
1098 &Action::App,
1099 &TypeId::of::<i64>(),
1100 None,
1101 None,
1102 )?;
1103 check_opt_val::<i64>(
1104 gopt,
1105 6,
1106 "--gopt",
1107 None,
1108 false,
1109 &Action::App,
1110 &TypeId::of::<i64>(),
1111 None,
1112 None,
1113 )?;
1114
1115 check_opt_val(
1116 fopt,
1117 5,
1118 "--/fopt",
1119 Some(vec![true]),
1120 false,
1121 &Action::Set,
1122 &TypeId::of::<bool>(),
1123 None,
1124 Some(vec![("-/fopt")]),
1125 )?;
1126 check_opt_val(
1127 eopt,
1128 4,
1129 "--eopt",
1130 Some(vec![true]),
1131 false,
1132 &Action::Set,
1133 &TypeId::of::<bool>(),
1134 None,
1135 Some(vec![("+eopt")]),
1136 )?;
1137 check_opt_val(
1138 bopt,
1139 1,
1140 "--/bopt",
1141 Some(vec![false]),
1142 false,
1143 &Action::Set,
1144 &TypeId::of::<bool>(),
1145 None,
1146 None,
1147 )?;
1148 check_opt_val(
1149 aopt,
1150 0,
1151 "--aopt",
1152 Some(vec![false]),
1153 false,
1154 &Action::Set,
1155 &TypeId::of::<bool>(),
1156 None,
1157 None,
1158 )?;
1159 check_opt_val::<String>(
1160 apos,
1161 set_uid,
1162 "set",
1163 None,
1164 true,
1165 &Action::Set,
1166 &TypeId::of::<Cmd>(),
1167 Some(&Index::forward(1)),
1168 None,
1169 )?;
1170 Ok(Some(value))
1171 });
1172 for opt in set.iter_mut() {
1173 opt.init()?;
1174 }
1175 policy.parse(&mut set, &mut inv, args)?;
1176 Ok(())
1177 }
1178
1179 fn testing_prepolicy() -> Result<(), Error> {
1180 let mut policy = AFwdPolicy::default().with_prepolicy(true);
1181 let mut set = AHCSet::default();
1182 let mut inv = AInvoker::default();
1183 let args = Args::from([
1184 "app", "--copt",
1186 "--iopt=63",
1187 "--/dopt",
1188 "set", "--iopt",
1190 "-42",
1191 "+eopt",
1192 "-/fopt",
1193 "8", "16", "average", "--りょう",
1197 "88",
1198 "--jopt",
1199 "2",
1200 "--iopt-alias1",
1201 "0",
1202 "--nopt=8.99",
1203 "--hopt",
1204 "48",
1205 "--qopt=cpp",
1206 "--alias-k=4",
1207 "-l2.79",
1208 "--nopt",
1209 "3.12",
1210 "--开关",
1211 "-olily",
1212 "program", "software", "反转", "--值=恍恍惚惚",
1216 "--qopt",
1217 "rust",
1218 "翻转", "left",
1220 "--wopt=98",
1221 "剩余的",
1222 "--ropt=23",
1223 "-r",
1224 "--s我的",
1225 ]);
1226
1227 set.validator_mut().add_prefix("+");
1229 set.add_opt("--aopt=b")?;
1231 set.add_opt("--/bopt=b")?.run()?;
1232 set.add_opt("--copt=b!")?.set_action(Action::Cnt);
1233 set.add_opt("--/dopt=b!")?.run()?;
1234 set.add_opt("--eopt=b")?.add_alias("+eopt").run()?;
1235 set.add_opt("--/fopt=b")?.add_alias("-/fopt").run()?;
1236
1237 set.add_opt("--gopt=i")?.run()?;
1239 set.add_opt("--hopt=i!")?.run()?;
1240 inv.entry(set.add_opt("--iopt=i")?.add_alias("--iopt-alias1").run()?)
1241 .on(|set, ctx| {
1242 assert_eq!(
1243 set["--hopt"].val::<i64>().ok(),
1244 None,
1245 "Option can set in any order, not access it in option"
1246 );
1247 Ok(Some(ctx.value::<i64>()? + 21))
1248 });
1249
1250 set.add_opt("--jopt=u")?.set_force(false).run()?;
1252 set.add_opt("--kopt=u")?
1253 .set_action(Action::Set)
1254 .add_alias("--alias-k")
1255 .run()?;
1256
1257 set.add_opt("--lopt=f!")?.add_alias("-l").run()?;
1259 set.add_opt("--mopt=f")?.set_value_t(1.02f64).run()?;
1260 set.add_opt("--nopt=f")?.set_action(Action::Set).run()?;
1261
1262 set.add_opt("--oopt=s!")?.add_alias("-o");
1264 set.add_opt("--popt=s")?.run()?;
1265 inv.entry(set.add_opt("--qopt=s")?.run()?)
1266 .on(|_, ctx| Ok(Some(ctx.value::<String>()?)))
1267 .then(
1268 |uid: Uid, set: &mut AHCSet, raw: Option<&OsStr>, val: Option<String>| {
1269 if let Some(val) = val {
1270 set["--popt"].accessor_mut().push(val);
1272 if let Some(raw) = raw {
1273 set[uid].rawvals_mut()?.push(raw.to_os_string());
1274 }
1275 Ok(true)
1276 } else {
1277 Ok(false)
1278 }
1279 },
1280 );
1281
1282 set.add_opt("--开关=b")?;
1284 set.add_opt("--值=s")?;
1285 set.add_opt("--りょう=i")?;
1286 set.add_opt("test_cmd=c")?;
1287
1288 let set_uid = set.add_opt("set=c")?.run()?;
1289 let bpos_uid = set
1290 .add_opt("bpos=p@[2,3]")?
1291 .set_pos_type_only::<u64>()
1292 .run()?;
1293 let cpos_uid = set
1294 .add_opt("cpos@4..5".infer::<Pos<String>>())?
1295 .set_validator(ValValidator::contains2(vec!["average", "plus"]))
1296 .run()?;
1297 let dpos_uid = set.add_opt("dpos=p@5..7")?.set_action(Action::Set).run()?;
1298 let epos_uid = set.add_opt("epos=p@7..9")?.run()?;
1299
1300 inv.entry(set.add_opt("main=m")?.run()?)
1301 .on(move |set, ctx| {
1302 let copt = &set["--copt"];
1303 let dopt = &set["--/dopt"];
1304 let bpos = &set["bpos"];
1305 let cpos = &set[cpos_uid];
1306 let dpos = &set[dpos_uid];
1307 let epos = &set["epos"];
1308 let idx = ctx.idx()?;
1309 let name = ctx.name()?;
1310
1311 assert_eq!(idx, 0);
1312 assert_eq!(name.map(|v| v.as_ref()), Some("app"));
1313 check_opt_val::<String>(
1314 epos,
1315 epos_uid,
1316 "epos",
1317 Some(vec!["反转".to_owned(), "翻转".to_owned()]),
1318 false,
1319 &Action::App,
1320 &TypeId::of::<Pos>(),
1321 Some(&Index::Range(7, Some(9))),
1322 None,
1323 )?;
1324 check_opt_val::<String>(
1325 dpos,
1326 dpos_uid,
1327 "dpos",
1328 Some(vec!["program -- software".to_owned()]),
1329 false,
1330 &Action::Set,
1331 &TypeId::of::<Pos>(),
1332 Some(&Index::Range(5, Some(7))),
1333 None,
1334 )?;
1335 check_opt_val(
1336 cpos,
1337 cpos_uid,
1338 "cpos",
1339 Some(vec![2.31]),
1340 false,
1341 &Action::App,
1342 &TypeId::of::<Pos<String>>(),
1343 Some(&Index::Range(4, Some(5))),
1344 None,
1345 )?;
1346 check_opt_val::<u64>(
1347 bpos,
1348 bpos_uid,
1349 "bpos",
1350 Some(vec![32, 64]),
1351 false,
1352 &Action::App,
1353 &TypeId::of::<Pos<u64>>(),
1354 Some(&Index::list(vec![2, 3])),
1355 None,
1356 )?;
1357 check_opt_val::<u64>(
1358 copt,
1359 2,
1360 "--copt",
1361 Some(vec![1]),
1362 true,
1363 &Action::Cnt,
1364 &TypeId::of::<bool>(),
1365 None,
1366 None,
1367 )?;
1368 check_opt_val(
1369 dopt,
1370 3,
1371 "--/dopt",
1372 Some(vec![true]),
1373 true,
1374 &Action::Set,
1375 &TypeId::of::<bool>(),
1376 None,
1377 None,
1378 )?;
1379 Ok(Some(true))
1380 });
1381 inv.entry(epos_uid).on(|set, ctx| {
1382 let ropt = &set["--开关"];
1383 let sopt = &set["--值"];
1384 let topt = &set["--りょう"];
1385 let idx = ctx.idx()?;
1386 let val = ctx.value::<String>()?;
1387
1388 check_opt_val::<i64>(
1389 topt,
1390 19,
1391 "--りょう",
1392 Some(vec![88]),
1393 false,
1394 &Action::App,
1395 &TypeId::of::<i64>(),
1396 None,
1397 None,
1398 )?;
1399 check_opt_val::<String>(
1400 sopt,
1401 18,
1402 "--值",
1403 Some(vec![String::from("恍恍惚惚")]),
1404 false,
1405 &Action::App,
1406 &TypeId::of::<String>(),
1407 None,
1408 None,
1409 )?;
1410 check_opt_val(
1411 ropt,
1412 17,
1413 "--开关",
1414 Some(vec![true]),
1415 false,
1416 &Action::Set,
1417 &TypeId::of::<bool>(),
1418 None,
1419 None,
1420 )?;
1421 assert!(idx == 7 || idx == 8);
1422 Ok(Some(val))
1423 });
1424 inv.entry(dpos_uid).on(|set, ctx| {
1425 let oopt = &set["--oopt"];
1426 let popt = &set["--popt"];
1427 let qopt = &set["--qopt"];
1428 let idx = ctx.idx()?;
1429 let val = ctx.value::<String>()?;
1430
1431 check_opt_val::<String>(
1432 qopt,
1433 16,
1434 "--qopt",
1435 None,
1436 false,
1437 &Action::App,
1438 &TypeId::of::<String>(),
1439 None,
1440 None,
1441 )?;
1442 check_opt_val(
1443 popt,
1444 15,
1445 "--popt",
1446 Some(vec![String::from("cpp"), String::from("rust")]),
1447 false,
1448 &Action::App,
1449 &TypeId::of::<String>(),
1450 None,
1451 None,
1452 )?;
1453 check_opt_val(
1454 oopt,
1455 14,
1456 "--oopt",
1457 Some(vec![String::from("lily")]),
1458 true,
1459 &Action::App,
1460 &TypeId::of::<String>(),
1461 None,
1462 Some(vec![("-o")]),
1463 )?;
1464 assert!(idx == 5 || idx == 6);
1465 match set["dpos"].val::<String>() {
1466 Ok(last_val) => Ok(Some(format!("{} -- {}", last_val, val))),
1467 Err(_) => Ok(Some(val)),
1468 }
1469 });
1470 inv.entry(cpos_uid).on(|set, ctx| {
1471 let lopt = &set["--lopt"];
1472 let mopt = &set["--mopt"];
1473 let nopt = &set["--nopt"];
1474 let idx = ctx.idx()?;
1475 let val = ctx.value::<String>()?;
1476
1477 check_opt_val(
1478 nopt,
1479 13,
1480 "--nopt",
1481 Some(vec![3.12]),
1482 false,
1483 &Action::Set,
1484 &TypeId::of::<f64>(),
1485 None,
1486 None,
1487 )?;
1488 check_opt_val::<f64>(
1489 mopt,
1490 12,
1491 "--mopt",
1492 Some(vec![1.02]),
1493 false,
1494 &Action::App,
1495 &TypeId::of::<f64>(),
1496 None,
1497 None,
1498 )?;
1499 check_opt_val::<f64>(
1500 lopt,
1501 11,
1502 "--lopt",
1503 Some(vec![2.79]),
1504 true,
1505 &Action::App,
1506 &TypeId::of::<f64>(),
1507 None,
1508 Some(vec![("-l")]),
1509 )?;
1510 assert!(idx == 4);
1511
1512 let mut sum = 0.0;
1513
1514 for uid in [lopt, mopt, nopt].iter().map(|v| v.uid()) {
1515 sum += set[uid].val::<f64>()?;
1516 }
1517
1518 match val.as_str() {
1519 "average" => Ok(Some(sum / 3.0)),
1520 "plus" => Ok(Some(sum)),
1521 _ => Ok(None),
1522 }
1523 });
1524 inv.entry(bpos_uid).on(|set, ctx| {
1525 let jopt = &set["--jopt"];
1526 let kopt = &set["--kopt"];
1527 let idx = ctx.idx()?;
1528 let val = ctx.value::<u64>()?;
1529
1530 check_opt_val::<u64>(
1531 jopt,
1532 9,
1533 "--jopt",
1534 Some(vec![2]),
1535 false,
1536 &Action::App,
1537 &TypeId::of::<u64>(),
1538 None,
1539 None,
1540 )?;
1541 check_opt_val::<u64>(
1542 kopt,
1543 10,
1544 "--kopt",
1545 Some(vec![4]),
1546 false,
1547 &Action::Set,
1548 &TypeId::of::<u64>(),
1549 None,
1550 None,
1551 )?;
1552 assert!(idx == 2 || idx == 3);
1553 Ok(Some(val * set["--alias-k"].val::<u64>()?))
1554 });
1555 inv.entry(set_uid).on(move |set, ctx| {
1556 let uid = ctx.uid()?;
1557 let aopt = &set[0];
1558 let bopt = &set["--/bopt"];
1559 let apos = &set[uid];
1560 let eopt = &set["+eopt"];
1561 let fopt = &set["--/fopt=b"];
1562 let gopt = &set["--gopt"];
1563 let hopt = &set["--hopt"];
1564 let iopt = &set["--iopt"];
1565 let name = ctx.name()?;
1566 let value = ctx.value::<String>()?;
1567
1568 assert_eq!(name.map(|v| v.as_ref()), Some("set"));
1569 check_opt_val::<i64>(
1570 iopt,
1571 8,
1572 "--iopt",
1573 Some(vec![84, -21, 21]),
1574 false,
1575 &Action::App,
1576 &TypeId::of::<i64>(),
1577 None,
1578 Some(vec![("--iopt-alias1")]),
1579 )?;
1580 check_opt_val::<i64>(
1581 hopt,
1582 7,
1583 "--hopt",
1584 Some(vec![48]),
1585 true,
1586 &Action::App,
1587 &TypeId::of::<i64>(),
1588 None,
1589 None,
1590 )?;
1591 check_opt_val::<i64>(
1592 gopt,
1593 6,
1594 "--gopt",
1595 None,
1596 false,
1597 &Action::App,
1598 &TypeId::of::<i64>(),
1599 None,
1600 None,
1601 )?;
1602
1603 check_opt_val(
1604 fopt,
1605 5,
1606 "--/fopt",
1607 Some(vec![true]),
1608 false,
1609 &Action::Set,
1610 &TypeId::of::<bool>(),
1611 None,
1612 Some(vec![("-/fopt")]),
1613 )?;
1614 check_opt_val(
1615 eopt,
1616 4,
1617 "--eopt",
1618 Some(vec![true]),
1619 false,
1620 &Action::Set,
1621 &TypeId::of::<bool>(),
1622 None,
1623 Some(vec![("+eopt")]),
1624 )?;
1625 check_opt_val(
1626 bopt,
1627 1,
1628 "--/bopt",
1629 Some(vec![false]),
1630 false,
1631 &Action::Set,
1632 &TypeId::of::<bool>(),
1633 None,
1634 None,
1635 )?;
1636 check_opt_val(
1637 aopt,
1638 0,
1639 "--aopt",
1640 Some(vec![false]),
1641 false,
1642 &Action::Set,
1643 &TypeId::of::<bool>(),
1644 None,
1645 None,
1646 )?;
1647 check_opt_val::<bool>(
1648 apos,
1649 set_uid,
1650 "set",
1651 None,
1652 true,
1653 &Action::Set,
1654 &TypeId::of::<Cmd>(),
1655 Some(&Index::forward(1)),
1656 None,
1657 )?;
1658 Ok(Some(value))
1659 });
1660 for opt in set.iter_mut() {
1661 opt.init()?;
1662 }
1663 let ret = policy.parse(&mut set, &mut inv, args.clone());
1664
1665 assert!(ret.is_ok());
1666 let ret = ret.unwrap();
1667 let args = ret.args();
1668
1669 for (idx, arg) in [
1670 "app",
1671 "set",
1672 "8",
1673 "16",
1674 "average",
1675 "program",
1676 "software",
1677 "反转",
1678 "翻转",
1679 "left",
1680 "--wopt=98",
1681 "剩余的",
1682 "--ropt=23",
1683 "-r",
1684 "--s我的",
1685 ]
1686 .iter()
1687 .enumerate()
1688 {
1689 assert_eq!(args[idx], OsStr::new(arg));
1690 }
1691 Ok(())
1692 }
1693}