Skip to main content

facet_args/
lib.rs

1#![warn(missing_docs)]
2#![warn(clippy::std_instead_of_core)]
3#![warn(clippy::std_instead_of_alloc)]
4#![deny(unsafe_code)]
5#![doc = include_str!("../README.md")]
6
7extern crate alloc;
8
9pub mod completions;
10mod format;
11pub mod help;
12
13pub(crate) mod arg;
14pub(crate) mod error;
15pub(crate) mod span;
16
17pub use completions::{Shell, generate_completions, generate_completions_for_shape};
18pub use error::{ArgsErrorKind, ArgsErrorWithInput};
19pub use format::from_slice;
20pub use format::from_slice_with_config;
21pub use format::from_std_args;
22pub use help::{HelpConfig, generate_help, generate_help_for_shape};
23
24// Args extension attributes for use with #[facet(args::attr)] syntax.
25//
26// After importing `use facet_args as args;`, users can write:
27//   #[facet(args::positional)]
28//   #[facet(args::short = 'v')]
29//   #[facet(args::named)]
30
31// Generate args attribute grammar using the grammar DSL.
32// This generates:
33// - `Attr` enum with all args attribute variants
34// - `__attr!` macro that dispatches to attribute handlers and returns ExtensionAttr
35// - `__parse_attr!` macro for parsing (internal use)
36facet::define_attr_grammar! {
37    ns "args";
38    crate_path ::facet_args;
39
40    /// Args attribute types for field configuration.
41    pub enum Attr {
42        /// Marks a field as a positional argument.
43        ///
44        /// Usage: `#[facet(args::positional)]`
45        Positional,
46        /// Marks a field as a named argument.
47        ///
48        /// Usage: `#[facet(args::named)]`
49        Named,
50        /// Specifies a short flag character for the field.
51        ///
52        /// Usage: `#[facet(args::short = 'v')]` or just `#[facet(args::short)]`
53        Short(Option<char>),
54        /// Marks a field as a subcommand.
55        ///
56        /// The field type must be an enum where each variant represents a subcommand.
57        /// Variant names are converted to kebab-case for matching.
58        ///
59        /// Usage: `#[facet(args::subcommand)]`
60        Subcommand,
61        /// Marks a field as a counted flag.
62        ///
63        /// Each occurrence of the flag increments the count. Works with both short
64        /// flags (`-vvv` or `-v -v -v`) and long flags (`--verbose --verbose`).
65        /// The field type must be an integer type (u8, u16, u32, u64, usize, i8, i16, i32, i64, isize).
66        /// Uses saturating arithmetic to avoid overflow.
67        ///
68        /// Usage: `#[facet(args::named, args::short = 'v', args::counted)]`
69        Counted,
70    }
71}
72
73/// Check if a field is marked with `args::counted`.
74pub fn is_counted_field(field: &facet_core::Field) -> bool {
75    field.has_attr(Some("args"), "counted")
76}
77
78/// Check if a shape is a supported type for counted fields (integer types).
79pub const fn is_supported_counted_type(shape: &'static facet_core::Shape) -> bool {
80    use facet_core::{NumericType, PrimitiveType, Type};
81    matches!(
82        shape.ty,
83        Type::Primitive(PrimitiveType::Numeric(NumericType::Integer { .. }))
84    )
85}