(For the background of problem, you can jump to this)
MWE in Rust 1.76:
/// The trait similar from [`From`]
/// but with a parser to determine how it will be parsed into.
///
/// It will be implemented to support `parser.parse::<Target>(source)` grammar.
trait ParseFrom<From, Parser> {
fn parse_from(from: From, parser: Parser) -> Self;
}
/// Source data, which is needed to be parsed into `Target`
#[derive(Debug, Clone)]
struct Source(String);
/// Target
#[derive(Debug)]
struct Target(Source);
/// The parser parsing `Source` into `Target`
/// * It will references some referenced data, so contains a lifetime parameter.
#[derive(Debug)]
struct Parser<'a> {
data: &'a str,
}
/// The parse state for parsing
#[derive(Debug)]
struct ParseState<'a> {
data: &'a str,
parse_count: usize,
source: Source,
}
impl<'a> Parser<'a> {
/// Build the parse state to parse the source data
pub fn build_state(&self, source: Source) -> ParseState<'a> {
ParseState {
data: "S", // any possible data using in parsing
parse_count: 0,
source,
}
}
}
impl<'a> ParseState<'a> {
/// Let the state start to parse to calculate the output.
/// * It should be generic function to reuse the function name likes [`str::parse`]
fn parse<To>(&'a mut self) -> To
where
To: ParseFrom<(), &'a mut Self>,
{
To::parse_from((), self)
}
}
/// () ---[ParseState]--> Target
impl<'a> ParseFrom<(), &'a mut ParseState<'a>> for Target {
/// Run the parse progress to yield result
fn parse_from(_: (), state: &'a mut ParseState) -> Self {
// the values in parse state may be changed
state.parse_count += 1;
Target(state.source.clone())
}
}
/// Source ---[Parser]--> ParserState --> AnyTarget
impl<'a, AnyTarget> ParseFrom<Source, &'a Parser<'a>> for AnyTarget
where
// Type `AnyTarget` should be possible to be yielded from `ParseState`
AnyTarget: ParseFrom<(), &'a mut ParseState<'a>>,
{
/// For all things `ParserState` can yield, it can be parsed from `Source`
fn parse_from(source: Source, parser: &'a Parser) -> Self {
// Build the parse state
let mut state = parser.build_state(source);
// Let the state parse the inner data to yield a result
let result = state.parse(); // line A
// Explicitly destruct the state after parsing data, to show more details
drop(state); // line B
// Return the result of parsing
result
}
}
At line A:
error[E0597]: `state` does not live long enough
--> main.rs:76:22
|
65 | impl<'a, AnyTarget> ParseFrom<Source, &'a Parser<'a>> for AnyTarget
| -- lifetime `'a` defined here
...
73 | let mut state = parser.build_state(source);
| --------- binding `state` declared here
...
76 | let result = state.parse(); // line A
| ^^^^^--------
| |
| borrowed value does not live long enough
| argument requires that `state` is borrowed for `'a`
...
83 | }
| - `state` dropped here while still borrowed
At line B:
error[E0505]: cannot move out of `state` because it is borrowed
--> main.rs:79:14
|
65 | impl<'a, AnyTarget> ParseFrom<Source, &'a Parser<'a>> for AnyTarget
| -- lifetime `'a` defined here
...
73 | let mut state = parser.build_state(source);
| --------- binding `state` declared here
...
76 | let result = state.parse(); // line A
| -------------
| |
| borrow of `state` occurs here
| argument requires that `state` is borrowed for `'a`
...
79 | drop(state); // line B
| ^^^^^ move out of `state` occurs here
How to resolve this lifetime problem, making guarantee to the compiler that the variable result
don't borrow anything from variable state
?
Also see Rust Playground