//! Inpt is a derive crate for dumb type-level text parsing.
//!
//! # Introduction
//! Imagine you need to chop up an annoying string and convert all the bits to useful types.
//! You could write that sort of code by hand using `split` and `from_str`, but the boiler-plate
//! of unwrapping and checking quickly looses all charm. Especially since that sort of parsing
//! shows up a lot in timed programming competitions like [advent of code](https://adventofcode.com).
//!
//! Inpt tries to write that sort of parsing code for you, automatically splitting input strings
//! based on field types and an optional regex. Inpt is absolutely _not_ performant, strict, or formal.
//! Whenever possible, it does the obvious thing:
//! <div style="display: flex; flex-direction: row; align-items: stretch; gap: 1em">
//!
//! ```rust, no_run
//! #[inpt::main]
//! fn main(x: f32, y: f32) {
//!     println!("{}", x * y);
//! }
//! ```
//!
//! ```text
//! $ echo '6,7' | cargo run
//! 42
//! ```
//!
//! </div>
//!
//! ## Contents
//! - [Introduction](crate#introduction)
//! - [Example](crate#example)
//! - [Struct Syntax](crate#struct-syntax)
//!     - [regex](crate#regex)
//!     - [from, try_from](crate#from-try_from)
//!     - [skip](crate#skip)
//!     - [option](crate#option)
//!     - [before/after](crate#before-after)
//!     - [bounds](crate#bounds)
//!     - [from_str](crate#from_str)
//!     - [from_iter](crate#from_iter)
//!     - [trim](crate#trim)
//!     - [split](crate#split)
//! - [Enum Syntax](crate#enum-syntax)
//!     - [enum regex](crate#enum-regex)
//! - [Main](crate#main)
//!
//! # Example
//! ```rust
//! use inpt::{Inpt, inpt};
//!
//! #[derive(Inpt)]
//! #[inpt(regex = r"(.)=([-\d]+)\.\.([-\d]+),?")]
//! struct Axis {
//!     name: char,
//!     start: i32,
//!     end: i32,
//! }
//!
//! #[derive(Inpt)]
//! #[inpt(regex = "target area:")]
//! struct Target {
//!     #[inpt(after)]
//!     axes: Vec<Axis>,
//! }
//!
//! impl Target {
//!     fn area(&self) -> i32 {
//!         self.axes.iter().map(|Axis { start, end, ..}| end - start).product()
//!     }
//! }
//!
//!
//! let target = inpt::<Target>("target area: x=119..176, y=-114..84").unwrap();
//! assert_eq!(target.area(), 11286);
//! ```
//!
//! # Struct Syntax
//! The [`Inpt`](macro@Inpt) derive macro can do a few neat tricks, listed here. In its default setting,
//! the fields of the struct are parsed in order, with each field consuming as much of the input as
//! possible before moving on:
//!
//! ```rust
//! # use inpt::{inpt, Inpt};
//! #[derive(Inpt, Debug, PartialEq)]
//! struct OrderedFields<'s>(char, i32, &'s str);
//!
//! assert_eq!(
//!     inpt::<OrderedFields>("A113 is a classroom").unwrap(),
//!     OrderedFields('A', 113, "is a classroom"),
//! )
//! ```
//!
//! This behavior is also implemented for arrays, tuples, and a number of collection types.
//!
//! ## regex
//! When the `#[inpt(regex = r".*")]` struct attribute is given, the fields are no longer
//! parsed one after the another. Instead the regex is matched against the remaining input, and
//! the fields are parsed from the regex's numbered capture groups. I recommend that regexes are given as
//! [raw strings](https://doc.rust-lang.org/reference/tokens.html#raw-string-literals) to avoid
//! double-escapes and quoting.
//! ```rust
//! # use inpt::{inpt, Inpt};
//! #[derive(Inpt, Debug, PartialEq)]
//! #[inpt(regex = r"(.*) number ([a-zA-Z])(\d+)")]
//! struct RegexFields<'s>(&'s str, char, i32);
//!
//! assert_eq!(
//!     inpt::<RegexFields>("classroom number A113").unwrap(),
//!     RegexFields("classroom", 'A', 113),
//! )
//! ```
//!
//! Ungreedy/lazy repetitions can be very useful when splitting inputs. Like rewriting a while loop as an until loop,
//! a regex `([^!]*)!` can be rewritten as `(.*?)!`. This is particularly helpful when we want to stop after finding multiple characters,
//! like the 3 quotes that end a multi-line string in Python or Julia: `"""(.*?)"""`.
//!
//! Be aware that when such a regex is used multiple times to parse a sequence of fields,
//! the last regex match is forced to parse all remaining input, even if normally lazy:
//! ```rust
//! # use inpt::{inpt, Inpt};
//! #[derive(Inpt, Debug, PartialEq)]
//! #[inpt(regex = r"(.+?),")]
//! struct Part<'s>(&'s str);
//!
//! assert_eq!(
//!     inpt::<[Part; 3]>("my,list,of,many,words,").unwrap(),
//!     [Part("my"), Part("list"), Part("of,many,words")],
//! )
//! ```
//!
//! ## from, try_from
//! When the `#[inpt(from = "T")]` or `#[inpt(try_from = "T")]` struct attributes are given, T is parsed instead
//! of the struct itself, and the From or TryFrom traits are used to convert.
//! ```rust
//! # use inpt::{inpt, Inpt};
//! # use std::{convert::TryFrom, fmt, error::Error};
//! use inpt::split::{Group, Line};
//!
//! #[derive(Inpt)]
//! #[inpt(try_from = "Group<Vec<Line<Vec<T>>>>")]
//! struct Grid<T> {
//!     width: usize,
//!     table: Vec<T>,
//! }
//!
//! #[derive(Debug)]
//! struct UnevenGridError;
//! impl fmt::Display for UnevenGridError {
//!     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
//!         f.write_str("grid rows must have even length")
//!     }
//! }
//! impl Error for UnevenGridError {}
//!
//! impl<'s, T> TryFrom<Group<Vec<Line<Vec<T>>>>> for Grid<T> {
//!     type Error = UnevenGridError;
//!
//!     fn try_from(Group { inner: lines }: Group<Vec<Line<Vec<T>>>>)
//!             -> Result<Self, Self::Error>
//!     {
//!         let mut width = None;
//!         let mut table = Vec::new();
//!         for Line { inner: mut line } in lines {
//!             width = match width {
//!                 Some(w) if w == line.len() => Some(w),
//!                 Some(_) => return Err(UnevenGridError),
//!                 None => Some(line.len()),
//!             };
//!             table.append(&mut line);
//!         }
//!         Ok(Grid {
//!             width: width.ok_or(UnevenGridError)?,
//!             table,
//!         })
//!     }
//! }
//!
//! assert_eq!(inpt::<Grid<char>>("##\n##").unwrap().width, 2);
//! ```
//!
//!
//! ## skip
//! The `#[inpt(skip)]` field attribute can be used to ignore fields when parsing
//! and instead insert their `Default::default()`.
//!
//! ## option
//! If a capture group corresponds to a field with type `Option`, the field will be set to `None` when the group is not captured
//! by the match, rather than producing an error.
//! ```rust
//! # use inpt::{inpt, Inpt};
//! #[derive(Inpt, Debug, PartialEq)]
//! #[inpt(regex = r"(.*) letter ([a-zA-Z])(\d+)?")]
//! struct RegexFields<'s>(&'s str, char, Option<i32>);
//!
//! assert_eq!(
//!     inpt::<RegexFields>("classroom letter A").unwrap(),
//!     RegexFields("classroom", 'A', None),
//! )
//! ```
//!
//! ## before, after
//! Any fields marked with the `#[inpt(before)]` attribute will be parsed sequentially, consuming input prior to matching the given regex.
//! After the regex is matched, remaining input is consumed by any fields marked `#[inpt(after)]`. Having such a field causes the regex
//! to again behave lazily in the example above.
//! ```rust
//! # use inpt::{inpt, Inpt};
//! #[derive(Inpt, Debug, PartialEq)]
//! #[inpt(regex = r"is a")]
//! struct RegexFields<'s>(
//!     #[inpt(before)] char,
//!     #[inpt(before)] i32,
//!     #[inpt(after)] &'s str,
//! );
//!
//! assert_eq!(
//!     inpt::<RegexFields>("A113 is a classroom").unwrap(),
//!     RegexFields('A', 113, "classroom"),
//! )
//! ```
//!
//! ## bounds
//! By default the derive macro adds `T: Inpt<'s>` bounds to every parsed field of a struct, as well as a `Self: 's` bound.
//! This greatly improves error messages and improves the ergonomics around generic structs. However, it is sometimes necessary
//! to replace those automatic bounds entirely. If you ever get
//! "<code><b color="ff5555">error\[E0275\]</b><b>: overflow evaluating the requirement \`T: Inpt&lt;'_&gt;\`</b></code>", try solving it
//! with a `#[inpt(bounds = "")]` attribute.
//!
//! ```rust
//! # use inpt::{inpt, Inpt};
//! use inpt::InptError;
//!
//! #[derive(Inpt)]
//! #[inpt(regex = "(.)(.+)?")]
//! #[inpt(bounds = "")]
//! struct Recursive(char, Option<Box<Recursive>>);
//!
//! let chars: Recursive = inpt("abc").unwrap();
//! # assert_eq!(chars.0, 'a');
//! # assert_eq!(chars.1.as_ref().unwrap().0, 'b');
//! # assert_eq!(chars.1.as_ref().unwrap().1.as_ref().unwrap().0, 'c');
//! ```
//!
//! ## from_str
//! Although Rust integers and strings all implement the `Inpt` trait, some types can only be parsed using `FromStr`.
//! The derive macro can be told to use a type's [`FromStr`](std::str::FromStr) implementation with the `#[inpt(from_str)]` field attribute.
//! Because the `from_str` function consumes an entire string instead of chopping off just the beginning, the attribute
//! can only be placed on the last field of a struct, or on fields receiving regex capture groups.
//!
//! ```rust
//! # use inpt::{inpt, Inpt};
//! use std::net::{IpAddr};
//!
//! #[derive(Inpt, Debug, PartialEq)]
//! #[inpt(regex = r"route from (\S+) to")]
//! struct Routing {
//!     #[inpt(from_str)]
//!     from: IpAddr,
//!     #[inpt(from_str, after)]
//!     to: IpAddr,
//! }
//!
//! let route: Routing = inpt("route from 192.168.1.2 to 127.0.0.1").unwrap();
//! # assert_eq!(&route.from.to_string(), "192.168.1.2");
//! # assert_eq!(&route.to.to_string(), "127.0.0.1");
//! ```
//!
//! ## from_iter
//! It is quite easy to repeatedly parse a type, either by using [`Vec`](std::vec::Vec)'s own inpt implementation,
//! or parsing then collecting a [`InptIter`]. This can also be accessed inside the derive macro using the
//! `#[inpt(from_iter = "T")]` field attribute, which calls into [`FromIterator<T>`](std::iter::FromIterator).
//! The item type has to be specified because some collections can be built from multiple different item types
//! (e.g. `String` can be collected from an iterator of `char`, an iterator of `&str`, or an iterator of `String`).
//! Like the from_str attribute, the from_iter attribute consumes an entire string and so must appear at the end
//! of the struct, or otherwise parse a regex capture group.
//!
//! ```rust
//! # use inpt::{inpt, Inpt};
//! use std::collections::HashMap;
//!
//! #[derive(Inpt, Debug, PartialEq)]
//! struct Rooms {
//!     #[inpt(from_iter = "(char, u32)")]
//!     letter_to_number: HashMap<char, u32>,
//! }
//!
//! assert_eq!(
//!     inpt::<Rooms>("B5 A113 F111").unwrap().letter_to_number,
//!     [('A', 113), ('B', 5), ('F', 111)].into_iter().collect::<HashMap<_, _>>(),
//! )
//! ```
//!
//! ## trim
//!
//! By default, inpt trims all whitespace between fields. However, some types implement more specific trimming rules.
//! For example, all number types additionally trim adjacent commas and semicolons:
//! ```rust
//! # use inpt::inpt;
//! assert_eq!(
//!     inpt::<Vec<i32>>("1,2;3 4").unwrap(),
//!     vec![1, 2, 3, 4],
//! )
//! ```
//!
//! Users of this crate can specify characters to trim with the `#[inpt(trim = r"\s")]` struct attribute. The attribute
//! syntax is the same as for [regex character classes](https://docs.rs/regex/1/regex/#character-classes) including
//! ranges, negation, intersection, and unicode class names.
//! ```
//! # use inpt::{inpt, Inpt};
//! #[derive(Inpt)]
//! #[inpt(trim = r"\p{Punctuation}")]
//! struct Sentence<'s>(&'s str);
//!
//! assert_eq!(
//!     inpt::<Sentence>("¡I love regexes 💕!").unwrap().0,
//!     "I love regexes 💕",
//! )
//! ```
//!
//! _The trim attribute is also available on fields._ In this case, the attribute will forcibly override the trimming
//! behavior of the field's immediate type. This works particularly well with the from_iter attribute.
//! ```
//! # use inpt::{inpt, Inpt};
//! #[derive(Inpt)]
//! struct PhoneNumber {
//!     #[inpt(from_iter = "u32", trim = r"+\-()\s")]
//!     digits: Vec<u32>,
//! }
//!
//! assert_eq!(
//!     inpt::<PhoneNumber>("+(1)(425) 555-0100").unwrap().digits,
//!     vec![1, 425, 555, 0100],
//! )
//! ```
//!
//! Trimming can be broadly disabled by setting `trim = ""` on a wrapper struct (e.g. [`NoTrim`]), as the default
//! trimmable character class is inherited by types deeper in the parse tree.
//!
//! ## split
//!
//! Sometimes a whole regex is overkill to separate fields, and you only need some kind of delimiter.
//! The wrapper types in [`inpt::split`](mod@crate::split) accomplish exactly this: they stop consuming
//! input as soon as the corresponding delimiter is reached.
//! The field attribute `#[inpt(split = "T")]` is used to parse a field
//! as if it were wrapped in the given type.
//!
//! ```rust
//! # use inpt::{inpt, Inpt};
//! #[derive(Inpt, Debug, PartialEq)]
//! struct Request<'s> {
//!     #[inpt(split = "Line")]
//!     method: &'s str,
//!     body: &'s str,
//! }
//!
//! assert_eq!(
//!     inpt::<Request>("
//!          PUT
//!          crabs are perfect animals
//!     ").unwrap(),
//!     Request {
//!         method: "PUT",
//!         body: "crabs are perfect animals",
//!     },
//! )
//! ````
//!
//! # Enum Syntax
//!
//! Structs and enums support all the same attributes, listed above. But the process of parsing an enum is
//! somewhat different. Inpt will attempt to parse each variant, returning the first that is successfully parsed.
//!
//! ```
//! # use inpt::{inpt, Inpt};
//! #[derive(Inpt)]
//! enum Math {
//!     #[inpt(regex = r"(.*)\+(.*)")]
//!     Add(f64, f64),
//!     #[inpt(regex = r"(.*)\*(.*)")]
//!     Mul(f64, f64),
//! }
//!
//! impl Math {
//!     fn solve(self) -> f64 {
//!         match self {
//!             Math::Add(a, b) => a + b,
//!             Math::Mul(a, b) => a * b,
//!         }
//!     }
//! }
//!
//! assert_eq!(inpt::<Math>("2.6+5.0").unwrap().solve(), 7.6);
//! assert_eq!(inpt::<Math>("2.6*5.0").unwrap().solve(), 13.0);
//!
//! ```
//!
//! ## enum regex
//!
//! Although a `#[regex = r".*"]` attribute is not _required_ on every variant, it is strongly encouraged. Without
//! a regex to pick the correct set of fields, inpt has to guess-and-check each individually. Not only can this
//! cause parsing cost to explode exponentially, it makes bugs and errors almost impossible to track down.
//!
//! When a regex is specified:
//! - if an error occurs before the regex match, the next variant may be tried
//! - if the regex does not match, the next variant is always tried
//! - if an error occurs inside capture group or after the regex match, an error is immediately produced
//!
//! # Main
//! Although inpt can be used with any source of text, it is most common to parse
//! stdin and report errors on stderr. The [`#[inpt::main]`](macro@main) attribute macro is built
//! to facilitate this. Applied to a function, it works exactly like `#[derive(Inpt)]` except
//! arguments behave like fields, and the function as a whole behaves like a struct. The created function
//! will have the same name, visibility, and return type, but will parse stdin instead of receiving arguments.
//!
//! ```rust,no_run
//! #[inpt::main(regex = r"(?:my name is|i am) (.+)")]
//! fn main(name: &'static str) {
//!     println!("hello {name}!");
//! }
//! ```
//!
//! If stdin can not be parsed, the cause of the error is clearly reported by [`error::InptError::annotated_stderr`]
//!
//! <code style="display: block; padding: 1em">$ echo 'call me sam' | cargo run -\-example hello
//! <span color="ff5555">INPT ERROR</span> in stdin:1:1
//! <b color="f1fa8c">&lt;hello::main::Arguments&gt;</b><b color="ff5555">&lt; </b><b color="bd93f9">/(?:my name is|i am) (.+)/</b><b color="ff5555"> &gt;</b>call me sam<b color="ff5555">&lt;/regex&gt;</b><b color="f1fa8c">&lt;/hello::main::Arguments&gt;</b>
//! </code>
//!
//! Note that lifetime elision does not currently work, so all borrows must use either `'static` or a generic lifetime.
//!
//!

