Type of `std::iter::Map` with a function

Hi

I am trying to generalize the following to a generic over T (i32, i64, f32, etc.),

#[inline]
pub fn read_unaligned_i32(chunk: &[u8]) -> i32 {
    let chunk: [u8; 4] = match chunk.try_into() {
        Ok(v) => v,
        Err(_) => panic!(),
    };
    i32::from_le_bytes(chunk)
}

fn cast_i32<'a>(
    values: &'a [u8],
) -> std::iter::Map<std::slice::ChunksExact<'a, u8>, for<'r> fn(&'r [u8]) -> i32> {
    let values = values.chunks_exact(std::mem::size_of::<i32>());
    values.map(cast_unaligned_i32)
}

but I am struggling with the compiler:

error[E0308]: mismatched types
  --> src/lib.rs:39:5
   |
36 | ) -> Casted<'a, T> {
   |      ------------- expected `Map<ChunksExact<'a, u8>, for<'r> fn(&'r [u8]) -> T>` because of return type
...
39 |     values
   |     ^^^^^^ expected fn pointer, found fn item
   |
   = note: expected struct `Map<ChunksExact<'a, _>, for<'r> fn(&'r [u8]) -> _>`
              found struct `Map<ChunksExact<'_, _>, for<'r> fn(&'r [u8]) -> _ {read_unaligned::<T>}>`

playground

pub trait NativeType {
    type Bytes: AsRef<[u8]> + for<'a> TryFrom<&'a [u8], Error = std::array::TryFromSliceError>;

    fn from_le_bytes(bytes: Self::Bytes) -> Self;
}

macro_rules! native {
    ($type:ty) => {
        impl NativeType for $type {
            type Bytes = [u8; std::mem::size_of::<Self>()];

            #[inline]
            fn from_le_bytes(bytes: Self::Bytes) -> Self {
                Self::from_le_bytes(bytes)
            }
        }
    };
}

native!(i32);
native!(i64);

#[inline]
pub fn read_unaligned<T: NativeType>(chunk: &[u8]) -> T {
    let chunk: <T as NativeType>::Bytes = match chunk.try_into() {
        Ok(v) => v,
        Err(_) => panic!(),
    };
    T::from_le_bytes(chunk)
}

pub fn native_cast<'a, T: NativeType>(
    values: &'a [u8],
) -> std::iter::Map<std::slice::ChunksExact<'a, u8>, fn(&'a[u8]) -> T> {
    let values = values.chunks_exact(std::mem::size_of::<T>());
    let values = values.map(read_unaligned::<T>);
    values
}

fn main() {
    todo!()
}

interestingly, if I re-write

pub fn native_cast<'a, T: NativeType>(
    values: &'a [u8],
) -> std::iter::Map<std::slice::ChunksExact<'a, u8>, fn(&'a[u8]) -> T> {
    let values = values.chunks_exact(std::mem::size_of::<T>());
    values.map(read_unaligned::<T>)
}

it compiles. This won't work for me because once this iterator signature is used anywhere, the compiler error re-emerges on that usage.

Any ideas?

Your rewrite works because the return position is a coercion site. You could instead cast the function item to a function pointer (the compiler can infer the type of the function pointer):

-    let values = values.map(read_unaligned::<T>);
+    let values = values.map(read_unaligned::<T> as _);
     value

But I'm not sure what you mean by "this won't work for me".

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.