The issue is that in to_bytes we allocate a Vec<u8> on the heap and then want to return a pointer to the underlying byte-array. But the Vec goes out of scope when to_bytes ends. This cleans up the Vec and the pointer would be invalid if would be allowed to use it after the method returns.
Save but sad.
One option would be to build a wrapper around the User that contains an inner: User and an extra field bytes, that contains a Vec of u8.
Or, which is what I will show here, we could store the Vec directly on the User. While the field is excluded from serialization. Like so:
Then there can be an extra method that initializes the bytes:
impl User {
fn calc_bytes(&mut self) {
let serde_vec = serde_json::to_vec_pretty(self)
.expect("json serialization failed");
self.bytes = Some(serde_vec);
}
}
Which means, that as long as we initialize the bytes field before we call to_bytes the compiler allows us to return a pointer to the underlying bytes-array. Because the compiler knows that this pointer is valid as long as the Vec is valid, which in turn will not be dropped until the User instance goes our of scope.
The impl of ToBytes could look like this:
impl ToBytes for User {
fn to_bytes(&self) -> &[u8] {
match self.bytes {
Some(ref bytes) => bytes,
None => &[],
}
}
}
An idea about the
impl ToBytes for User
problem:The issue is that in
to_bytes
we allocate aVec<u8>
on the heap and then want to return a pointer to the underlying byte-array. But theVec
goes out of scope whento_bytes
ends. This cleans up theVec
and the pointer would be invalid if would be allowed to use it after the method returns.Save but sad.
One option would be to build a wrapper around the
User
that contains aninner: User
and an extra fieldbytes
, that contains aVec
of u8.Or, which is what I will show here, we could store the
Vec
directly on the User. While the field is excluded from serialization. Like so:Then there can be an extra method that initializes the bytes:
Which means, that as long as we initialize the bytes field before we call
to_bytes
the compiler allows us to return a pointer to the underlying bytes-array. Because the compiler knows that this pointer is valid as long as theVec
is valid, which in turn will not be dropped until theUser
instance goes our of scope.The
impl
ofToBytes
could look like this:The full example can be seen at this playground-link:
play.rust-lang.org/?version=stable...