use once_cell::sync::OnceCell;
use regex::{Regex, RegexBuilder};
use std::any::type_name;
use std::collections::HashSet;
use std::error::Error as StdError;
use std::marker::PhantomData;
use std::ops::Deref;
use std::{io, process};

/// Apply to a main function to parse stdin.
///
/// See [the syntax documentation](crate#main) for more details.
pub use inpt_macros::main;

/// Apply to a struct so that it can be parsed.
///
/// See [the syntax documentation](crate#struct-syntax) for more details.
pub use inpt_macros::Inpt;

/// Parse a [regex character class](https://docs.rs/regex/1/regex/#character-classes),
/// and return an instance of [`CharClass`].
///
/// The [ucd-generate](https://github.com/BurntSushi/ucd-generate) command line tool is the underlying source of truth
/// for these tables, although the `char_class!` macro depends on it indirectly, via the
/// [regex-syntax crate](https://docs.rs/regex-syntax/).
pub use inpt_macros::char_class;

mod error;
mod impls;
pub mod split;

pub use error::ResultExt;
pub use error::{InptError, InptResult};

extern crate self as inpt;

/// The output of a single parsing step.
#[derive(Debug)]
pub struct InptStep<'s, T> {
    /// The parsed type if successful, or the cause of the error if not.
    pub data: InptResult<'s, T>,
    /// The remaining input to parse.
    pub rest: &'s str,
}

