Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trouble understanding &mut &mut reference

Tags:

rust

I'm following this tutorial and I'm having trouble understanding the following code:

mail_account.serialize(&mut &mut account.data.borrow_mut()[..])?;

where mail_account is a struct and .serialize() is a method derived from Borsh Serialize.

One other thing to note is that account is an AccountInfo struct from the solana_program crate and data has type: Rc<RefCell<&'a mut [u8]>>

The author explains the code as follows:

You might notice the tricky &mut &mut account.data.borrow_mut()[..] expression. The serialize() method takes a reference to a mutable slice of u8 as an argument, the borrow_mut() method returns a RefMut. We can't pass RefMut to a method that expects a slice, so we take a mutable slice of RefMut which returns a mutable slice of u8

What I do understand is that we want to write the current mail_account struct into account.data, which is why we are borrowing a mutable reference to account.data. What I don't understand is why is it important to add the [..]? I assume it has something to do with the serialize() expecting a slice.

I'm also having trouble understanding how adding &mut &mut to account.data.borrow_mut()[..] creates a slice of u8. How is this being converted to u8? To me it seems like it would just be adding additional mutable references to the original one. (How is the type changing from RefMut to &[u32]?)

like image 674
Craig Avatar asked Oct 22 '21 01:10

Craig


People also ask

What does it mean when you have a hard time understanding things?

A person with receptive aphasia experiences difficulty understanding things they hear or read. They may also have difficulty interpreting gestures, drawings, numbers and pictures.

Why cant I comprehend what I read as an adult?

Some adults develop poor reading comprehension from a young age. This may be due to being trained by illiterate parents or lacking access to qualitative education. Additionally, medical conditions associated with age, like dyslexia or difficulty with vision, hearing, or speech, can cause poor comprehension in adults.


1 Answers

So, I guess, you have multiple questions:

  1. What I don't understand is why is it important to add the [..]?

  2. I'm also having trouble understanding how adding &mut &mut to account.data.borrow_mut()[..] creates a slice of u8. How is this being converted to u8?

Those questions are kinda intertwined, as you can see inthe anwser to question 1.

Question 1

When we look at the documentation about certain cases of indexing, we see, that

account.data.borrow_mut()[..]

is sugar for

*(account.data.borrow_mut().index_mut(..))

Why is that a valid expression?

.. is a shorthand for RangeFull.

RangeFull has an implementation for SliceIndex<[u8]>.

With this blanket implementation we get a IndexMut<RangeFull> for [u8], which provides

fn index_mut(&mut [u8], index: RangeFull) -> &mut [u8]

Now the deref coercion and or the auto dereferencing mentioned in other answers and comments kicks in.

account.data.borrow_mut().index_mut(..)

And RefMut<&mut [u8]> implements DerefMut which has Deref<Target = &mut [u8]> as a super trait.

And &mut [u8] implements DerefMut with Deref<Target = [u8]> as super trait.

As mentioned in the reference, the compiler will now take the receiver expression and dereference it repeatedly, so it gets a list of candidate types. It also adds for each type resulting from a dereference the reference type and the mutable reference type to the list of candidate types. From this candidate types it selects one providing the method to call.

  1. RefMut<&mut [u8]> using account.data.borrow_mut()
  2. &RefMut<&mut [u8]>
  3. &mut RefMut<&mut [u8]>
  4. &mut [u8] using *account.data.borrow_mut().deref_mut()
  5. &&mut [u8]
  6. &mut &mut [u8]
  7. [u8] using *(*account.data.borrow_mut().deref_mut())
  8. &[u8]
  9. &mut [u8]

(In 7. we are dereferencing a pointer type &mut [u8] so no DerefMut Trait is used.)

The first (and only) type in this list providing an index_mut() method is &mut [u8], via the IndexMut<FullRange> implementation for [u8], so &mut [u8] is selected as receiver type. The return type of index_mut() is &mut [u8] as well.

So now, we hopefully understand, the type of

*(account.data.borrow_mut().index_mut(..)) is [u8].

Hence:

Question 2

&mut &mut account.data.borrow_mut()[..]

has type &mut &mut [u8].

Addendum

&mut &mut [u8] is needed as &mut [u8] has a Write implementation.

And serialize

pub fn serialize<W: Write>(&self, writer: &mut W) -> Result<()>

needs an argument of type &mut W, where W implements Write.

The reference to a value of type W implementing Write needs to mutable, as we want to keep track of the actual writing position in the value of type W. In the case of &mut [u8] we simply alter the reference to start at a different position in the underlying slice, so we need a mutable reference to the mutable reference, as we want to alter the mutable reference itself and not only the underlying data.

Addendum 2

Just use

mail_account.serialize(&mut *account.data.borrow_mut())?;
like image 173
typetetris Avatar answered Sep 27 '22 02:09

typetetris