I'm writing Rust for the first time in awhile, and I ran into an issue with mutability, that I figured I'd write up.

The thing I was trying to do was have a Client that creates an XML response body, and then makes a request to a server.  There are several parameter that make their way into the response that I want to be immutable, and I want the resulting XML to be available as bytes.  I went through three iterations.

My first attempt looked like this:

struct Client<'a> {
    params: Params,
    writer: EventWriter<&'a mut Vec<u8>>,
    buffer: &'a Vec<u8>,
}
graph classDef mut fill:#adf,stroke-dasharray: 5 5 subgraph Client p(parameters) b(buffer) w(writer) s(self) s-->p s-->b:::mut s-->w:::mut w-->b f1(fn write_request) f1-->s end m[mutable]:::mut i[immutable]

I put the writer and the buffer on the Client struct.  However, in methods on Client, I would need have &mut self as an argument in order to modify the writer / buffer. I wanted to access the parameters without modifying them, but  I still needed to borrow them as mutable since I was borrowing self as mutable. By modifying the writer or buffer, I'm modifying the whole Client struct.  One of the fundamental rules about the borrow checker is that you can't borrow something mutably while also borrowing it mutably or immutably somewhere else.

This led me to separate the Client and a new Writer struct that I create on demand in the functions.  Then I can pass around the Writer to other methods as mutable without having to borrow self on the Client as mutable.

graph TD classDef mut fill:#adf,stroke-dasharray: 5 5 subgraph Writer s2(self):::mut s2-->b(buffer):::mut s2-->w(writer):::mut w-->b end subgraph Client p(parameters) s(self) s-->p f(fn write_req)-->s2 f-->s end

I thought this was pretty neat because it pushed me to a design that makes more sense overall.  The main reason to create the Client was to be able to easily make multiple requests more conveniently.  A second request would need another writer and buffer, so separating them fits the problem better.

However, this came with another problem.  The writer field on the Writer struct needed to mutably borrow the buffer in order to output to it.  This made it challenging to also keep a reference to the buffer on the Writer struct (again due to the requirement that a mutable borrow excludes any other borrows).  This made this structure not workable.

Finally, this structure is the one that ended up working:

graph LR classDef mut fill:#adf,stroke-dasharray: 5 5 f(fn write_req)-->s f-->writer:::mut subgraph Function[Function scope] writer:::mut end buffer:::mut-->f subgraph Client p(parameters) s(self) s-->p end

I passed in a mutable reference to a buffer and created a writer referencing it.  I then used the writer to interact with the buffer throughout, and once I was done writing, I could count on the buffer I passed to be populated with the XML request.