impl<'s, T> InptStep<'s, T> {
    /// Apply the given function to the successfully parsed type if any,
    /// keeping the error and remaining input the same.
    pub fn map<V>(self, f: impl FnOnce(T) -> V) -> InptStep<'s, V> {
        InptStep {
            data: self.data.map(f),
            rest: self.rest,
        }
    }

    /// Apply the given function to the successfully parsed type if any,
    /// producing a converted error if the function fails.
    pub fn try_map<V, E>(self, f: impl FnOnce(T) -> Result<V, E>) -> InptStep<'s, V>
    where
        E: StdError,
    {
        use self::error::InptContext;
        InptStep {
            data: self.data.and_then(|x| match f(x) {
                Ok(x) => Ok(x),
                Err(e) => Err(InptError {
                    context: vec![InptContext::AtStart, InptContext::Message(e.to_string())],
                }),
            }),
            rest: self.rest,
        }
    }
}

/// A class of characters, as defined by [`char_class!`](macro@char_class) and used for trimming.
#[derive(Clone, Copy)]
pub struct CharClass(#[doc(hidden)] pub &'static [(char, char)]);

/// The "\s" character class, used by default to trim types during parsing.
pub const WHITESPACE: CharClass = inpt_macros::char_class!(r"\s");

impl CharClass {
    /// Tests if the given char is a member of this class.
    pub fn contains(self, c: char) -> bool {
        match self.0.binary_search_by(|range| range.1.cmp(&c)) {
            Ok(_) => true,
            Err(index) => index < self.0.len() && self.0[index].0 <= c,
        }
    }

    /// Trim this character class off the beginning/end of the given string.
    pub fn trim(self, text: &str, end: bool) -> &str {
        match end {
            true => text.trim_matches(|c| self.contains(c)),
            false => text.trim_start_matches(|c| self.contains(c)),
        }
    }
}

/// The core parsing trait.
///
/// Although this can be implemented manually without too much work,
/// it is best to derive it as described in the [top-level documentation](crate#struct-syntax).
pub trait Inpt<'s>: Sized + 's {
    /// Consume a token of this type from the given text if possible, returning an error if not.
    /// If `end` is false, all remaining text should also be returned. Otherwise the text should be
    /// consumed entirely. All text must be trimmed with the given [`CharClass`] (typically but not
    /// always returned from [`Inpt::default_trim`]) before being passed to this function.
    ///
    /// <b color="ff5555">Consider [deriving `Inpt`](crate#struct-syntax) or calling [`crate::inpt()`] instead of using this directly.</b>
    fn step(
        text: &'s str,
        end: bool,
        trimmed: CharClass,
        guard: &mut RecursionGuard,
    ) -> InptStep<'s, Self>;

    /// Determine the class of characters which this type would like trimmed off of any text before parsing.
    /// This is inherited from the parent type if not otherwise defined.
    fn default_trim(inherited: CharClass) -> CharClass {
        inherited
    }
}

/// Lazily parse input as a sequence of type `T`.
pub struct InptIter<'s, T> {
    /// The remaining text to parse.
    pub text: &'s str,
    /// The first error encountered, if any.
    pub outcome: Result<(), InptError<'s>>,
    trim: CharClass,
    _p: PhantomData<T>,
}

