The parameter type Input
may not live long enough when using bytes:: length*
combinators
#643
-
First things first: Great framework! While working on a MQTT v5 parser I tried to refactorize this code snippet into using Original version
impl<'input> UnsubscribeProperties<'input> {
#[inline]
pub fn parse<'settings, Input, Error>(
parser_settings: &'settings Settings,
) -> impl Parser<Input, Self, Error> + use<'input, 'settings, Input, Error>
where
Input: Stream<Token = u8, Slice = &'input [u8]>
+ UpdateSlice
+ StreamIsPartial
+ Clone
+ 'input,
Error: ParserError<Input>
+ AddContext<Input, StrContext>
+ FromExternalError<Input, Utf8Error>
+ FromExternalError<Input, InvalidQosError>
+ FromExternalError<Input, InvalidPropertyTypeError>
+ FromExternalError<Input, UnknownFormatIndicatorError>,
{
combinator::trace(type_name::<Self>(), |input: &mut Input| {
// TODO: Can't use binary::length_and_then because it doesn't work
let data = binary::length_take(variable_byte_integer).parse_next(input)?;
let mut input = input.clone().update_slice(data);
let input = &mut input;
let mut properties = Self::default();
let mut parser = combinator::alt((
combinator::eof.value(None),
Property::parse(parser_settings).map(Some),
));
while let Some(p) = parser.parse_next(input)? {
match p {
Property::UserProperty(key, value) => {
properties.user_properties.push((key, value))
}
_ => return Err(ErrMode::Cut(Error::assert(input, "Invalid property type"))),
}
}
Ok(properties)
})
.context(StrContext::Label(type_name::<Self>()))
}
} The snippet let data = binary::length_take(variable_byte_integer).parse_next(input)?;
let mut input = input.clone().update_slice(data);
let input = &mut input; was adapted from If I try to use Modified version with length_and_then
impl<'input> UnsubscribeProperties<'input> {
#[inline]
pub fn parse<'settings, Input, Error>(
parser_settings: &'settings Settings,
) -> impl Parser<Input, Self, Error> + use<'input, 'settings, Input, Error>
where
Input: Stream<Token = u8, Slice = &'input [u8]>
+ UpdateSlice
+ StreamIsPartial
+ Clone
+ 'input,
Error: ParserError<Input>
+ AddContext<Input, StrContext>
+ FromExternalError<Input, Utf8Error>
+ FromExternalError<Input, InvalidQosError>
+ FromExternalError<Input, InvalidPropertyTypeError>
+ FromExternalError<Input, UnknownFormatIndicatorError>,
{
combinator::trace(
type_name::<Self>(),
binary::length_and_then(variable_byte_integer, |input: &mut Input| {
let mut properties = Self::default();
let mut parser = combinator::alt((
combinator::eof.value(None),
Property::parse(parser_settings).map(Some),
));
while let Some(p) = parser.parse_next(input)? {
match p {
Property::UserProperty(key, value) => {
properties.user_properties.push((key, value))
}
_ => {
return Err(ErrMode::Cut(Error::assert(input, "Invalid property type")))
}
}
}
Ok(properties)
}),
)
.context(StrContext::Label(type_name::<Self>()))
}
} I get the following error: cargo check output
Checking sansio-mqtt5 v0.1.0 (/Users/compux72/Developer/sans-io-mqtt/crates/sansio-mqtt5)
error[E0310]: the parameter type `Input` may not live long enough
--> crates/sansio-mqtt5/src/parser/unsubscribe.rs:83:9
|
83 | / combinator::trace(
84 | | type_name::<Self>(),
85 | | binary::length_and_then(variable_byte_integer, |input: &mut Input| {
86 | | let mut properties = Self::default();
... |
105 | | }),
106 | | )
| | ^
| | |
| |_________the parameter type `Input` must be valid for the static lifetime...
| ...so that the type `Input` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound
|
75 | + 'input + 'static,
| +++++++++
error[E0310]: the parameter type `Input` may not live long enough
--> crates/sansio-mqtt5/src/parser/unsubscribe.rs:83:9
|
83 | / combinator::trace(
84 | | type_name::<Self>(),
85 | | binary::length_and_then(variable_byte_integer, |input: &mut Input| {
86 | | let mut properties = Self::default();
... |
106 | | )
107 | | .context(StrContext::Label(type_name::<Self>()))
| | ^
| | |
| |________________________________________________________the parameter type `Input` must be valid for the static lifetime...
| ...so that the type `Input` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound
|
75 | + 'input + 'static,
| +++++++++
error[E0310]: the parameter type `Input` may not live long enough
--> crates/sansio-mqtt5/src/parser/unsubscribe.rs:85:13
|
85 | / binary::length_and_then(variable_byte_integer, |input: &mut Input| {
86 | | let mut properties = Self::default();
87 | |
88 | | let mut parser = combinator::alt((
... |
104 | | Ok(properties)
105 | | }),
| | ^
| | |
| |______________the parameter type `Input` must be valid for the static lifetime...
| ...so that the type `Input` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound
|
75 | + 'input + 'static,
| +++++++++
For more information about this error, try `rustc --explain E0310`.
error: could not compile `sansio-mqtt5` (lib) due to 3 previous errors I have no idea why rustc asks for How to reproduce
git clone https://github.com/Altair-Bueno/sansio-mqtt
# Apply the git patch using `git am < PATCH_FILE`
cargo check diff --git a/crates/sansio-mqtt5/src/parser/unsubscribe.rs b/crates/sansio-mqtt5/src/parser/unsubscribe.rs
index 7a9426d..67aa4ab 100644
--- a/crates/sansio-mqtt5/src/parser/unsubscribe.rs
+++ b/crates/sansio-mqtt5/src/parser/unsubscribe.rs
@@ -80,30 +80,30 @@ impl<'input> UnsubscribeProperties<'input> {
+ FromExternalError<Input, InvalidPropertyTypeError>
+ FromExternalError<Input, UnknownFormatIndicatorError>,
{
- combinator::trace(type_name::<Self>(), |input: &mut Input| {
- // TODO: Can't use binary::length_and_then because it doesn't work
- let data = binary::length_take(variable_byte_integer).parse_next(input)?;
- let mut input = input.clone().update_slice(data);
- let input = &mut input;
-
- let mut properties = Self::default();
+ combinator::trace(
+ type_name::<Self>(),
+ binary::length_and_then(variable_byte_integer, |input: &mut Input| {
+ let mut properties = Self::default();
- let mut parser = combinator::alt((
- combinator::eof.value(None),
- Property::parse(parser_settings).map(Some),
- ));
+ let mut parser = combinator::alt((
+ combinator::eof.value(None),
+ Property::parse(parser_settings).map(Some),
+ ));
- while let Some(p) = parser.parse_next(input)? {
- match p {
- Property::UserProperty(key, value) => {
- properties.user_properties.push((key, value))
+ while let Some(p) = parser.parse_next(input)? {
+ match p {
+ Property::UserProperty(key, value) => {
+ properties.user_properties.push((key, value))
+ }
+ _ => {
+ return Err(ErrMode::Cut(Error::assert(input, "Invalid property type")))
+ }
}
- _ => return Err(ErrMode::Cut(Error::assert(input, "Invalid property type"))),
}
- }
- Ok(properties)
- })
+ Ok(properties)
+ }),
+ )
.context(StrContext::Label(type_name::<Self>()))
}
} |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments
-
If I remove Also, is there a reason the parsers are so generic, rather than working with concrete Input and Error? |
Beta Was this translation helpful? Give feedback.
-
My God, so simple yet so easy to miss... You have no idea how much time I spent wondering what the hell rustc was complaining about. I clearly see it now. Thanks I think I added it when rustc complained about something else, didn't work, and I just stick with it until now. Changes applied: https://github.com/Altair-Bueno/sansio-mqtt/tree/663872075f8b2c57fafff46670ea723fc7117d93
I'm using generic errors and inputs mostly because it can be done that way, just for the fun of it. Although now that I've finished writing the parser, I recognize it is not that fun to work this way. Thanks again for your wisdom, and happy new year! |
Beta Was this translation helpful? Give feedback.
If I remove
+ 'input
from every parser, it builds. Is there a reason that is there? If you look at Winnow's generic parsers, we don't specify this.Also, is there a reason the parsers are so generic, rather than working with concrete Input and Error?