Can I create a structure that can be built from either a slice or a custom buffer?

I'll try to be as clear as possible. Suppose I:

struct Foo<'a> {
    buffer: &'a [u8],
}

impl<'a> Foo<'a> {
    fn create_builder() -> FooBuilder {
        FooBuilder::new()
    }

    fn from_slice(slice: &[u8]) -> Foo {
        Foo { buffer: slice }
    }
}

struct FooBuilder {
    in_progress_buffer: Vec<u8>,
}

impl FooBuilder {
    fn new() -> FooBuilder {
        FooBuilder { in_progress_buffer: Vec::new() }
    }

    fn push(&mut self, item: u8) {
        self.in_progress_buffer.push(item);
    }

    fn build_foo(self) -> Foo {
        Foo { buffer: self.in_progress_buffer }
    }
}

fn main() {
    // Option1: Gradually construct Foo from FooBuilder
    let mut foo_builder = FooBuilder::new();
    foo_builder.push(7);
    let foo = foo_builder.build_foo();

    // Option2: Construct Foo from a slice
    let v = vec![7];
    let foo2 = Foo::from_slice(&v);
}

      

This gives a compile error:

error[E0106]: missing lifetime specifier
  --> src/main.rs:28:27
   |
28 |     fn build_foo(self) -> Foo {
   |                           ^^^ expected lifetime parameter
   |
   = help: this function return type contains a borrowed value, but there is no value for it to be borrowed from
   = help: consider giving it a 'static lifetime

      

Is this pattern possible? How can I fix the compilation error? I'm not sure what the lifecycle specifier is, since in version FooBuilder

, FooBuilder

owns the buffer, and I don't want to force users to Foo

maintain FooBuilder

in the scope for the full duration of Foo

use

+3


source to share


1 answer


You can use std::borrow::Cow

; as docs :

it can enclose and provide immutable access to borrowed data and clone data lazily when mutation or property is required



use std::borrow::Cow;

struct Foo<'a> {
    buffer: Cow<'a, [u8]>,
}

impl<'a> Foo<'a> {
    fn create_builder() -> FooBuilder {
        FooBuilder::new()
    }

    fn from_slice(slice: &[u8]) -> Foo {
        Foo { buffer: slice.into() } // note .into()
    }
}

struct FooBuilder {
    in_progress_buffer: Vec<u8>,
}

impl<'a> FooBuilder {
    fn new() -> FooBuilder {
        FooBuilder { in_progress_buffer: Vec::new() }
    }

    fn push(&mut self, item: u8) {
        self.in_progress_buffer.push(item);
    }

    fn build_foo(self) -> Foo<'a> {
            Foo { buffer: self.in_progress_buffer.into() } // note .into()
    }
}

      

Also, you will need to make it foo_builder

mutable in order to be able to execute push

on it.

+2


source







All Articles