Implement abstraction on printable command response

I am developing a cli app that makes http responses to an API server. Sometimes I wan't to show the user the body of the response and sometimes I want to transform that response into something printable I can show the user, a table for example.

The functions that execute the commands receive a closure: impl FnOnce(T) -> Result<()> that is called to show the result to the user.

I came up with the following traits and classes to do this:

pub struct TableResponse {
    pub headers: HeaderMap,
    pub str: String
}

impl PrintableResponse for TableResponse {
    fn headers(&mut self) -> HashMap<String, String> {
        HashMap::new() // TODO: Implement
    }

    fn read(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
        Ok(buf.write(self.str.as_bytes())?)
    }
}

pub trait PrintableResponse {
    fn headers(&mut self: Self) -> HashMap<String, String>;

    fn read(&mut self: Self, buf: &mut Vec<u8>) -> Result<usize>;
}

impl PrintableResponse for Response {
    fn headers(&mut self) -> HashMap<String, String> {
        let mut res: HashMap<String, String> = HashMap::new();

        for (k, v) in Response::headers(self).iter() {
            res.insert(k.to_string(), v.to_str().unwrap_or("").to_owned());
        }

        res
    }

    fn read(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
        Ok(self.read_to_end(buf)?)
    }
}

But this is kind of a mess. I have to use Box<dyn PrintableResult> everywhere in the signatures wherever I want to pass the closure, but also when converting a Result to a Box<dyn PrintableResult> is not always pretty.

I tried to create a wrapper type around this:

pub struct PrintableWrapped {
    inner: Box<dyn PrintableResponse>,
}

impl From<Response> for PrintableWrapped {
    fn from(r: Response) -> Self {
        PrintableWrapped { inner: Box::new(r) }
    }
}

impl From<TableResponse> for PrintableWrapped {
    fn from(r: TableResponse) -> Self {
        PrintableH { inner: Box::new(r) }
    }
}

Which is ok, I then use PrintableWrapped in function definitions, and just call .into() whenever I need a PrintableWrapped from a Response, but this looks like a lot of boilerplate for such a simple thing and I feel I am fighting the type system here.

Is there a simpler/more idiomatic/rusty way to do this?

Thanks.

Maybe it's easier to read the code than my explanation:

https://github.com/simao/ota-cli/blob/305a13a1480f3fa9d5be8a6235cc88f629f96a09/src/http.rs#L28

It seems like a lot of boilerplate for this, but it works...

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.