Type coercion for `Input` in `8.0.0`
Problem
When upgrading from 7.* to 8.0.0 I noticed that tag(b"hello") now produces an error.
the trait `Input` is not implemented for `&[u8; 5]`
This is due to the shift from the InputLength trait being implemented for tag in 7.* https://docs.rs/nom/7.1.3/nom/bytes/complete/fn.tag.html
To tag must implement Input in 8.0.0: https://docs.rs/nom/8.0.0/nom/bytes/complete/fn.tag.html
Interim Solution
A way to fix this in the interim is to coerce the type into &[u8] which Input is implemented for. i.e. tag(b"hello" as &[u8]).
Possible Fix
Implement Input for &[u8; N] for any const N: usize
I met the same problem today. This isn't possible to implement to impl<'a, const N: usize> Input for &'a [u8; N] because of Input::take (and other sibling methods) which returns Self (or (Self, Self) in the case of take_split):
https://github.com/rust-bakery/nom/blob/2cec1b3e4c9ccac62c902d60c00de6d1549ccbe1/src/traits.rs#L42-L47
We may want to refactor that by splitting the Input trait into 2 traits. Thoughts @Geal? I didn't check the implication of that yet. It's probably more trait bound checks for a couple of combinators.
Alternatively, we can add another associated type for the output of take() & siblings, à laIter & IterIndices:
https://github.com/rust-bakery/nom/blob/2cec1b3e4c9ccac62c902d60c00de6d1549ccbe1/src/traits.rs#L23-L36
Something like:
pub trait Input: Clone + Sized {
// …
type TakeOutput;
fn take(&self, index: usize) -> Self::TakeOutput;
// …
}
that might make it way more complex. Are there other alternatives? maybe making Parser::parse take a Into<I> ?
@Hywan Yeah that makes sense why that won't do it.
@Geal Another option to the list other than splitting up the Input trait could be a separate one that can do the conversion i.e.
pub trait IntoInput {
type Input: Input;
fn into_input(self) -> Self::Input;
}
impl<'a, const N: usize> IntoInput for &'a [u8; N] {
type Input = &'a [u8];
fn into_input(self) -> Self::Input {
self as &[u8]
}
}
impl<T: Input> IntoInput for T {
type Input = T;
fn into_input(self) -> Self::Input {
self
}
}
fn tag<I>(input: I) where I: IntoInput {
let input = input.into_input();
}
Or something of the like. Similar to the Into<I> but with the trait bounds.
I like this IntoInput solution. This could applied in more places, where we transparently translate any parameter that supports it into the correctly supported Input type. You can also provide a good standard implementation such that no API breaks, but you do accept way more types as inputs.
Something like this?
https://github.com/rust-bakery/nom/pull/1810/files#diff-172747fc43e38d33de743b2d5f564ad6440570670af7aa912235399448a55c7cR570