Idiomatic way for passing an optional, mutable reference around?


I’m new to Rust and I’m working on an application that serializes some data into a byte buffer. There are several methods that take an &mut Option<&mut Buffer> and some data and return Result<usize, String>. If some buffer is given, the data is written to the buffer and the number of bytes written is returned; if None is given, the functions just return the number of bytes that would have written. See below for a simplified example.

Constructs such as &mut None and &mut Some(...) look a bit awkward to me, esp. since the Option itself is never modified (i.e. cannot be modified), just it’s contents. But I understand why &Option<&mut Buffer> does not work, since it would allow multiple immutable references to the Option and therefore the contained mutable reference to the Buffer.

Is there a “better” or more idiomatic way to pass an optional, mutable Buffer reference through the code?

The much simplified example:

type Buffer = Vec<u8>;

fn foo(buf: &mut Option<&mut Buffer>) -> Result<usize, String> {
    let mut size: usize = 0;
    size += try!(pack(buf, 1));
    size += try!(pack(buf, 2));
    size += try!(pack(buf, 3));

fn pack(buf: &mut Option<&mut Buffer>, val: u8) -> Result<usize, String> {
    if let &mut Some(ref mut buf) = buf {

fn main() {
    let mut buf = vec![];
    let estimate = foo(&mut None).unwrap();
    let actual = foo(&mut Some(&mut buf)).unwrap();
    assert_eq!(estimate, actual);
    println!("{} bytes written: {:?}", actual, buf);

The actual implementation of the Buffer type is more than just a byte vector but I think is irrelevant to the question.


I think you want just Option<&mut Buffer>. You don’t want to change the option itself, you want to use the underlying buffer.


If I just use Option<&mut Buffer> then a call like try!(pack(buf, 1)); passes ownership of the Option to the pack method and I cannot use buf any more in foo after that.


Weird, I was sure that Option<&mut Something> is copy! Thanks for clearing this up. Then, I think &mut Option<Buffer> should work?

struct Buff;

fn pack(b: &mut Option<Buff>) { }

fn main() {
    let mut buff: Option<Buff> = Some(Buff);
    pack(&mut buff);
    pack(&mut buff);


If &mut T was Copy, you’d have two mutable pointers to the same thing, which would alias them, which is wrong by definition.


Hm, how does

fn by_ref(s: &mut S) {}

fn main() {
    let mut s = S;
        let r = &mut s;

work then?


And why this sort of works?

struct S;

fn by_opt_ref(s: Option<&mut S>) {}

fn foo(r: Option<&mut S>) {
    if let Some(r) = r {

        let l = Some(r); 

        // Next one will fail.
        // Why the first two work then?
        // by_opt_ref(Some(r)); 

fn main(){}



I believe this is reborrowing.

Note the help for the error here:

   = note: move occurs because `r` has type `&mut S`, which does not implement the `Copy` trait

One reason why this is safe but being Copy isn’t: this code doesn’t let you have access to the other pointer while you’re inside the function.


See: Reborrow vs move


You could pass an io::Write instead of a Buffer and create a special writer that just counts the bytes and discards them, like:

fn foo<W: std::io::Write>(buf: &mut W) -> std::io::Result<()> {

struct Counter {
    pub count: u64,

impl std::io::Write for Counter {
    fn write(&mut self, buf: &[u8]) -> Result<usize> { self.count += buf.len(); Ok(buf.len()) }
    fn flush(&mut self) -> Result<()> {}

fn main() {
    let mut counter = Counter { count: 0 };
    let mut buf = vec![];
    foo(&mut counter).unwrap();
    foo(&mut buf).unwrap();
    assert_eq!(counter.count, buf.len());
    println!("{} bytes written: {:?}", buf.len(), buf);



Thanks, @troplin, I was actually thinking about using a counting-only buffer/writer implementation. Will give that a try.