can someone give me a explanation of the usage of repr(C) macro, since in my understanding it simply acts for bridging up the compilation in C, is not wrong?
Further, why does COption keep 4 bytes for only matching the appended tags, shouldn't it be enough in just 1 bit storage?
/// Mint data.
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Mint {
/// Optional authority used to mint new tokens. The mint authority may only be provided during
/// mint creation. If no mint authority is present then the mint has a fixed supply and no
/// further tokens may be minted.
pub mint_authority: COption<Pubkey>,
/// Total supply of tokens.
pub supply: u64,
/// Number of base 10 digits to the right of the decimal place.
pub decimals: u8,
/// Is `true` if this structure has been initialized
pub is_initialized: bool,
/// Optional authority to freeze token accounts.
pub freeze_authority: COption<Pubkey>,
}
impl Pack for Mint {
const LEN: usize = 82;
fn unpack_from_slice(src: &[u8]) -> Result<Self, ProgramError> {
let src = array_ref![src, 0, 82];
let (mint_authority, supply, decimals, is_initialized, freeze_authority) =
array_refs![src, 36, 8, 1, 1, 36];
...
}
...
fn pack_coption_u64(src: &COption<u64>, dst: &mut [u8; 12]) {
let (tag, body) = mut_array_refs![dst, 4, 8];
match src {
COption::Some(amount) => {
*tag = [1, 0, 0, 0];
*body = amount.to_le_bytes();
}
COption::None => {
*tag = [0; 4];
}
}
}
fn unpack_coption_u64(src: &[u8; 12]) -> Result<COption<u64>, ProgramError> {
let (tag, body) = array_refs![src, 4, 8];
match *tag {
[0, 0, 0, 0] => Ok(COption::None),
[1, 0, 0, 0] => Ok(COption::Some(u64::from_le_bytes(*body))),
_ => Err(ProgramError::InvalidAccountData),
}
}
Generally speaking, you are correct about repr(C) however; the rust documentation is your friend.
Regarding COption using 4 vs 1 byte to indicate presence or not. First consider the alignment benefits on memory addressing. Secondly, it does not presume any type of serialization (it is its own).
Related
I want to modify a collection in place before returning it:
fn main() {
println!("{:?}", compute()); // should print [[2, 1, 0], [5, 4, 3]]
}
// u8 is just a placeholder, so impl Copy is considered cheating :)
fn compute() -> Vec<Vec<u8>> {
let a = vec![0, 1, 2];
let b = vec![3, 4, 5];
let mut result = Vec::new();
result.push(a);
result.push(b);
// avoids allocations from:
//
// result.iter()
// .map(|r| {
// r.reverse()
// r
// })
// .collect::<Vec<_>>()
result.into_iter().for_each(|mut r| r.reverse());
// errors out: the collection was consumed the line above
result
}
A collection was already allocated with Vec::new(), so allocating a second collection here seems like a waste. I am assuming that's what .collect() does.
How do I avoid the allocation in excess?
Is there any easy way to know how many allocations are happening? In golang it was as easy as go test -bench=., but I can't find anything similar when it comes to Rust.
Link to playground
You need to use a &mut to each of the inside vectors, for that you can just use iter_mut which uses &mut Self instead of Self for the outer vector.
// u8 is just a placeholder, so impl Copy is considered cheating :)
fn compute() -> Vec<Vec<u8>> {
let a = vec![0, 1, 2];
let b = vec![3, 4, 5];
let mut result = Vec::new();
result.push(a);
result.push(b);
result.iter_mut().for_each(|r| r.reverse());
result
}
Playground
I am reversing a segment inside a linked list based on a start and end position. For example, reverse_between([1, 2, 3, 4, 5], 2, 4) would return [1, 4, 3, 2, 5].
I was able to solve it, but I'm not happy with my solution because I have to iterate over the middle segment twice:
cut off the tail of the list after the middle segment
reverse the middle segment by adding each element onto the front of the tail
From a language-independent perspective, I know that I should be able to just keep a reference to the beginning (soon-to-be end) of the middle chunk, and then when I'm done reversing, I would use that reference to append the tail and be done in one pass. However, a reference to any part of the tail of a linked list will make the Rust compiler refuse to let me modify the head.
Is it possible to solve this problem in one pass?
pub struct ListNode {
pub val: i32,
pub next: Option<Box<ListNode>>,
}
fn reverse_between(mut head: Option<Box<ListNode>>, m: i32, n: i32) -> Option<Box<ListNode>> {
let mut head_ptr = &mut head;
for _ in 1..m {
head_ptr = &mut head_ptr.as_mut().unwrap().next;
}
let mut middle = head_ptr.take();
let mut middle_ptr = &mut middle;
for _ in m..=n {
middle_ptr = &mut middle_ptr.as_mut().unwrap().next;
}
let mut tail = middle_ptr.take();
while let Some(mut x) = middle {
middle = x.next.take();
x.next = tail;
tail = Some(x);
}
std::mem::swap(head_ptr, &mut tail);
head
}
An example from the documentation about vectors:
let v = vec![1, 2, 3, 4, 5];
let third: &i32 = &v[2];
println!("The third element is {}", third);
match v.get(2) {
Some(third) => println!("The third element is {}", third),
None => println!("There is no third element."),
}
I can't see why third needs to be a reference. let third: i32 = v[2] seems to work just as well. What does making it a reference achieve?
Similarly:
let v = vec![100, 32, 57];
for i in &v {
println!("{}", i);
}
why is it in &v instead of just in v?
let third: i32 = v[2] works because i32 implements Copy trait. They don't get moved out when indexing the vector, they get copied instead.
When you have a vector of non Copy type, it is a different story.
let v = vec![
"1".to_string(),
"2".to_string(),
"3".to_string(),
"4".to_string(),
"5".to_string(),
];
let third = &v[2]; // This works
// let third = v[2]; // This doesn't work because String doesn't implement Copy
As for the second question about the loop, for loop is syntactic sugar for IntoIterator which moves and consumes.
So, when you need to use v after the loop, you don’t want to move it. You want to borrow it with &v or v.iter() instead.
let v = vec![100, 32, 57];
for i in &v { // borrow, not move
println!("{}", i);
}
println!("{}", v[0]); // if v is moved above, this doesn't work
According to The Rust Programming Language, ch15-03, std::mem::drop takes an object, receives its ownership, and calls its drop function.
That's what this code does:
fn my_drop<T>(x: T) {}
fn main() {
let x = 5;
let y = &x;
let mut z = 4;
let v = vec![3, 4, 2, 5, 3, 5];
my_drop(v);
}
Is this what std::mem::drop does? Does it perform any other cleanup tasks other than these?
Let's take a look at the source:
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn drop<T>(_x: T) { }
#[inline] gives a hint to the compiler that the function should be inlined. #[stable] is used by the standard library to mark APIs that are available on the stable channel. Otherwise, it's really just an empty function! When _x goes out of scope as drop returns, its destructor is run; there is no other way to perform cleanup tasks implicitly in Rust.
When sorting with multiple keys, how can I reverse the order of an individual key? For example:
vec.sort_by_key(|k| (foo(k).reverse(), bar(k)));
You can use sort_by paired with Ordering::reverse instead of sort_by_key.
use std::cmp::Ordering;
#[derive(Debug)]
struct Foo(&'static str, u8);
impl Foo {
fn name(&self) -> &str { self.0 }
fn len(&self) -> u8 { self.1 }
}
fn main() {
let mut vec = vec![Foo("alpha", 1), Foo("beta", 2), Foo("beta", 1)];
vec.sort_by(|a, b| {
match a.name().cmp(b.name()).reverse() {
Ordering::Equal => a.len().cmp(&b.len()),
other => other,
}
});
println!("{:?}", vec);
}
This sorts in reverse alphabetical order, then ties are sorted in ascending numerical order:
[Foo("beta", 1), Foo("beta", 2), Foo("alpha", 1)]
Since Rust 1.17 (via RFC 1677), you can write it like this:
vec.sort_by(|a, b| {
a.name().cmp(b.name()).reverse()
.then(a.len().cmp(&b.len()))
});
If you have something that can naturally be negated / inverted, you can simply negate the key.
Since Rust 1.19, the std::cmp::Reverse struct wraps a value and implements PartialOrd and Ord by calling partial_cmp and cmp with swapped arguments in order to return the reversed order. Just wrap the key to sort in descending order:
vec.sort_by_key(|k| (Reverse(foo(k)), bar(k)));
Before Rust 1.19, you can use the revord crate (documentation) which provides the struct RevOrd which provides the same benefit::
vec.sort_by_key(|k| (RevOrd(foo(k)), bar(k)));
Here's a similar approach to the problem: create a function for chaining multiple orderings:
/// chain two orderings: the first one gets more priority
fn chain_ordering(o1: Ordering, o2: Ordering) -> Ordering {
match o1 {
Ordering::Equal => o2,
_ => o1,
}
}
Then use sort_by, possibly with pattern matching, to produce the ordering of each key:
#[derive(Debug, PartialEq)]
struct HeroSkill(&'static str, &'static str);
fn main() {
// a vector of hero names and super powers
let mut v = vec![
HeroSkill("Bob", "X"),
HeroSkill("Bob", "Y"),
HeroSkill("Alice", "X")
];
// sort by name, then by super power, where Y is more powerful than X
v.sort_by(|&HeroSkill(name1, power1), &HeroSkill(name2, power2)| {
chain_ordering(name1.cmp(name2), power1.cmp(power2).reverse())
});
assert_eq!(v, vec![
HeroSkill("Alice", "X"),
HeroSkill("Bob", "Y"),
HeroSkill("Bob", "X")
]);
}
Playground