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. Theserialize()
method takes a reference to a mutable slice ofu8
as an argument, theborrow_mut()
method returns aRefMut
. We can't passRefMut
to a method that expects a slice, so we take a mutable slice ofRefMut
which returns a mutable slice ofu8
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]
?)
A person with receptive aphasia experiences difficulty understanding things they hear or read. They may also have difficulty interpreting gestures, drawings, numbers and pictures.
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.
So, I guess, you have multiple questions:
What I don't understand is why is it important to add the [..]?
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.
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.
RefMut<&mut [u8]>
using account.data.borrow_mut()
&RefMut<&mut [u8]>
&mut RefMut<&mut [u8]>
&mut [u8]
using *account.data.borrow_mut().deref_mut()
&&mut [u8]
&mut &mut [u8]
[u8]
using *(*account.data.borrow_mut().deref_mut())
&[u8]
&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:
&mut &mut account.data.borrow_mut()[..]
has type &mut &mut [u8]
.
&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.
Just use
mail_account.serialize(&mut *account.data.borrow_mut())?;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With