impl<'s, T: Inpt<'s>> InptIter<'s, T> {
    /// Start parsing the given text, inheriting trim from the given class.
    pub fn new(text: &'s str, trim: CharClass) -> Self {
        Self {
            text,
            trim,
            outcome: Ok(()),
            _p: PhantomData,
        }
    }
}

impl<'s, T: Inpt<'s>> Iterator for InptIter<'s, T> {
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        let rest = self.trim.trim(self.text, false);
        // Really we should have previously trimmed with `true` in this case.
        if rest.is_empty() {
            return None;
        }

        let InptStep { data, rest } = T::step(rest, false, self.trim, &mut RecursionGuard::new());
        self.text = rest;
        match data {
            Ok(data) => Some(data),
            Err(err) => {
                if self.outcome.is_ok() {
                    self.outcome = Err(err);
                }
                None
            }
        }
    }
}

impl<'s, T: Inpt<'s>> Inpt<'s> for InptIter<'s, T> {
    fn step(
        text: &'s str,
        _end: bool,
        trimmed: CharClass,
        _: &mut RecursionGuard,
    ) -> InptStep<'s, Self> {
        InptStep {
            data: Ok(Self::new(text, trimmed)),
            rest: &text[text.len()..],
        }
    }
}

/// Broadly disables the default whitespace trimming on the inner type.
///
/// Types with custom trimming rules (e.g. number types) are not effected.
#[derive(Inpt, Debug, Copy, Clone)]
#[inpt(trim = "")]
pub struct NoTrim<T>(pub T);

