kmdparse/lib.rs
1#![doc(html_root_url = "https://docs.rs/kmdparse/0.0.2")]
2#![warn(missing_docs)]
3#![no_std]
4#![cfg_attr(docsrs, feature(doc_cfg))]
5
6//! `kmdparse` is, as the name suggests, parses user commands into arbitrary Rust types,
7//! including in a `no-std` environment.
8//!
9//! Generally, this crate can be viewed as a data deserialization framework. It defines a syntax
10//! designed to be easy to entered interactively and includes utilities for transforming the input
11//! in this format into arbitrary Rust types, as well as automatically suggesting completions for
12//! incomplete user input.
13//!
14//! It is not suitable for parsing command line arguments, even though the syntax it supports is
15//! fairly similar to what those would look like. Instead, it was designed to be used for parsing
16//! commands entered interactively inside the application. Of course, you are not limited to this
17//! use case and free to use `kmdparse` as a generic data deserialization framework in any way
18//! you like.
19//!
20//! # Examples
21//!
22//! Let’s consider the following example. It defines a struct `MailSendCommand` and derives
23//! [`Parsable`] trait for it. This is enough to be able to parse it.
24//!
25//! ```
26//! # extern crate std;
27//! # use std::vec::Vec;
28//! # use std::string::{String, ToString};
29//! use kmdparse::{Parsable, parse};
30//!
31//! #[derive(Debug, PartialEq, Eq, Parsable)]
32//! struct MailSendCommand {
33//! text: String,
34//! #[cmd(attr(subject), default = "\"no subject\".to_string()")]
35//! subject: String,
36//! #[cmd(attr(to))]
37//! to: Vec<String>,
38//! }
39//!
40//! # fn main() -> Result<(), kmdparse::error::ParseError<'static>> {
41//! let input = "\"Hello, world\" --to user1@example.com user2@example.com --subject Greeting";
42//! let result = parse::<_, MailSendCommand>(input, ())?;
43//! assert_eq!(result, MailSendCommand {
44//! text: "Hello, world".to_string(),
45//! subject: "Greeting".to_string(),
46//! to: vec!["user1@example.com".to_string(), "user2@example.com".to_string()],
47//! });
48//! # Ok(())
49//! # }
50//! ```
51//!
52//! This example demonstrates several features of `kmdparse`:
53//!
54//! * Parsing functionality can be automatically derived for an arbitrary struct or enum as long
55//! as the inner types are [`Parsable`] or there is an appropriate [`Parser`] for them. (To
56//! learn about the distinction between parsable and parser, read documentation for these traits).
57//! * Derived parser is configurable: you may make fields either required or optional. Optional
58//! fields can be specified via a name attribute (`--` token). They can have a default value
59//! explicitly specified (see default attribute on the `subject` field) or not (`to` field
60//! defaults to an empty vector, as per its [`Default`] implementation)
61//! * Parsable values can contain nested parsable values: `MailSendCommand` is parsable, it
62//! contains a [`Vec`] which is parsable and in repeatedly parses [`String`]s that are parsable.
63//! Note how `kmdparse` recognized that the list of email addresses finished when it
64//! encountered the attribute that neither [`String`] nor [`Vec`] recognizes.
65//!
66//! `kmdparse` can generate completion suggestions:
67//!
68//! ```
69//! # use kmdparse::{Parsable, parse};
70//! use kmdparse::complete;
71//! use std::collections::BTreeSet;
72//!
73//! # #[derive(Debug, PartialEq, Eq, Parsable)]
74//! # struct MailSendCommand {
75//! # text: String,
76//! # #[cmd(attr(subject), default = "\"no subject\".to_string()")]
77//! # subject: String,
78//! # #[cmd(attr(to))]
79//! # to: Vec<String>,
80//! # }
81//! # fn main() -> Result<(), kmdparse::error::ParseError<'static>> {
82//! let suggestions = complete::<_, MailSendCommand>("\"Hello, world\" --", ());
83//! assert_eq!(suggestions, BTreeSet::from(["to".into(), "subject".into()]));
84//! # Ok(())
85//! # }
86//! ```
87//!
88//! It also supports parsing enums. In case of enum, it expects a discriminator (automatically
89//! converted into kebab-case by the [`Parsable`] derive macro):
90//!
91//! ```
92//! use kmdparse::{parse, Parsable};
93//!
94//! #[derive(Debug, PartialEq, Eq, Parsable)]
95//! enum Priority {
96//! High,
97//! Medium,
98//! Low,
99//! }
100//!
101//! impl Default for Priority {
102//! fn default() -> Self {
103//! Priority::Medium
104//! }
105//! }
106//!
107//! #[derive(Debug, PartialEq, Eq, Parsable)]
108//! enum Command {
109//! AddTask(String, #[cmd(attr(priority))] Priority),
110//! Remove(usize),
111//! }
112//!
113//! # fn main() -> Result<(), kmdparse::error::ParseError<'static>> {
114//! assert_eq!(
115//! parse::<_, Command>("add-task parse-all-commands", ())?,
116//! Command::AddTask("parse-all-commands".to_string(), Priority::Medium),
117//! );
118//! assert_eq!(
119//! parse::<_, Command>("add-task enjoy-your-day --priority high", ())?,
120//! Command::AddTask("enjoy-your-day".to_string(), Priority::High),
121//! );
122//! assert_eq!(parse::<_, Command>("remove 1", ())?, Command::Remove(1));
123//! # Ok(())
124//! # }
125//! ```
126//!
127//! # Syntax
128//!
129//! The syntax that `kmdparse` supports is fairly minimal. The parsing machinery sees the input as
130//! a sequence of tokens. Token is any sequence of characters separated by whitespaces. If you wish
131//! to include a whitespace in the token, you may enclose any substring of the input into a pair of
132//! quotation marks (either double or singular); `kmdparse` supports escaping these symbols
133//! inside quoted tokens with a slash (`\`).
134//!
135//! Input can contain a comment beginning with an octothorp (`#`). Octothorps within quoted tokens
136//! are not considered beginning a comment.
137//!
138//! The meaning of the token and attributes are highly specific to each parser. Generally, each
139//! parser consumes tokens sequentially until each required field’s value is filled. It also
140//! handles attributes in any order and at arbitrary positions.
141//!
142//! Due to the nature of the commands' syntax, parsing can seem ambiguous. For example,
143//! `kmdparse` can parse nested structs such as `Vec<Vec<u32>>`. It may be confusing to the end
144//! user, how would a sequence of numbers be interpreted (they all will be put in the only item of
145//! the outer vector). It is best to design your command to be simple and avoid highly nested
146//! structures for the better user experience. In some cases, complexity is unavoidable. In such
147//! situations, users may find useful an ability to group tokens, belonging to the same data
148//! structure, with parenthesis: `(` and `)`. This way, users can express a value `vec![vec![1, 2],
149//! vec![3, 4, 5]]` as `(1 2) (3 4 5)`.
150//!
151//! More details about how the tokenization and the parsing algorithm are documented in the
152//! [`tokens`] module’s and [`Parser`] trait’s documentation.
153//!
154//! # Features
155//! This crate is `no_std` compatible. Features that depend on the standard library are only enabled
156//! when the `std` feature is enabled. These features include support for types from the standard
157//! library, such as `Vec`, `String`, and collections from the standard library.
158
159#[cfg(doc)]
160extern crate std;
161#[cfg(doc)]
162use std::{
163 collections::BTreeSet,
164 string::{String, ToString},
165 vec::Vec,
166};
167
168pub mod error;
169pub mod parsers;
170pub mod testing;
171pub mod tokens;
172
173use error::ParseError;
174use error::ParseFailure;
175#[doc(hidden)]
176pub use kmdparse_derive::Parsable;
177use tokens::TokenStream;
178
179/// The result value returned by the individual parsers
180///
181/// [`Parser::parse`] either succeeds, in which case it returns a value that was parsed and the
182/// remaining tokens in the token stream, or fails with a [`ParseFailure`]. This type alias
183/// represents the return value.
184pub type ParseResult<'a, T> = Result<(T, TokenStream<'a>), ParseFailure<'a>>;
185
186/// Definition of the parsing and completion algorithm for some type
187///
188/// This trait is fundamental for the functionality of `kmdparse`. The implementers must define
189/// two operations: parsing (converting the input [`TokenStream`] into a value of a target type)
190/// and completion (generating the set of possible completions for the last meaningful token in the
191/// input stream).
192///
193/// Most often, the types being parsed are compound, meaning they contain multiple fields with
194/// different parsers. It is best to keep parsers as simple as possible and delegate most of the
195/// work to the child parsers. To ensure correct interaction between parsers, custom
196/// implementations must follow the parsing protocol. The rules are described in the documentation
197/// for each of the `Parser`'s methods.
198///
199/// Please note, that in most cases writing the parser by hand isn't necessary. Parser is
200/// automatically generated for any type that derives [`Parsable`]. The name of the generated
201/// parser is constructed by appending the word Parser to the end of the type.
202///
203/// # Context
204///
205/// The `Parser` trait is generic over an arbitrary context. Context is passed as an argument to both
206/// of the `Parser`'s methods and is intended to make parsers configurable, meaning their behavior
207/// can depend on some information available at runtime.
208///
209/// The following example demonstrates how to implement the parser for a variant-like data,
210/// dependent on data available at runtime.
211///
212/// ```
213/// use kmdparse::{Parser, CompletionResult, ParseResult, parse_parser, complete_parser};
214/// use kmdparse::tokens::{TokenStream, Token};
215/// use kmdparse::error::{ParseError, UnrecognizedToken};
216/// use std::borrow::Cow;
217/// use std::collections::{BTreeSet, HashMap};
218///
219/// struct RuntimeContext { variables: HashMap<String, u32> }
220///
221/// #[derive(Default)]
222/// struct VariableParser;
223///
224/// impl<'c> Parser<&'c RuntimeContext> for VariableParser {
225/// type Value = u32;
226///
227/// fn parse<'a>(&self, input: TokenStream<'a>, ctx: &'c RuntimeContext) -> ParseResult<'a, Self::Value> {
228/// match input.take().transpose()? {
229/// None => Err(ParseError::token_required().expected("variable").into()),
230/// Some((attr @ Token::Attribute(_), remaining)) => {
231/// Err(UnrecognizedToken::new(attr, remaining).into())
232/// }
233/// Some((token @ Token::Text(text), remaining)) => {
234/// let text = text.parse_string();
235/// match ctx.variables.get(&text as &str) {
236/// Some(value) => Ok((*value, remaining)),
237/// None => Err(UnrecognizedToken::new(token, remaining).into()),
238/// }
239/// }
240/// }
241/// }
242///
243/// fn complete<'a>(&self, input: TokenStream<'a>, ctx: &'c RuntimeContext) -> CompletionResult<'a> {
244/// match input.take() {
245/// Some(Err(_)) | None => CompletionResult::new_final(false),
246/// Some(Ok((Token::Attribute(_), _))) => CompletionResult::new(input, false),
247/// Some(Ok((Token::Text(text), remaining))) if remaining.is_all_consumed() => {
248/// let text = text.parse_string();
249/// CompletionResult::new_final(true).add_suggestions(
250/// ctx.variables.keys()
251/// .filter_map(|key| key.strip_prefix(&text as &str))
252/// .map(|suggestion| Cow::Owned(suggestion.to_string()))
253/// )
254/// }
255/// Some(Ok((Token::Text(_), remaining))) => CompletionResult::new(remaining, true),
256/// }
257/// }
258/// }
259///
260/// # fn main() -> Result<(), ParseError<'static>> {
261/// let context = RuntimeContext {
262/// variables: HashMap::from([("var-1".to_string(), 10), ("var-2".to_string(), 20)]),
263/// };
264///
265/// assert_eq!(parse_parser::<_, VariableParser>("var-1", &context)?, 10);
266/// assert_eq!(parse_parser::<_, VariableParser>("var-2", &context)?, 20);
267/// assert_eq!(
268/// complete_parser::<_, VariableParser>("va", &context),
269/// BTreeSet::from(["r-1".into(), "r-2".into()]),
270/// );
271/// # Ok(())
272/// # }
273/// ```
274///
275/// Parser implementation should be as generic as possible to avoid type errors when integrating
276/// with other parsers.
277pub trait Parser<Ctx>: Default {
278 /// The type that this parser will parse the input stream into.
279 type Value;
280
281 /// Parsers the beginning of the token stream into a `Value`.
282 ///
283 /// This function performs the parsing of the input stream: it repeatedly consumes tokens from
284 /// the token stream and then produces one of the following return values:
285 /// * `Ok((value, remaining))` in case of the correctly parsed sequence of tokens. Here
286 /// `value` is the result of the parsing, (it has type `Self::Value`), and remaining is the
287 /// token stream representing the set of tokens that wasn’t consumed;
288 /// * `Err(ParseFailure::Error(error))` in case the parser failed with an error indicating the
289 /// malformed input. See [`ParseError`];
290 /// * `Err(ParseFailure::Unexpected(unexpected_token))` if the first token in the input stream
291 /// is an attribute or an enum variant discriminator that the parser does not recognize.
292 ///
293 /// To be interoperable with other parsers, the parse implementation must follow the parsing
294 /// protocol:
295 /// * if the first token in the input stream is an attribute and the parser does not recognize
296 /// this attribute, it should return `Err(UnexpectedToken::new(token, remaining).into())`
297 /// where `token` is the attribute that was not recognized, and `remaining` is the token
298 /// stream consisting of tokens directly following token;
299 /// * if the parser expects the enum variant discriminator and the first token of the input is
300 /// not recognized as such, it should return `Err(UnexpectedToken::new(token,
301 /// remaining).into())` with the same values as described above;
302 /// * the parser must not return [`UnexpectedToken`] result with any token other than the first
303 /// token of the input stream; if it receives this value from an inner parser, it must convert
304 /// it into the equivalent error if the parser was not called on the original input;
305 /// * when all required tokens are successfully consumed parser should continue to take tokens
306 /// until a text token or an attribute that is not recognized is encountered (this is not
307 /// necessary if parser does not expect attributes)
308 fn parse<'a>(&self, input: TokenStream<'a>, ctx: Ctx) -> ParseResult<'a, Self::Value>;
309}
310
311/// Sets the default parser for a given type
312///
313/// This trait allows the users of a type to avoid specifying the parser explicitly.
314///
315/// This trait can be procedurally derived for any struct or enum if all its inner types are
316/// Parsable or have explicit parser specified.
317///
318/// # Derive macro
319///
320/// The `Parsable` derive macro accepts attributes that modify parsing behavior. These attributes
321/// are specified in the form `#[cmd(...)]` attributes can be specifed in the same parenthesis
322/// separated by commas or separately: `#[cmd(default, attr(field))]` and `#[cmd(default)]
323/// #[cmd(attr(field))]` are equivalent.
324///
325/// ## Type attribute
326///
327/// The following attributes are applied to the entire struct or enum for which the trait is being
328/// derived.
329///
330/// ### `ctx = "type-name"`, `ctx_bound = "trait-names"`
331///
332/// Restricts the type of the parsing context in case of ctx attribute or bounds the generic
333/// parsing context to the specific trait or collection of traits in case `ctx_bound` attribute is
334/// used. This is needed when one or more inner parser restricts the type of the context it uses.
335///
336/// The following example demonstrates the creation of a custom parser that requires a specific
337/// parsing context and restricting the context type in the derived trait implementation.
338///
339/// ```
340/// use kmdparse::{parse, tokens::TokenStream, CompletionResult, Parsable, Parser, ParseResult};
341///
342/// #[derive(Debug, Copy, Clone, PartialEq, Eq)]
343/// enum LengthUnit { Cm, In }
344///
345/// #[derive(Clone)]
346/// struct ParsingContext {
347/// unit: LengthUnit,
348/// }
349///
350/// #[derive(Debug, PartialEq)]
351/// struct Length(f64, LengthUnit);
352///
353/// #[derive(Default)]
354/// struct LengthParser;
355///
356/// impl Parser<ParsingContext> for LengthParser {
357/// type Value = Length;
358///
359/// fn parse<'a>(&self, input: TokenStream<'a>, ctx: ParsingContext) -> ParseResult<'a, Self::Value> {
360/// let unit = ctx.unit;
361/// let parser = <f64 as Parsable<ParsingContext>>::Parser::default();
362/// let (value, remaining) = parser.parse(input, ctx)?;
363/// Ok((Length(value, unit), remaining))
364/// }
365///
366/// fn complete<'a>(&self, input: TokenStream<'a>, ctx: ParsingContext) -> CompletionResult<'a> {
367/// let parser = <f64 as Parsable<ParsingContext>>::Parser::default();
368/// parser.complete(input, ctx)
369/// }
370/// }
371///
372/// impl Parsable<ParsingContext> for Length {
373/// type Parser = LengthParser;
374/// }
375///
376/// #[derive(Debug, PartialEq, Parsable)]
377/// #[cmd(ctx = "ParsingContext")]
378/// struct Size {
379/// height: Length,
380/// width: Length,
381/// }
382///
383/// # fn main() -> Result<(), kmdparse::error::ParseError<'static>> {
384/// assert_eq!(
385/// parse::<_, Size>("10 20", ParsingContext{ unit: LengthUnit::Cm })?,
386/// Size {
387/// height: Length(10.0, LengthUnit::Cm),
388/// width: Length(20.0, LengthUnit::Cm)
389/// }
390/// );
391/// # Ok(())
392/// # }
393/// ```
394///
395/// ## Field attributes
396///
397/// The following attributes can be used for the struct’s or enum variant’s fields.
398///
399/// ### `parser = "parser-type-name"`
400///
401/// Specifies a custom parser used for a field.
402///
403/// This attribute is useful in situations where the required parser is different from the parser
404/// defined by the `Parsable` trait (which is used by default) or when implementation of `Parsable`
405/// is not possible (e.g. when dealing with types defined in a foreign crate).
406///
407/// The following example demonstrates how to use `TransformParser` for data validation.
408///
409/// ```
410/// use kmdparse::parsers::{TransformParser, ParsableTransformation};
411/// use kmdparse::error::ParseError;
412/// use kmdparse::Parsable;
413///
414/// struct Number01RangeValidator;
415///
416/// impl ParsableTransformation<f64> for Number01RangeValidator {
417/// type Input = f64;
418///
419/// fn transform(input: Self::Input) -> Result<f64, ParseError<'static>> {
420/// if input < 0.0 || input >= 1.0 {
421/// Err(ParseError::custom("must be between 0 and 1"))
422/// } else {
423/// Ok(input)
424/// }
425/// }
426/// }
427///
428/// #[derive(Debug, Parsable)]
429/// struct Point(
430/// #[cmd(parser = "TransformParser<<f64 as Parsable<kmdparserCtx>>::Parser, Number01RangeValidator, f64>")] f64,
431/// #[cmd(parser = "TransformParser<<f64 as Parsable<kmdparserCtx>>::Parser, Number01RangeValidator, f64>")] f64,
432/// );
433/// ```
434///
435/// ### `default` or `default = "value"` without `attr`
436///
437/// If the `default` attribute is used on a field, this field will not be parsed. Instead, when
438/// constructing the containing instance, the parser uses a default value (if value is not
439/// specified) or a specific value (specified after `=` sign).
440///
441/// ```
442/// use kmdparse::{Parsable, parse};
443///
444/// #[derive(Debug, PartialEq, Eq, Parsable)]
445/// struct MyStruct(#[cmd(default)] u8, #[cmd(default = "5")] u8, u8);
446///
447/// # fn main() -> Result<(), kmdparse::error::ParseError<'static>> {
448/// assert_eq!(parse::<_, MyStruct>("24", ())?, MyStruct(0, 5, 24));
449/// # Ok(())
450/// # }
451/// ```
452///
453/// ### `attr(attribute = "value")` or `attr(attribute)`
454///
455/// Indicates that the field is optional, it can be specified by the user using a named attribute.
456/// This attribute comes in two variants: when “value” is specified, the field’s value is taken
457/// from the expression in the attribute, otherwise the attribute token must be followed by the
458/// field value’s tokens.
459///
460/// ```
461/// use kmdparse::{Parsable, parse};
462///
463/// #[derive(Debug, PartialEq, Eq, Parsable)]
464/// enum Color{ Red, Green, Blue }
465///
466/// impl Default for Color {
467/// fn default() -> Self {
468/// Color::Green
469/// }
470/// }
471///
472/// #[derive(Debug, PartialEq, Eq, Parsable)]
473/// struct MyStruct {
474/// #[cmd(attr(important = "true"))] is_important: bool,
475/// #[cmd(attr(color))] color: Color,
476/// }
477///
478/// # fn main() -> Result<(), kmdparse::error::ParseError<'static>> {
479/// assert_eq!(
480/// parse::<_, MyStruct>("--important", ())?,
481/// MyStruct { color: Color::Green, is_important: true },
482/// );
483/// assert_eq!(
484/// parse::<_, MyStruct>("--color red", ())?,
485/// MyStruct { color: Color::Red, is_important: false },
486/// );
487/// # Ok(())
488/// # }
489/// ```
490///
491/// #### In combination with `default = "value"`
492///
493/// If an optional field’s value is not specified, the default value is used instead, as determined
494/// by the implementation of `Default` trait. This can be overridden by specifying a default value
495/// using `default` attribute.
496///
497/// ```
498/// use kmdparse::{Parsable, parse};
499///
500/// #[derive(Debug, PartialEq, Eq, Parsable)]
501/// struct MyStruct(#[cmd(default = "5", attr(value))] u8);
502///
503/// # fn main() -> Result<(), kmdparse::error::ParseError<'static>> {
504/// assert_eq!(parse::<_, MyStruct>("--value 10", ())?, MyStruct(10));
505/// assert_eq!(parse::<_, MyStruct>("", ())?, MyStruct(5));
506/// # Ok(())
507/// # }
508/// ```
509///
510/// ### `alias_value(alias = "alias", value="value")`
511///
512/// Used for enum variant’s fields. Specifies the value for a field if the specific alias is used
513/// as enum’s discriminator. An `alias` can be either a name of a variant (converted into
514/// kebab-case), a renamed variant name (via `rename` attribute), or an alias defined using `alias`
515/// attribute.
516///
517/// ```
518/// use kmdparse::{Parsable, parse};
519///
520/// #[derive(Debug, PartialEq, Eq, Parsable)]
521/// enum MyEnum {
522/// #[cmd(alias = "enable", alias = "disable")]
523/// SetEnabled(
524/// #[cmd(
525/// alias_value(alias = "enable", value = "true"),
526/// alias_value(alias = "disable", value = "false")
527/// )] bool
528/// )
529/// }
530///
531/// # fn main() -> Result<(), kmdparse::error::ParseError<'static>> {
532/// assert_eq!(parse::<_, MyEnum>("enable", ())?, MyEnum::SetEnabled(true));
533/// assert_eq!(parse::<_, MyEnum>("disable", ())?, MyEnum::SetEnabled(false));
534/// # Ok(())
535/// # }
536/// ```
537///
538/// ## Enum variant attributes
539///
540/// These attributes are applicable to enum variants. Generally, `kmdparse` expects a
541/// discriminator—the variant’s name in kebab-case followed by tokens for its fields if any exist.
542///
543/// ### `rename = "name"`
544///
545/// Changes the name of the variant’s discriminator. The variant cannot be parsed using its
546/// original name.
547///
548/// ```
549/// use kmdparse::{Parsable, parse};
550///
551/// #[derive(Debug, PartialEq, Eq, Parsable)]
552/// enum MyEnum {
553/// #[cmd(rename = "first")] One,
554/// #[cmd(rename = "second")] Two,
555/// }
556///
557/// # fn main() -> Result<(), kmdparse::error::ParseError<'static>> {
558/// assert_eq!(parse::<_, MyEnum>("first", ())?, MyEnum::One);
559/// assert!(parse::<_, MyEnum>("one", ()).is_err());
560/// # Ok(())
561/// # }
562/// ```
563///
564/// ### `alias = "alias"`
565///
566/// Adds an alias for the variant. Variant can have an arbitrary number of aliases and the value
567/// can be parsed using any of this. Specifying an alias does not prevent the usage of the
568/// variant’s original name.
569///
570/// ```
571/// use kmdparse::{Parsable, parse};
572///
573/// #[derive(Debug, PartialEq, Eq, Parsable)]
574/// enum Color {
575/// Black,
576/// White,
577/// #[cmd(alias = "grey")] Gray,
578/// }
579///
580/// # fn main() -> Result<(), kmdparse::error::ParseError<'static>> {
581/// assert_eq!(parse::<_, Color>("grey", ())?, Color::Gray);
582/// assert_eq!(parse::<_, Color>("gray", ())?, Color::Gray);
583/// # Ok(())
584/// # }
585/// ```
586///
587/// ### `ignore`
588///
589/// Disables the parsing of the variant. Note that this does not prevent assigning aliases to the
590/// variant.
591///
592/// ```
593/// use kmdparse::{Parsable, parse};
594///
595/// #[derive(Debug, PartialEq, Eq, Parsable)]
596/// enum MyEnum {
597/// Command,
598/// #[cmd(ignore)] NonInteractive,
599/// }
600///
601/// # fn main() -> Result<(), kmdparse::error::ParseError<'static>> {
602/// assert!(parse::<_, MyEnum>("non-interactive", ()).is_err());
603/// # Ok(())
604/// # }
605/// ```
606///
607/// ### `transparent`
608///
609/// Indicates that a variant can be parsed without a discriminator. This can be used when splitting
610/// a large enum into several smaller ones is desirable.
611///
612/// ```
613/// use kmdparse::{Parsable, parse};
614///
615/// #[derive(Debug, PartialEq, Eq, Parsable)]
616/// enum Subcommand { First, Second }
617///
618/// #[derive(Debug, PartialEq, Eq, Parsable)]
619/// enum Command {
620/// #[cmd(transparent)]
621/// Subcommand(Subcommand),
622/// Third,
623/// }
624///
625/// # fn main() -> Result<(), kmdparse::error::ParseError<'static>> {
626/// assert_eq!(parse::<_, Command>("first", ())?, Command::Subcommand(Subcommand::First));
627/// assert_eq!(parse::<_, Command>("third", ())?, Command::Third);
628/// # Ok(())
629/// # }
630/// ```
631///
632/// ### `transparent_no_error`
633///
634/// Functions similarly to `transparent` but does not terminate parsing on failure. It is useful
635/// when the first field of this variant is not an enum.
636///
637/// ```
638/// use kmdparse::{Parsable, parse};
639///
640/// #[derive(Debug, PartialEq,Parsable)]
641/// enum Value {
642/// #[cmd(transparent_no_error)] Integer(i64),
643/// #[cmd(transparent_no_error)] Real(f64),
644/// #[cmd(transparent_no_error)] Boolean(bool),
645/// }
646///
647/// # fn main() -> Result<(), kmdparse::error::ParseError<'static>> {
648/// assert_eq!(parse::<_, Value>("0.4", ())?, Value::Real(0.4));
649/// assert_eq!(parse::<_, Value>("12", ())?, Value::Integer(12));
650/// assert_eq!(parse::<_, Value>("true", ())?, Value::Boolean(true));
651/// # Ok(())
652/// # }
653/// ```
654///
655/// Note that in the example above, the orders in which the enum variants are declared matters:
656/// `kmdparse` tries to parse transparent variants in order in which they are declared and
657/// returns the first successfully parsed result.
658pub trait Parsable<Ctx> {
659 /// The parser type for this type
660 type Parser: Parser<Ctx, Value = Self>;
661}
662
663/// Parsers a value from an input string using an explicitly specified parser
664///
665/// This function takes an input string slice as an input and a context, and returns a value parsed
666/// from the input or an error. `parse` ensures that all tokens from the input string were
667/// consumed, and the input is valid.
668///
669/// This function is different from [`parse`] in that is expects a parser as its second generic
670/// parameter. The value returned by `parse_parser` does not need to implement [`Parsable`].
671/// `parse_parser` most commonly used with custom parsers.
672///
673/// # Example:
674///
675/// ```
676/// use kmdparse::parse_parser;
677/// use kmdparse::parsers::{IntegerParser, StringParser, tuples::TupleParser2};
678///
679/// type ExplicitParser = TupleParser2<IntegerParser<u64>, StringParser>;
680/// # fn main() -> Result<(), kmdparse::error::ParseError<'static>> {
681/// let value = parse_parser::<_, ExplicitParser>("42 fourty-two", ())?;
682/// assert_eq!(value, (42, "fourty-two".to_string()));
683/// # Ok(())
684/// # }
685/// ```
686pub fn parse_parser<Ctx, P: Parser<Ctx>>(
687 input: &str,
688 ctx: Ctx,
689) -> Result<P::Value, ParseError<'_>> {
690 let tokens = TokenStream::new(input);
691 match P::default().parse(tokens, ctx) {
692 Ok((result, remaining)) => match remaining.peek() {
693 Some(Ok(token)) => Err(ParseError::unknown(token)),
694 Some(Err(err)) => Err(err.into()),
695 None => Ok(result),
696 },
697 Err(ParseFailure::Error(err)) => Err(err),
698 Err(ParseFailure::Unrecognized(unrecognized)) => Err(unrecognized.into_error()),
699 }
700}
701
702/// Parsers a [`Parsable`] value from an input string
703///
704/// This function takes an input string slice as an input and a context, and returns a value parsed
705/// from the input or an error. `parse` ensures that all tokens from the input string were
706/// consumed, and the input is valid.
707///
708/// # Example:
709///
710/// ```
711/// use kmdparse::parse;
712///
713/// # fn main() -> Result<(), kmdparse::error::ParseError<'static>> {
714/// let value: (u64, String) = parse("42 fourty-two", ())?;
715/// assert_eq!(value, (42, "fourty-two".to_string()));
716/// # Ok(())
717/// # }
718/// ```
719pub fn parse<Ctx, T: Parsable<Ctx>>(input: &str, ctx: Ctx) -> Result<T, ParseError<'_>> {
720 parse_parser::<_, T::Parser>(input, ctx)
721}