Richard Neumann
Richard Neumann

Reputation: 3371

Generic trait for u8 iterators with function that returns a bool iterator

I have this code:

pub trait BytesToBits<T>: Iterator<Item = u8>
where
    T: Iterator<Item = bool>,
{
    fn bits(&mut self) -> T;
}

impl<T> BytesToBits<T> for dyn Iterator<Item = u8>
where
    T: Iterator<Item = bool>,
{
    fn bits(&mut self) -> T {
        self.flat_map(|byte| (0..8).map(move |offset| byte & (1 << offset) != 0))
    }
}

However, compiling it results in:

error[E0308]: mismatched types
  --> src/bitstream.rs:13:9
   |
8  | impl<T> BytesToBits<T> for dyn Iterator<Item = u8>
   |      - this type parameter
...
12 |     fn bits(&mut self) -> T {
   |                           - expected `T` because of return type
13 |         self.flat_map(|byte| (0..8).map(move |offset| byte & (1 << offset) != 0))
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter `T`, found struct `FlatMap`
   |
   = note: expected type parameter `T`
                      found struct `FlatMap<&mut (dyn Iterator<Item = u8> + 'static), Map<std::ops::Range<{integer}>, [closure@src/bitstream.rs:13:41: 13:54]>, [closure@src/bitstream.rs:13:23: 13:29]>`

I am new to Rust and do not know what I exactly did wrong there and how to resolve the issue.

My goal is to have a trait BytesToBits that extends all Iterator<Item = u8> by providing them with a method bits() that returns an Iterator<Item = bool>.

Upvotes: 0

Views: 194

Answers (2)

Richard Neumann
Richard Neumann

Reputation: 3371

Thanks for the comments and the answer. I think my issue again boiled down to the fact, that you cannot return traits from functions of traits [1]. I solved it now with a custom iterator:

pub trait BytesToBits<T>
where
    T: Iterator<Item = bool>,
{
    fn bits(self) -> T;
}

impl<T> BytesToBits<BytesToBitsIterator<T>> for T
where
    T: Iterator<Item = u8>,
{
    fn bits(self) -> BytesToBitsIterator<T> {
        BytesToBitsIterator::from(self)
    }
}

pub struct BytesToBitsIterator<T>
where
    T: Iterator<Item = u8>,
{
    bytes: T,
    current: Option<u8>,
    index: u8,
}

impl<T> From<T> for BytesToBitsIterator<T>
where
    T: Iterator<Item = u8>,
{
    fn from(bytes: T) -> Self {
        Self {
            bytes,
            current: None,
            index: 0,
        }
    }
}

impl<T> Iterator for BytesToBitsIterator<T>
where
    T: Iterator<Item = u8>,
{
    type Item = bool;

    fn next(&mut self) -> Option<Self::Item> {
        if self.index > 7 {
            self.current = None;
            self.index = 0;
        }

        let current = match self.current {
            None => match self.bytes.next() {
                None => {
                    return None;
                }
                Some(byte) => {
                    self.current = Some(byte);
                    byte
                }
            },
            Some(byte) => byte,
        };

        let bit = current & (1 << self.index) != 0;
        self.index += 1;
        Some(bit)
    }
}

[1] Implement trait that has function which return traits

Upvotes: 0

complikator
complikator

Reputation: 282

I think that this solves your problem:

pub trait BytesToBits<T>: Iterator<Item=u8>
    where
        T: Iterator<Item=bool>,
{
    fn bits(&mut self) -> Box<dyn Iterator<Item=bool> + '_>;
}

impl<T> BytesToBits<T> for dyn Iterator<Item=u8>
    where
        T: Iterator<Item=bool>,
{
    fn bits(&mut self) -> Box<dyn Iterator<Item=bool> + '_> {
        Box::new(self.flat_map(|byte| (0..8).map(move |offset| byte & (1 << offset) != 0)))
    }
}

But if someone will find explanation why the first approach is wrong I will be grateful :D

Upvotes: 1

Related Questions