/// A const regex used internally by [`macro@Inpt`].
pub struct LazyRegex {
    source: &'static str,
    re: OnceCell<Regex>,
}

impl LazyRegex {
    pub const fn new(source: &'static str) -> Self {
        Self {
            source,
            re: OnceCell::new(),
        }
    }
}

/// Prevents infinite parse trees.
pub struct RecursionGuard {
    hit: HashSet<(usize, fn() -> &'static str)>,
}

impl RecursionGuard {
    /// Start with no `check` calls registered.
    pub fn new() -> Self {
        RecursionGuard {
            hit: Default::default(),
        }
    }

    /// Call the given function if `check::<T>` has not already been
    /// performed at the start of `text`, otherwise produce an error.
    pub fn check<'s, T>(
        &mut self,
        text: &'s str,
        with: impl FnOnce(&mut Self) -> InptStep<'s, T>,
    ) -> InptStep<'s, T> {
        let key = (
            text.as_ptr() as usize,
            type_name::<T> as fn() -> &'static str,
        );
        if self.hit.insert(key) {
            let res = with(self);
            self.hit.remove(&key);
            res
        } else {
            InptStep {
                data: Err(InptError::recursion_at_start::<T>()),
                rest: text,
            }
        }
    }
}

impl Deref for LazyRegex {
    type Target = Regex;

