Working on base85 decoding using iterators. Preliminary implementation, so the algorithm may not be correct - just trying to get past the borrow checker for now.
pub fn decode(indata: impl IntoIterator<Item=impl Borrow<u8>> + 'static) -> impl Iterator<Item=Result<u8>> {
#[inline]
fn char85_to_byte(c: u8) -> Result<u8> {
match c {
b'0'..=b'9' => Ok(c - b'0'),
b'A'..=b'Z' => Ok(c - b'A' + 10),
b'a'..=b'z' => Ok(c - b'a' + 36),
b'!' => Ok(62),
b'#' => Ok(63),
b'$' => Ok(64),
b'%' => Ok(65),
b'&' => Ok(66),
b'(' => Ok(67),
b')' => Ok(68),
b'*' => Ok(69),
b'+' => Ok(70),
b'-' => Ok(71),
b';' => Ok(72),
b'<' => Ok(73),
b'=' => Ok(74),
b'>' => Ok(75),
b'?' => Ok(76),
b'@' => Ok(77),
b'^' => Ok(78),
b'_' => Ok(79),
b'`' => Ok(80),
b'{' => Ok(81),
b'|' => Ok(82),
b'}' => Ok(83),
b'~' => Ok(84),
v => Err(Error::UnexpectedCharacter(v)),
}
}
indata
.into_iter()
.map(|v|*v.borrow())
.filter(|v| !(*v == 32 || *v == 10 || *v == 11 || *v == 13))
.chunks(5)
.into_iter()
.map(|mut v| {
let (a,b,c,d,e) = (v.next(), v.next(), v.next(), v.next(), v.next());
let accumulator = u32::from(char85_to_byte(a.unwrap())?)
+ u32::from(b.map_or(Err(Error::UnexpectedEnd), char85_to_byte)?) * 85u32.pow(1)
+ u32::from(c.map_or(Ok(0), char85_to_byte)?) * 85u32.pow(2)
+ u32::from(d.map_or(Ok(0), char85_to_byte)?) * 85u32.pow(3)
+ u32::from(e.map_or(Ok(0), char85_to_byte)?) * 85u32.pow(4);
Ok([
Some((accumulator >> 24) as u8),
c.map(|_|(accumulator >> 16) as u8),
d.map(|_|(accumulator >> 8) as u8),
e.map(|_|accumulator as u8)
])
})
.flatten_ok()
.filter_map_ok(|v| v)
}
However this gives the following error:
error[E0716]: temporary value dropped while borrowed
--> src/lib.rs:96:5
|
96 | indata
| _____^
| |_____|
| ||
97 | || .into_iter()
98 | || .map(|v|*v.borrow())
99 | || .filter(|v| !(*v == 32 || *v == 10 || *v == 11 || *v == 13))
100 | || .chunks(5)
| ||__________________^ creates a temporary which is freed while still in use
... |
114 | | ])
115 | | })
| |___________- argument requires that borrow lasts for `'static`
...
118 | }
| - temporary value is freed at the end of this statement
For more information about this error, try `rustc --explain E0716`.
What's still borrowed? Everything I can think of should be getting passed by value.
Much appreciated.
I guess that the missing methods are coming from the de-facto standard iteration library, namely, itertools
. Therefore, the minimized example is this:
use itertools::Itertools;
pub fn decode(indata: Vec<u8>) -> impl Iterator<Item = u8> {
indata.into_iter().chunks(2).into_iter().flatten()
}
Errors:
error[E0716]: temporary value dropped while borrowed
--> src/lib.rs:4:5
|
4 | indata.into_iter().chunks(2).into_iter().flatten()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------
| |
| creates a temporary which is freed while still in use
| argument requires that borrow lasts for `'static`
5 | }
| - temporary value is freed at the end of this statement
The reason for this error is the fact that IntoChunks
is not iterable by value - only by reference; the second .into_iter()
is called not on IntoChunks
itself, but on a reference to it.
Not sure why it was implemented this way - this might warrant a question to itertools
's authors, or even a PR to add the owned alternative, if it is deemed feasible.