0

Based on this https://stackoverflow.com/a/68174563/10116440 I have a type that can hold references, but can be cloned also. The clone is just for being able to call a closure dyn Fn that moves this type repeated times.

use std::cell::RefCell;
use std::ops::Deref;
use std::ops::DerefMut;
use std::rc::Rc;
use std::vec::Vec;

#[derive(Debug)]
pub enum EncodedPacketError {
    NotOwned,
    NotMutable,
}

#[derive(Clone)]
pub enum EncodedPacket<'a> {
    Owned(Vec<u8>),
    Ref(Rc<&'a [u8]>),
    RefMut(Rc<RefCell<&'a mut [u8]>>),
}

impl<'a> EncodedPacket<'a> {
    pub fn slice(&'a self) -> &'a [u8] {
        match self {
            EncodedPacket::Owned(vec) => vec.as_slice(),
            EncodedPacket::Ref(slice) => slice,
            EncodedPacket::RefMut(slice) => slice.borrow().deref(),
        }
    }

    pub fn slice_mut(&'a mut self) -> Result<&'a mut [u8], EncodedPacketError> {
        match self {
            EncodedPacket::Owned(ref mut vec) => Ok(vec.as_mut_slice()),
            EncodedPacket::Ref(_) => Err(EncodedPacketError::NotMutable),
            EncodedPacket::RefMut(slice) => Ok(slice.borrow_mut().deref_mut()),
        }
    }

    pub fn vec_ref(&'a self) -> Result<&'a Vec<u8>, EncodedPacketError> {
        match self {
            EncodedPacket::Owned(vec) => Ok(&vec),
            EncodedPacket::Ref(slice) => Err(EncodedPacketError::NotOwned),
            EncodedPacket::RefMut(slice) => Err(EncodedPacketError::NotOwned),
        }
    }

    pub fn vec_ref_mut(&'a mut self) -> Result<&'a Vec<u8>, EncodedPacketError> {
        match self {
            EncodedPacket::Owned(vec) => Ok(vec),
            EncodedPacket::Ref(slice) => Err(EncodedPacketError::NotOwned),
            EncodedPacket::RefMut(slice) => Err(EncodedPacketError::NotOwned),
        }
    }
}

Playground

I'm having errors on how to access the inner types as references:

error[E0515]: cannot return value referencing temporary value
  --> src/lib.rs:22:9
   |
22 | /         match self {
23 | |             EncodedPacket::Owned(vec) => vec.as_slice(),
24 | |             EncodedPacket::Ref(slice) => slice,
25 | |             EncodedPacket::RefMut(slice) => slice.borrow().deref(),
   | |                                             -------------- temporary value created here
26 | |         }
   | |_________^ returns a value referencing data owned by the current function

error[E0515]: cannot return value referencing temporary value
  --> src/lib.rs:33:45
   |
33 |             EncodedPacket::RefMut(slice) => Ok(slice.borrow_mut().deref_mut()),
   |                                             ^^^------------------^^^^^^^^^^^^^
   |                                             |  |
   |                                             |  temporary value created here
   |                                             returns a value referencing data owned by the current function

I don't understand why. Indeed, I'm creating a temporary Ref when I call slice.borrow_mut(), but I'm not returning a reference to this Ref, I'm returning a reference to what's inside of the Ref, which I access using deref_mut(). Why do I get temporary value error?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Guerlando OCs
  • 1,886
  • 9
  • 61
  • 150
  • *I'm returning a reference to what's inside of the `Ref`* — and what will happen when someone else comes along later and gets a mutable reference to that data that you have as immutable? – Shepmaster Jun 30 '21 at 20:06
  • @Shepmaster is it possible to get an `&mut T` from an `&T`? – Guerlando OCs Jun 30 '21 at 20:09
  • See also [Lifetimes when returning a reference to the contents of Rc>](https://stackoverflow.com/q/64030274/155423); [Returning reference from RefCell](https://stackoverflow.com/q/51341643/155423); [How can I return a reference to the inner data of a RefCell – Shepmaster Jun 30 '21 at 20:10
  • No, it is not possible, but you propose to get a`Ref` and then get the `&T`. Since the `Ref` would be **temporary** (except the compiler stops you), you could then get a `RefMut` and introduce memory unsafety. – Shepmaster Jun 30 '21 at 20:12
  • @Shepmaster I don't get it, `Ref` own a reference to `T`. This reference comes from `&self`, so it has the lifetime of `&self`. It should be ok for me to throw away the `Ref` and return the reference – Guerlando OCs Jun 30 '21 at 20:14
  • Ok, so you throw away the `Ref` and return the `&T`. *Then you can get a `RefMut` and **mutate** the supposedly immutable `&T`*. Memory unsafety. This is why the `Ref` must stick around — to prevent getting a `RefMut`. – Shepmaster Jun 30 '21 at 20:17
  • @Shepmaster got it, I thought you were talking about getting an `&mut T` from the `& T` but it's actually getting a `Ref`, dropping the `Ref` and then getting a `RefMut` and then I have both `& T` and `&mut T`. The links mentioned as a solution suggests that I return a `Ref`, but this is quite complicated if you have both the `&` and `&mut` inside the type. Here's a sketch: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=baf8070d4839c3fac0d4f48448bfb12c – Guerlando OCs Jun 30 '21 at 20:32
  • @GuerlandoOCs For what it's worth, I got it working like this: [playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=ca67a945eda484ee7717d683cf892460) – Cryptjar Jun 30 '21 at 23:31
  • @Cryptjar very nice. Just one thing: why `Rc`? Shouldn't `RefCell` suffice? Or even better, a `RefCell` alternative that is `Send` – Guerlando OCs Jul 04 '21 at 01:46
  • @GuerlandoOCs well, the `Rc>` is there to make the `&mut` Clone and mutably accessible. If you need `Send`, you can go with a `Arc>`, e.g.: [playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=dfca24c711500f926b7bf54e049ee841) – Cryptjar Jul 04 '21 at 10:46

0 Answers0