    fn deref(&self) -> &Self::Target {
        self.re
            .get_or_init(|| RegexBuilder::new(self.source).build().unwrap())
    }
}

/// *The point of this crate.* Parse `T` from the given string.
pub fn inpt<'s, T: Inpt<'s>>(text: &'s str) -> InptResult<'s, T> {
    let trimmed = T::default_trim(WHITESPACE);
    T::step(
        trimmed.trim(text, true),
        true,
        trimmed,
        &mut RecursionGuard::new(),
    )
    .data
}

/// Parse `T` from stdin and print any errors on stderr.
///
/// If parsing fails, the process will be exited with status -1.
///
/// Note that the input text will be permanently allocated on the heap, allowing
/// the parsed type to contain `&'static str` strings.
/// This is the core function used by the [`#[inpt::main]` macro](crate#main).
pub fn inpt_stdio<T>() -> T
where
    T: Inpt<'static>,
{
    let mut text = Box::new(String::new());
    io::Read::read_to_string(&mut io::stdin(), &mut text)
        .expect("could not read utf8 text from stdin");
    match inpt::<T>(Box::leak(text).as_str()) {
        Ok(value) => value,
        Err(err) => {
            err.annotated_stderr("stdin").unwrap();
            process::exit(-1)
        }
    }
}
