impl Parser
, but since they're different opaque types, rustc doesn't like it at all
dispatch!
parser which does exactly this https://docs.rs/combine/4.0.0-beta.1/src/combine/parser/choice.rs.html#800-816
FnOpaque
impl Trait
and which are generic over Input
. my compile times have absolutely skyrocketed and i'm looking for a way to bring them down. i've isolated all of my parser logic into a separate crate, but that doesn't seem to help – the outer crate compile times are still brutal.
impl Trait
shouldn't harm compiletimes much on its own
R: Read
fn n_digits<Input>(min: usize, max: usize) -> impl Parser<Input, Output = i32>
where
Input: Stream<Token = char>,
// Necessary due to rust-lang/rust#24159
Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
{
count_min_max(min, max, digit()).map(|s: String| {
s.parse::<i32>().unwrap()
})
}
s.parse
fails, but despite diving into a few codebases that use combine and trying many things, I'm not getting anywhere. Can anyone help me out?
from_str(count_min_max::<String, _, _>(min, max, digit()))
parse::<i32>
is acceptable
and_then
like from_str
does and substitute your own message https://github.com/Marwes/combine/blob/a358c88933bb58c4df0d9a0212b4a33d2b24be7b/src/parser/combinator.rs#L1165-L1169
I did stumble onto StreamErrorFor::<Input>::other
eventually yesterday, and ended up with
fn n_digits<Input>(min: usize, max: usize) -> impl Parser<Input, Output = i32>
where
Input: Stream<Token = char>,
// Necessary due to rust-lang/rust#24159
Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
{
count_min_max(min, max, digit()).and_then(|s: String| {
s.parse().map_err(StreamErrorFor::<Input>::other)
})
}
Which was acceptable. I'll try out from_str
tonight though and compare the error messages that they generate, looks like they may arrive at different errors, though I'm not sure how they'll differ.
captures
I get some incredible error spam that's hard to sort through.
fn main() {
let mut p =
captures(Regex::new(r"<((?:\\\\|\\>|[^>\n])*)>").unwrap())
.map(|captures: Vec<&str>| String::from(captures[1]));
let input = "<hello>";
let result = p.easy_parse(input);
match result {
Ok((value, _remaining_input)) => println!("{:?}", value),
Err(err) => println!("{}", err)
}
}
fn custom_status<Input>() -> impl Parser<Input, Output = String>
where
Input: Stream<Token = char>,
// Necessary due to rust-lang/rust#24159
Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
{
captures(Regex::new("<(\\\\|\\>|[^>\n])>").unwrap()).map(|captures: Vec<&str>| String::from(captures[1]))
}
Goddam, I am not nearly familiar enough with Rust to be doing this, but I did figure out how to make my function compile:
/**
* Parses a status.
*/
fn custom_status<'a, Input: 'a>() -> impl Parser<Input, Output = String> + 'a
where
Input: Stream<Token = char>,
Input: RangeStreamOnce<Range = &'a str>,
// Necessary due to rust-lang/rust#24159
Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
{
captures(Regex::new(r"<((?:\\\\|\\>|[^>\n])*)>").unwrap()).map(|captures: Vec<&str>| String::from(captures[1]))
}
I am dubious that this is the easiest way though...
i have been increasingly writing parsers that have chains of the form
.then(|val| {
value(val)
.and(.........
and I figure that there could be a combinator here that passes in the output of the previous parser as an immutable ref for dispatching but then just forwards that value through without consuming it