duat_core/cmd/
parameters.rs

1//! Defines the processing of parameters in commands
2//!
3//! This processing first separates the [`Flags`] and [`Args`] of the
4//! call, and then transforms the list of arguments into a list of
5//! [`Parameter`]s, as defined by the command. Each [`Parameter`] may
6//! take multiple words, which makes this structure very flexible for
7//! multiple branching paths on how to read the arguments, all from
8//! the same command.
9use std::{iter::Peekable, marker::PhantomData, ops::Range, path::PathBuf};
10
11use crossterm::style::Color;
12
13use crate::{
14    buffer::Buffer,
15    context::Handle,
16    data::Pass,
17    form::{self, FormId},
18    text::{Text, txt},
19};
20
21/// A parameter for commands that can be called
22///
23/// This parameter must be parseable from [`Args`], which come from a
24/// `&str`. It can take multiple words, and can be composed of other
25/// [`Parameter`]s. An example of this is the [`Form`], which is
26/// composed of multiple [`Color`] parameters, which are then composed
27/// of some format (rgb, hsl), which is then composed of more
28/// parameters, like rgb values, for example.
29///
30/// Other types of [`Parameter`] are just a "list" of other
31/// [`Parameter`]s. For example, [`Vec<P>`] can be used as a
32/// [`Parameter`] to capture any number of `P` arguments.
33/// Additionally, there is the [`Between<MIN, MAX, P>`], which is
34/// _like_ [`Vec<P>`], but takes at least `MIN` `P`s and at most `MAX`
35/// `P`s.
36///
37/// [`Form`]: crate::form::Form
38pub trait Parameter<'a>: Sized {
39    /// The type that is returned
40    type Returns;
41    /// Tries to consume arguments until forming a parameter
42    ///
43    /// Since parameters shouldn't mutate data, pa is just a regular
44    /// shared reference.
45    fn new(pa: &Pass, args: &mut Args<'a>) -> Result<(Self::Returns, Option<FormId>), Text>;
46}
47
48impl<'a, P: Parameter<'a>> Parameter<'a> for Option<P> {
49    type Returns = Option<P::Returns>;
50
51    /// Will match either [`Parameter`] given, or nothing
52    ///
53    /// This, like other lists, _has_ to be the final argument in the
54    /// [`Parameter`] list, as it will either match correcly, finish
55    /// matching, or match incorrectly in order to give accurate
56    /// feedback.
57    fn new(pa: &Pass, args: &mut Args<'a>) -> Result<(Self::Returns, Option<FormId>), Text> {
58        match args.next_as::<P>(pa) {
59            Ok(arg) => Ok((Some(arg), None)),
60            Err(err) if args.is_forming_param => Err(err),
61            Err(_) => Ok((None, None)),
62        }
63    }
64}
65
66impl<'a, P: Parameter<'a>> Parameter<'a> for Vec<P> {
67    type Returns = Vec<P::Returns>;
68
69    /// Will match a list of [`Parameter`]s
70    ///
71    /// This, like other lists, _has_ to be the final argument in the
72    /// [`Parameter`] list, as it will either match correcly, finish
73    /// matching, or match incorrectly in order to give accurate
74    /// feedback.
75    fn new(pa: &Pass, args: &mut Args<'a>) -> Result<(Self::Returns, Option<FormId>), Text> {
76        let mut returns = Vec::new();
77
78        loop {
79            match args.next_as::<P>(pa) {
80                Ok(ret) => returns.push(ret),
81                Err(err) if args.is_forming_param => return Err(err),
82                Err(_) => break Ok((returns, None)),
83            }
84        }
85    }
86}
87
88impl<'a, const N: usize, P: Parameter<'a>> Parameter<'a> for [P; N] {
89    type Returns = [P::Returns; N];
90
91    /// Will match either the argument given, or nothing
92    ///
93    /// This, like other lists, _has_ to be the final argument in the
94    /// [`Parameter`] list, as it will either match correcly, finish
95    /// matching, or match incorrectly in order to give accurate
96    /// feedback.
97    fn new(pa: &Pass, args: &mut Args<'a>) -> Result<(Self::Returns, Option<FormId>), Text> {
98        use std::mem::MaybeUninit;
99        let mut returns = [const { MaybeUninit::uninit() }; N];
100
101        for r in returns.iter_mut() {
102            match args.next_as::<P>(pa) {
103                Ok(ret) => *r = MaybeUninit::new(ret),
104                Err(err) => return Err(err),
105            }
106        }
107
108        Ok((returns.map(|ret| unsafe { ret.assume_init() }), None))
109    }
110}
111
112/// Command [`Parameter`]: A list of between `MIN` and `MAX` items
113///
114/// This, like other lists, _has_ to be the final argument in the
115/// [`Parameter`] list, as it will either match correcly, finish
116/// matching, or match incorrectly in order to give accurate
117/// feedback.
118pub struct Between<const MIN: usize, const MAX: usize, P>(PhantomData<P>);
119
120impl<'a, const MIN: usize, const MAX: usize, P: Parameter<'a>> Parameter<'a>
121    for Between<MIN, MAX, P>
122{
123    type Returns = Vec<P::Returns>;
124
125    /// Will match between `MIN` and `MAX` [`Parameter`]s
126    ///
127    /// This, like other lists, _has_ to be the final argument in the
128    /// [`Parameter`] list, as it will either match correcly, finish
129    /// matching, or match incorrectly in order to give accurate
130    /// feedback.
131    fn new(pa: &Pass, args: &mut Args<'a>) -> Result<(Self::Returns, Option<FormId>), Text> {
132        let mut returns = Vec::new();
133
134        for _ in 0..MAX {
135            match args.next_as::<P>(pa) {
136                Ok(ret) => returns.push(ret),
137                Err(err) if args.is_forming_param => return Err(err),
138                Err(_) if returns.len() >= MIN => return Ok((returns, None)),
139                Err(err) => return Err(err),
140            }
141        }
142
143        if returns.len() >= MIN {
144            Ok((returns, None))
145        } else {
146            Err(txt!(
147                "List needed at least [a]{MIN}[] elements, got only [a]{}",
148                returns.len()
149            ))
150        }
151    }
152}
153
154impl<'a> Parameter<'a> for &'a str {
155    type Returns = &'a str;
156
157    fn new(_: &Pass, args: &mut Args<'a>) -> Result<(Self::Returns, Option<FormId>), Text> {
158        args.next().map(|arg| (arg, None))
159    }
160}
161
162impl Parameter<'_> for String {
163    type Returns = String;
164
165    fn new(_: &Pass, args: &mut Args) -> Result<(Self::Returns, Option<FormId>), Text> {
166        Ok((args.next()?.to_string(), None))
167    }
168}
169
170/// Command [`Parameter`]: The remaining arguments, divided by a space
171///
172/// Fails if the [`String`] would be empty.
173pub struct Remainder;
174
175impl Parameter<'_> for Remainder {
176    type Returns = String;
177
178    fn new(_: &Pass, args: &mut Args) -> Result<(Self::Returns, Option<FormId>), Text> {
179        let remainder: String = std::iter::from_fn(|| args.next().ok())
180            .collect::<Vec<&str>>()
181            .join(" ");
182        if remainder.is_empty() {
183            Err(txt!("There are no more arguments"))
184        } else {
185            Ok((remainder, None))
186        }
187    }
188}
189
190/// Command [`Parameter`]: An existing [`ColorScheme`]'s name
191///
192/// [`ColorScheme`]: crate::form::ColorScheme
193pub struct ColorSchemeArg;
194
195impl<'a> Parameter<'a> for ColorSchemeArg {
196    type Returns = &'a str;
197
198    fn new(_: &Pass, args: &mut Args<'a>) -> Result<(Self::Returns, Option<FormId>), Text> {
199        let scheme = args.next()?;
200        if crate::form::colorscheme_exists(scheme) {
201            Ok((scheme, None))
202        } else {
203            Err(txt!("The colorscheme [a]{scheme}[] was not found"))
204        }
205    }
206}
207
208impl<'a> Parameter<'a> for Buffer {
209    type Returns = Handle;
210
211    fn new(pa: &Pass, args: &mut Args<'a>) -> Result<(Self::Returns, Option<FormId>), Text> {
212        let buffer_name = args.next()?;
213        if let Some(handle) = crate::context::windows()
214            .buffers(pa)
215            .find(|handle| handle.read(pa).name() == buffer_name)
216        {
217            Ok((handle, Some(form::id_of!("param.buffer.open"))))
218        } else {
219            Err(txt!("No buffer called [a]{buffer_name}[] open"))
220        }
221    }
222}
223
224/// Command [`Parameter`]: An open [`Buffer`]'s name, except the
225/// current
226///
227/// [`Buffer`]: crate::buffer::Buffer
228pub struct OtherBuffer;
229
230impl<'a> Parameter<'a> for OtherBuffer {
231    type Returns = Handle;
232
233    fn new(pa: &Pass, args: &mut Args<'a>) -> Result<(Self::Returns, Option<FormId>), Text> {
234        let handle = args.next_as::<Buffer>(pa)?;
235        let cur_handle = crate::context::current_buffer(pa);
236        if *cur_handle == handle {
237            Err(txt!("Argument can't be the current buffer"))
238        } else {
239            Ok((handle, Some(form::id_of!("param.buffer.open"))))
240        }
241    }
242}
243
244/// Command [`Parameter`]: A [`Buffer`] whose parent is real
245///
246/// [`Buffer`]: crate::buffer::Buffer
247pub struct ValidBuffer;
248
249impl Parameter<'_> for ValidBuffer {
250    type Returns = PathBuf;
251
252    fn new(pa: &Pass, args: &mut Args) -> Result<(Self::Returns, Option<FormId>), Text> {
253        let path = args.next_as::<PathBuf>(pa)?;
254
255        let canon_path = path.canonicalize();
256        let path = if let Ok(path) = &canon_path {
257            if !path.is_file() {
258                return Err(txt!("Path is not a buffer"));
259            }
260            path.clone()
261        } else if canon_path.is_err()
262            && let Ok(canon_path) = path.with_file_name(".").canonicalize()
263        {
264            canon_path.join(
265                path.file_name()
266                    .ok_or_else(|| txt!("Path has no buffer name"))?,
267            )
268        } else {
269            return Err(txt!("Path was not found"));
270        };
271
272        if let Some(parent) = path.parent()
273            && let Ok(false) | Err(_) = parent.try_exists()
274        {
275            return Err(txt!("Path's parent doesn't exist"));
276        }
277
278        let form = if crate::context::windows()
279            .buffers(pa)
280            .map(|handle| handle.read(pa).path())
281            .any(|p| std::path::Path::new(&p) == path)
282        {
283            form::id_of!("param.buffer.open")
284        } else if let Ok(true) = path.try_exists() {
285            form::id_of!("param.buffer.exists")
286        } else {
287            form::id_of!("param.buffer")
288        };
289
290        Ok((path, Some(form)))
291    }
292}
293
294/// A [`ValidBuffer`] or `--opts` or `--opts-manifest`
295pub(super) enum PathOrBufferOrCfg {
296    Path(PathBuf),
297    Buffer(Handle),
298    Cfg,
299    CfgManifest,
300}
301
302impl Parameter<'_> for PathOrBufferOrCfg {
303    type Returns = Self;
304
305    fn new(pa: &Pass, args: &mut Args<'_>) -> Result<(Self::Returns, Option<FormId>), Text> {
306        if args.flags.word("cfg") {
307            Ok((Self::Cfg, None))
308        } else if args.flags.word("cfg-manifest") {
309            Ok((Self::CfgManifest, None))
310        } else if let Ok((handle, form)) = args.next_as_with_form::<Buffer>(pa) {
311            Ok((Self::Buffer(handle), form))
312        } else {
313            let (path, form) = args.next_as_with_form::<ValidBuffer>(pa)?;
314            Ok((Self::Path(path), form))
315        }
316    }
317}
318
319/// Command [`Parameter`]: An [`f32`] from a [`u8`] or a percentage
320///
321/// The percentage is of whole divisions of 100, 100 being equivalent
322/// to 255 in [`u8`].
323pub struct F32PercentOfU8;
324
325impl Parameter<'_> for F32PercentOfU8 {
326    type Returns = f32;
327
328    fn new(_: &Pass, args: &mut Args) -> Result<(Self::Returns, Option<FormId>), Text> {
329        let arg = args.next()?;
330        if let Some(percentage) = arg.strip_suffix("%") {
331            let percentage: u8 = percentage
332                .parse()
333                .map_err(|_| txt!("[a]{arg}[] is not a valid percentage"))?;
334            if percentage <= 100 {
335                Ok((percentage as f32 / 100.0, None))
336            } else {
337                Err(txt!("[a]{arg}[] is more than [a]100%"))
338            }
339        } else {
340            let byte: u8 = arg
341                .parse()
342                .map_err(|_| txt!("[a]{arg}[] couldn't be parsed"))?;
343            Ok((byte as f32 / 255.0, None))
344        }
345    }
346}
347
348impl<'a> Parameter<'a> for Color {
349    type Returns = Color;
350
351    fn new(pa: &Pass, args: &mut Args<'a>) -> Result<(Self::Returns, Option<FormId>), Text> {
352        const fn hue_to_rgb(p: f32, q: f32, mut t: f32) -> f32 {
353            t = if t < 0.0 { t + 1.0 } else { t };
354            t = if t > 1.0 { t - 1.0 } else { t };
355            if t < 1.0 / 6.0 {
356                p + (q - p) * 6.0 * t
357            } else if t < 1.0 / 2.0 {
358                q
359            } else if t < 2.0 / 3.0 {
360                p + (q - p) * (2.0 / 3.0 - t) * 6.0
361            } else {
362                p
363            }
364        }
365
366        let arg = args.next()?;
367        // Expects "#{red:x}{green:x}{blue:x}"
368        if let Some(hex) = arg.strip_prefix("#") {
369            let total = match u32::from_str_radix(hex, 16) {
370                Ok(total) if hex.len() == 6 => total,
371                _ => return Err(txt!("Hexcode does not contain 6 hex values")),
372            };
373            let r = (total >> 16) as u8;
374            let g = (total >> 8) as u8;
375            let b = total as u8;
376            Ok((Color::Rgb { r, g, b }, None))
377            // Expects "rgb {red} {green} {blue}"
378        } else if arg == "rgb" {
379            let r = args.next_as::<u8>(pa)?;
380            let g = args.next_as::<u8>(pa)?;
381            let b = args.next_as::<u8>(pa)?;
382            Ok((Color::Rgb { r, g, b }, None))
383            // Expects "hsl {hue%?} {saturation%?} {lightness%?}"
384        } else if arg == "hsl" {
385            let hue = args.next_as::<F32PercentOfU8>(pa)?;
386            let sat = args.next_as::<F32PercentOfU8>(pa)?;
387            let lit = args.next_as::<F32PercentOfU8>(pa)?;
388            let [r, g, b] = if sat == 0.0 {
389                [lit.round() as u8; 3]
390            } else {
391                let q = if lit < 0.5 {
392                    lit * (1.0 + sat)
393                } else {
394                    lit + sat - lit * sat
395                };
396                let p = 2.0 * lit - q;
397                let r = hue_to_rgb(p, q, hue + 1.0 / 3.0);
398                let g = hue_to_rgb(p, q, hue);
399                let b = hue_to_rgb(p, q, hue - 1.0 / 3.0);
400                [r.round() as u8, g.round() as u8, b.round() as u8]
401            };
402            Ok((Color::Rgb { r, g, b }, None))
403        } else {
404            Err(txt!("Color format was not recognized"))
405        }
406    }
407}
408
409/// Command [`Parameter`]: The name of a [`Form`] that has been [set]
410///
411/// [set]: crate::form::set
412/// [`Form`]: crate::form::Form
413pub struct FormName;
414
415impl<'a> Parameter<'a> for FormName {
416    type Returns = &'a str;
417
418    fn new(_: &Pass, args: &mut Args<'a>) -> Result<(Self::Returns, Option<FormId>), Text> {
419        let arg = args.next()?;
420        if !arg.chars().all(|c| c.is_ascii_alphanumeric() || c == '.') {
421            return Err(txt!(
422                "Expected identifiers separated by '.'s, found [a]{arg}"
423            ));
424        }
425        if crate::form::exists(arg) {
426            Ok((arg, Some(form::id_of_non_static(arg))))
427        } else {
428            Err(txt!("The form [a]{arg}[] has not been set"))
429        }
430    }
431}
432
433impl<'a> Parameter<'a> for Flags<'a> {
434    type Returns = Flags<'a>;
435
436    fn new(_: &Pass, args: &mut Args<'a>) -> Result<(Self::Returns, Option<FormId>), Text> {
437        Ok((args.flags.clone(), None))
438    }
439}
440
441/// The list of arguments passed to a command
442///
443/// This list excludes [`Flags`], and separates arguments either by
444/// whitespace, or by non escaped double quotes.
445///
446/// ```rust
447/// # use duat_core::cmd;
448/// # fn test() {
449/// //                    cmd │      flags      │         arguments
450/// //                   ┌   ┐│┌               ┐│┌  ┐ ┌        ┐ ┌   ┐ ┌   ┐
451/// cmd::queue_notify(r#"mycmd --flags -moreflag arg1 "more arg" \"arg arg\""#);
452/// # }
453/// ```
454pub struct Args<'a> {
455    args: Peekable<ArgsIter<'a>>,
456    param_range: Range<usize>,
457    has_to_start_param: bool,
458    is_forming_param: bool,
459    flags: Flags<'a>,
460}
461
462impl<'a> Args<'a> {
463    /// Returns the next word or quoted argument
464    #[allow(clippy::should_implement_trait)]
465    pub fn next(&mut self) -> Result<&'a str, Text> {
466        match self.args.next() {
467            Some((arg, range)) => {
468                self.param_range = range.clone();
469                if self.has_to_start_param {
470                    self.has_to_start_param = false;
471                    self.is_forming_param = true;
472                }
473                Ok(arg)
474            }
475            None => Err(txt!("Wrong argument count")),
476        }
477    }
478
479    /// Tries to parse the next argument as `P`
480    ///
481    /// If parsing fails, [`Args`] will be reset as if this function
482    /// wasn't called.
483    pub fn next_as<P: Parameter<'a>>(&mut self, pa: &Pass) -> Result<P::Returns, Text> {
484        let initial_args = self.args.clone();
485        self.has_to_start_param = true;
486        let ret = P::new(pa, self);
487        if ret.is_ok() {
488            self.is_forming_param = false;
489        } else {
490            self.args = initial_args
491        }
492        ret.map(|(arg, _)| arg)
493    }
494
495    /// Tries to parse the next argument as `P`
496    ///
497    /// If parsing fails, [`Args`] will be reset as if this function
498    /// wasn't called.
499    pub fn next_as_with_form<P: Parameter<'a>>(
500        &mut self,
501        pa: &Pass,
502    ) -> Result<(P::Returns, Option<FormId>), Text> {
503        let initial_args = self.args.clone();
504        self.has_to_start_param = true;
505        let ret = P::new(pa, self);
506        if ret.is_ok() {
507            self.is_forming_param = false;
508        } else {
509            self.args = initial_args
510        }
511        ret
512    }
513
514    /// Tries to get the next argument, otherwise returns a [`Text`]
515    pub fn next_else<T: Into<Text>>(&mut self, to_text: T) -> Result<&'a str, Text> {
516        match self.args.next() {
517            Some((arg, _)) => Ok(arg),
518            None => Err(to_text.into()),
519        }
520    }
521
522    /// Returns the char position of the next argument
523    ///
524    /// Mostly used for error feedback by the [`PromptLine`]
525    ///
526    /// [`PromptLine`]: docs.rs/duat/latest/duat/widgets/struct.PromptLine.html
527    pub fn next_start(&mut self) -> Option<usize> {
528        self.args.peek().map(|(_, r)| r.start)
529    }
530
531    /// The range of the previous [`Parameter`]
532    ///
533    /// Mostly used for error feedback by the [`PromptLine`]
534    ///
535    /// [`PromptLine`]: docs.rs/duat/latest/duat/widgets/struct.PromptLine.html
536    pub fn param_range(&self) -> Range<usize> {
537        self.param_range.clone()
538    }
539
540    /// A private [`Clone`]
541    pub(super) fn clone(&self) -> Self {
542        Self {
543            args: self.args.clone(),
544            param_range: self.param_range.clone(),
545            has_to_start_param: self.has_to_start_param,
546            is_forming_param: self.is_forming_param,
547            flags: self.flags.clone(),
548        }
549    }
550}
551
552/// The flags passed to a command
553///
554/// They work just like flags on regular Linux commands, i.e., you
555/// have word flags, like `"--global"`, and glob flags, like `"-aBc"`.
556#[derive(Clone)]
557pub struct Flags<'a> {
558    blob: String,
559    word: Vec<&'a str>,
560}
561
562impl Flags<'_> {
563    /// Checks if all of the [`char`]s in the `blob` passed.
564    pub fn blob(&self, blob: impl AsRef<str>) -> bool {
565        let mut all_chars = true;
566        for char in blob.as_ref().chars() {
567            all_chars &= self.blob.contains(char);
568        }
569        all_chars
570    }
571
572    /// Returns `true` if the `word` flag was passed.
573    pub fn word(&self, flag: impl AsRef<str>) -> bool {
574        self.word.contains(&flag.as_ref())
575    }
576
577    /// Returns `true` if no flags have been passed.
578    pub fn is_empty(&self) -> bool {
579        self.blob.is_empty() && self.word.is_empty()
580    }
581}
582
583/// Splits a command into [`Args`] and [`Flags`]
584///
585/// [`Args`]: super::Args
586/// [`Flags`]: super::Flags
587pub fn get_args(command: &str) -> super::Args<'_> {
588    let mut blob = String::new();
589    let mut word = Vec::new();
590
591    let args = ArgsIter::new(command);
592    let mut args = args.peekable();
593    let mut byte = 0;
594
595    while let Some((arg, range)) = args.peek() {
596        if let Some(word_arg) = arg.strip_prefix("--") {
597            if !word_arg.is_empty() {
598                args.next();
599                if !word.contains(&word_arg) {
600                    word.push(word_arg)
601                }
602            } else {
603                args.next();
604                break;
605            }
606        } else if let Some(blob_arg) = arg.strip_prefix('-') {
607            args.next();
608            for char in blob_arg.chars() {
609                if !blob.contains(char) {
610                    blob.push(char)
611                }
612            }
613        } else {
614            byte = range.start;
615            break;
616        }
617    }
618
619    super::Args {
620        args,
621        param_range: byte..byte,
622        has_to_start_param: false,
623        is_forming_param: false,
624        flags: super::Flags { blob, word },
625    }
626}
627
628/// A iterator over arguments in a `&str`, useful for the [`cmd`]
629/// module
630///
631/// [`cmd`]: super
632#[derive(Clone)]
633pub struct ArgsIter<'a> {
634    command: &'a str,
635    chars: std::str::CharIndices<'a>,
636    start: Option<usize>,
637    end: Option<usize>,
638    is_quoting: bool,
639    last_char: char,
640}
641
642impl<'a> ArgsIter<'a> {
643    /// Returns a new iterator over arguments in a `&str`
644    pub fn new(command: &'a str) -> Self {
645        let mut args_iter = Self {
646            command,
647            chars: command.char_indices(),
648            start: None,
649            end: None,
650            is_quoting: false,
651            // Initial value doesn't matter, as long as it's not '\'
652            last_char: 'a',
653        };
654
655        args_iter.next();
656        args_iter
657    }
658}
659
660impl<'a> Iterator for ArgsIter<'a> {
661    type Item = (&'a str, Range<usize>);
662
663    fn next(&mut self) -> Option<Self::Item> {
664        while let Some((b, char)) = self.chars.next() {
665            let lc = self.last_char;
666            self.last_char = char;
667            if self.start.is_some() && char.is_whitespace() && !self.is_quoting {
668                self.end = Some(b);
669                break;
670            } else if char == '"' && lc != '\\' {
671                self.is_quoting = !self.is_quoting;
672                if !self.is_quoting {
673                    self.end = Some(b + 1);
674                    break;
675                } else {
676                    self.start = Some(b);
677                }
678            } else if !char.is_whitespace() && self.start.is_none() {
679                self.start = Some(b);
680            }
681        }
682
683        let e = self.end.take().unwrap_or(self.command.len());
684        self.start.take().map(|s| (&self.command[s..e], s..e))
685    }
686}
687
688macro_rules! parse_impl {
689    ($t:ty) => {
690        impl Parameter<'_> for $t {
691            type Returns = Self;
692
693            fn new(_: &Pass, args: &mut Args) -> Result<(Self::Returns, Option<FormId>), Text> {
694                let arg = args.next()?;
695                let arg = arg
696                    .parse()
697                    .map_err(|_| txt!("[a]{arg}[] couldn't be parsed as [a]{}[]", stringify!($t)));
698                arg.map(|arg| (arg, None))
699            }
700        }
701    };
702}
703
704parse_impl!(bool);
705parse_impl!(u8);
706parse_impl!(u16);
707parse_impl!(u32);
708parse_impl!(u64);
709parse_impl!(u128);
710parse_impl!(usize);
711parse_impl!(i8);
712parse_impl!(i16);
713parse_impl!(i32);
714parse_impl!(i64);
715parse_impl!(i128);
716parse_impl!(isize);
717parse_impl!(f32);
718parse_impl!(f64);
719parse_impl!(std::path::PathBuf);