A question about lifetimes

assuming that i have a struct that will process a large chunk of data, how can i keep a reference inside the struct field to the data, instead of cloning/copying it?

#[derive(Default)]
pub struct Meta<'a> {
    author: Option<&'a [u8]>,
    year: Option<usize>,
}

impl Meta<'a> {
    pub fn parse(reader: &mut T, buf: &mut BytesMut) -> Result<Self> {
        Ok(Self {
            ..Default::default()
        })
    }
}

pub struct Book<'a> {
    buf: &'a BytesMut,
    meta: &'a Meta,
}

impl Book<'_> {
    fn new<T>(reader: &mut T) -> Result<Self> 
    where 
        T: AsyncRead + std::marker::Unpin,
    {
        let buf = BytesMut::with_capacity(4096);
        let meta = Meta::parse(&mut reader, &mut buf);
        
        Ok(Self {
            buf: &buf,
            meta: &meta,
        })
    }
}

i do understand that meta and buf, will be droped at the end of pub fn new (probably), but since i am returning self which is a reference to Book (maybe) is there a way to attach references to self, from the beginning without reallocation ?

Not sure why you need a reference here. It looks like your Book type is constructed from the reader. Why don't you just put the owned buf and meta directly inside Book, without a reference?

@H2CO3 that's what i am trying to do,

Basically, a reference inside a struct must always reference something that is stored outside of that struct. It is not possible to make references from one field to another, and this is true recursively too: If Meta is stored in Book, then Meta cannot reference other fields in Book — the reference must be to some variable outside Book.

@alice when i write something like this

impl Book {
  fn new() -> Self {
     let buf = BytesMut::with_capacity(4096);

     // fill buf with lot of data..

     Self {
       buf,
     }
  }
}

does this create a copy of buf, when its returned inside Self? like memcpy, or does it only copy the reference to data, and probably updates indexes?

The data allocated in a BytesMut is stored on the heap, and moving the BytesMut only moves that pointer to the heap (and some length information). The heap data (the 4K of data) is not moved.

If you come from a C++ background, note that Rust has no copy constructors, so moving things around wont silently decide to perform an expensive copy. You have to actually explicitly call the clone() function to do that.

1 Like