Relrin
Relrin

Reputation: 790

Convert vector of enum values into an another vector

I have the following code which generates a vector of bytes from the passed vector of enum values:

#[derive(Debug, PartialEq)]
pub enum BertType {
    SmallInteger(u8),
    Integer(i32),
    Float(f64),
    String(String),
    Boolean(bool),
    Tuple(BertTuple),
}

#[derive(Debug, PartialEq)]
pub struct BertTuple {
    pub values: Vec<BertType>
}

pub struct Serializer;

pub trait Serialize<T> {
    fn to_bert(&self, data: T) -> Vec<u8>;
}

impl Serializer {
    fn enum_value_to_binary(&self, enum_value: BertType) -> Vec<u8> {
        match enum_value {
            BertType::SmallInteger(value_u8) => self.to_bert(value_u8),
            BertType::Integer(value_i32) => self.to_bert(value_i32),
            BertType::Float(value_f64) => self.to_bert(value_f64),
            BertType::String(string) => self.to_bert(string),
            BertType::Boolean(boolean) => self.to_bert(boolean),
            BertType::Tuple(tuple) => self.to_bert(tuple),
        }
    }
}

// some functions for serialize bool/integer/etc. into Vec<u8>
// ...

impl Serialize<BertTuple> for Serializer {
    fn to_bert(&self, data: BertTuple) -> Vec<u8> {
        let mut binary: Vec<u8> = data.values
            .iter()
            .map(|&item| self.enum_value_to_binary(item)) // <-- what the issue there?
            .collect();

        let arity = data.values.len();
        match arity {
            0...255 => self.get_small_tuple(arity as u8, binary),
            _ => self.get_large_tuple(arity as i32, binary),
        }
    }
}

But when compiling, I receive an error with iterating around map:

error: the trait bound `std::vec::Vec<u8>: std::iter::FromIterator<std::vec::Vec<u8>>` is not satisfied [E0277]
           .collect();
           ^~~~~~~
help: run `rustc --explain E0277` to see a detailed explanation
note: a collection of type `std::vec::Vec<u8>` cannot be built from an iterator over elements of type `std::vec::Vec<u8>`
error: aborting due to previous error
error: Could not compile `bert-rs`.

How can I fix this issue with std::iter::FromIterator?

Upvotes: 1

Views: 1846

Answers (1)

allTwentyQuestions
allTwentyQuestions

Reputation: 1240

The problem is that enum_value_to_binary returns a Vec<u8> for each element in values. So you end up with an Iterator<Item=Vec<u8>> and you call collect::<Vec<u8>>() on that, but it doesn't know how to flatten the nested vectors. If you want all the values to be flattened into one Vec<u8>, then you should use flat_map instead of map:

let mut binary: Vec<u8> = data.values
            .iter()
            .flat_map(|item| self.enum_value_to_binary(item).into_iter()) 
            .collect();

Or, slightly more idiomatic and performant, you can just have enum_value_to_binary return an iterator directly.

Also, the iter method returns an Iterator<Item=&'a T>, which means you are just borrowing the elements, but self.enum_value_to_binary wants to take ownership over the value. There's a couple of ways to fix that. One option would be to use into_iter instead of iter, which will give you the elements by value. If you do that, you'll move the arity variable up to before the binary variable, since creating the binary variable will take ownership (move) data.values.

The other option would be to change self.enum_value_to_binary to take it's argument by reference.

Also possible that you meant for the type of binary to actually be Vec<Vec<u8>>.

Upvotes: 2

Related Questions