momvart
momvart

Reputation: 1999

Implement trait for multiple Fn types

I have a trait called Describer which has a function that accepts an array of bytes and returns a list of strings. For the sake of simplifying the codes, I want to accept both Fn(&[u8]) -> Vec<String> and Fn(&[u8]) -> String as a Describer.

So, here is what I have done:

trait Describer {
    fn get_parts(&self, data: &[u8]) -> Vec<String>;
}

impl Describer for dyn Fn(&[u8]) -> Vec<String> {
    fn get_parts(&self, data: &[u8]) -> Vec<String> {
        self(data)
    }
}

impl Describer for dyn Fn(&[u8]) -> String {
    fn get_parts(&self, data: &[u8]) -> Vec<String> {
        vec![self(data)]
    }
}

But if I use a closure (or a function pointer) in place of a Describer, the compiler complains that the trait bounds are not satisfied. For example:

let x: Box<dyn Describer> = Box::new(|data: &[u8]| String::from("x"));
let y: Box<dyn Describer> = Box::new(|data: &[u8]| vec![String::from("y")]);
the trait bound `[[email protected]:223:38: 223:51]: Describer` is not satisfied
the following other types implement trait `Describer`:
  (dyn for<'r> Fn(&'r [u8]) -> String + 'static)
  (dyn for<'r> Fn(&'r [u8]) -> Vec<String> + 'static)
required for the cast from `[[email protected]:223:38: 223:51]` to the object type `dyn Describer

However, if I implement the trait for a generic that implements the closure type, it will work but then not possible to have both of the closure types because of the conflicting implementation error.

impl<F: Fn(&[u8]) -> Vec<String>> Describer for F {
    fn get_parts(&self, data: &[u8]) -> Vec<String> {
        self(data)
    }
}

// Not working
impl<F: Fn(&[u8]) -> String> Describer for F {
    fn get_parts(&self, data: &[u8]) -> Vec<String> {
        self(data)
    }
}

Upvotes: 1

Views: 78

Answers (1)

Chayim Friedman
Chayim Friedman

Reputation: 70910

You can create a trait that both Vec<String> and String impl and convert them to Vec<String>, then impl Describer for functions with return type implementing this trait:

trait DescriberResult {
    fn convert(self) -> Vec<String>;
}

impl DescriberResult for Vec<String> {
    fn convert(self) -> Vec<String> { self }
}

impl DescriberResult for String {
    fn convert(self) -> Vec<String> { vec![self] }
}

impl<R: DescriberResult, F: Fn(&[u8]) -> R> Describer for F {
    fn get_parts(&self, data: &[u8]) -> Vec<String> {
        self(data).convert()
    }
}

Upvotes: 2

Related Questions