What's the best way to mutate a nested enum? - rust

I have an enum which roughly looks like this simplified example:
use std::collections::BTreeMap;
enum Value {
Null,
Object(BTreeMap<String, Value>)
}
Now I would like to, based on a list of field names, drill down into a Value::Object and initialize it with the given fields. The leaf field should always receive the Value::Null variant.
What I would like to, and am used to, do is the following:
fn set_null_to_how_i_want_it(fields: &[&str], mut v: &mut Value) {
debug_assert!(fields.len() > 0);
for (fid, field) in fields.iter().enumerate() {
v =
match *v {
Value::Object(ref mut map) => {
let val_to_insert =
if fid == fields.len() - 1 {
Value::Null
} else {
Value::Object(Default::default())
};
map.entry(field.to_string()).or_insert(val_to_insert)
}
_ => unreachable!(),
}
}
}
However, the borrow checker will not allow it.
Interestingly, what worked is the following, more complex and probably less performant implementation:
fn set_null_how_borrow_chk_allows_it(fields: &[&str], v: &mut Value) {
let next =
match *v {
Value::Object(ref mut map) => {
let val_to_insert =
if fields.len() == 1 {
Value::Null
} else {
Value::Object(Default::default())
};
map.entry(fields[0].to_string()).or_insert(val_to_insert)
},
_ => unreachable!()
};
if fields.len() > 1 {
set_null_how_borrow_chk_allows_it(&fields[1..], next)
}
}
With the version above, all the following code runs fine:
let mut v = Value::Object(Default::default());
let fields = ["foo", "bar", "baz"];
set_null_how_borrow_chk_allows_it(&fields, &mut v);
let mut map_count = 0;
for (fid, field) in fields.iter().enumerate() {
let next =
match v {
Value::Object(mut map) => {
map_count += 1;
map.remove(&field.to_string()).unwrap()
},
_ => unreachable!()
};
v = next;
}
assert_eq!(map_count, fields.len());
match v {
Value::Null => (),
Value::Object(_) => unreachable!(),
}
Is there a better way to initialize a nested enumeration or to get set_null_to_how_i_want_it(...) to work ?
How to reproduce
You can have a look at the complete example on github, and play around with it as follows:
git clone https://github.com/Byron/depot
cd depot/src/rust/hello
cargo test --test lang
# edit src/rust/hello/tests/lang.rs for testing
Meta
➜ hello git:(master) ✗ rustc --version --verbose
rustc 1.1.0-nightly (4b88e8f63 2015-05-11) (built 2015-05-12)
binary: rustc
commit-hash: 4b88e8f63eeaf557c916a0a1e73150b028c44c52
commit-date: 2015-05-11
build-date: 2015-05-12
host: x86_64-apple-darwin
release: 1.1.0-nightly

The borrow checker works on names, and so some examples like your first approach don’t work; this can be worked around by moving the value v to a different name first and then assigning the new value to v:
fn set_null_to_how_i_want_it(fields: &[&str], mut v: &mut Value) {
debug_assert!(fields.len() > 0);
for (fid, field) in fields.iter().enumerate() {
let tmp = v;
v = match *tmp {
Value::Object(ref mut map) => {
let val_to_insert =
if fid == fields.len() - 1 {
Value::Null
} else {
Value::Object(Default::default())
};
map.entry(field.to_string()).or_insert(val_to_insert)
}
_ => unreachable!(),
};
}
}

Related

Iterate through a singly linked list of Option<Rc<RefCell<Node>>> without increasing strongcount

Don't ask why I'm learning Rust using linked lists. I want to mutably iterate down a recursive structure of Option<Rc<RefCell<Node>>> while keeping the ability to swap out nodes and unwrap them. I have a singly-linked list type with a tail pointer to the last node.
pub struct List<T> {
maybe_head: Option<Rc<RefCell<Node<T>>>>,
maybe_tail: Option<Rc<RefCell<Node<T>>>>,
length: usize,
}
struct Node<T> {
value: T,
maybe_next: Option<Rc<RefCell<Node<T>>>>,
}
Let's say we have a constructor and an append function:
impl<T> List<T> {
pub fn new() -> Self {
List {
maybe_head: None,
maybe_tail: None,
length: 0,
}
}
pub fn put_first(&mut self, t: T) -> &mut Self {
let new_node_rc = Rc::new(RefCell::new(Node {
value: t,
maybe_next: mem::replace(&mut self.maybe_head, None),
}));
match self.length == 0 {
true => {
let new_node_rc_clone = new_node_rc.clone();
self.maybe_head = Some(new_node_rc);
self.maybe_tail = Some(new_node_rc_clone);
},
false => {
self.maybe_head = Some(new_node_rc);
},
}
self.length += 1;
self
}
}
I want to remove and return the final node by moving the tail pointer to its predecessor, then returning the old tail. After iterating down the list using RefCell::borrow() and Rc::clone(), the first version of remove_last() below panics when trying to unwrap the tail's Rc. How do I iterate down this recursive structure without incrementing each node's strongcount?
PANICKING VERSION
pub fn remove_last(&mut self) -> Option<T> {
let mut opt: Option<Rc<RefCell<Node<T>>>>;
if let Some(rc) = &self.maybe_head {
opt = Some(Rc::clone(rc))
} else {
return None;
};
let mut rc: Rc<RefCell<Node<T>>>;
let mut countdown_to_penultimate: i32 = self.length as i32 - 2;
loop {
rc = match opt {
None => panic!(),
Some(ref wrapped_rc) => Rc::clone(wrapped_rc),
};
match RefCell::borrow(&rc).maybe_next {
Some(ref next_rc) => {
if countdown_to_penultimate == 0 {
self.maybe_tail = Some(Rc::clone(x));
}
opt = Some(Rc::clone(next_rc));
countdown_to_penultimate -= 1;
},
None => {
let grab_tail = match Rc::try_unwrap(opt.take().unwrap()) {
Ok(something) => {
return Some(something.into_inner().value);
}
Err(_) => panic!(),
};
},
}
}
If all I do during iteration is move the tail pointer and enclose the iteration code in a {...} block to drop cloned references, I can then safely swap out and return the old tail, but this is obviously unsatisfying.
UNSATISFYING WORKING VERSION
pub fn remove_last(&mut self) -> Option<T> {
{let mut opt: Option<Rc<RefCell<Node<T>>>>;
if let Some(rc) = &self.maybe_head {
opt = Some(Rc::clone(rc))
} else {
return None;
};
let mut rc: Rc<RefCell<Node<T>>>;
let mut countdown_to_penultimate: i32 = self.length as i32 - 2;
loop {
rc = match opt {
None => panic!(),
Some(ref wrapped_rc) => Rc::clone(wrapped_rc),
};
match RefCell::borrow(&rc).maybe_next {
Some(ref next_rc) => {
if countdown_to_penultimate == 0 {
self.maybe_tail = Some(Rc::clone(&rc));
}
opt = Some(Rc::clone(next_rc));
countdown_to_penultimate -= 1;
},
None => {
break;
},
}
}}
match self.maybe_tail {
None => panic!(),
Some(ref rc) => {
let tail = mem::replace(&mut RefCell::borrow_mut(rc).maybe_next, None);
return Some(Rc::try_unwrap(tail.unwrap()).ok().unwrap().into_inner().value);
}
};
}
I wrote a List::remove_last() that I can live with, although I'd still like to know what more idiomatic Rust code here might look like. I find that this traversal idiom also extends naturally into things like removing the n-th node or removing the first node that matches some predicate.
fn remove_last(&mut self) -> Option<T> {
let mut opt: Option<Rc<RefCell<Node<T>>>>;
let mut rc: Rc<RefCell<Node<T>>>;
#[allow(unused_must_use)]
match self.length {
0 => {
return None;
}
1 => {
let head = mem::replace(&mut self.maybe_head, None);
mem::replace(&mut self.maybe_tail, None);
self.length -= 1;
return Some(
Rc::try_unwrap(head.unwrap())
.ok()
.unwrap()
.into_inner()
.value,
);
}
_ => {
opt = Some(Rc::clone(self.maybe_head.as_ref().unwrap()));
}
}
loop {
rc = match opt {
None => unreachable!(),
Some(ref wrapped_rc) => Rc::clone(wrapped_rc),
};
let mut borrowed_node = RefCell::borrow_mut(&rc);
let maybe_next = &mut borrowed_node.maybe_next;
match maybe_next {
None => unreachable!(),
Some(_)
if std::ptr::eq(
maybe_next.as_ref().unwrap().as_ptr(),
self.maybe_tail.as_ref().unwrap().as_ptr(),
) =>
{
borrowed_node.maybe_next = None;
let old_tail = self.maybe_tail.replace(Rc::clone(&rc));
self.length -= 1;
return Some(
Rc::try_unwrap(old_tail.unwrap())
.ok()
.unwrap()
.into_inner()
.value,
);
}
Some(ref next_rc) => {
opt = Some(Rc::clone(next_rc));
}
}
}
}

Temporary value dropped while borrowed while pushing elements into a Vec

I'm trying to solve the RPN calculator exercise at exercism but stumbled upon this temporary value dropped while borrowed error that I can't seem to work out.
Here's my code:
#[derive(Debug)]
pub enum CalculatorInput {
Add,
Subtract,
Multiply,
Divide,
Value(i32),
}
pub fn evaluate(inputs: &[CalculatorInput]) -> Option<i32> {
let mut stack = Vec::new();
for input in inputs {
match input {
CalculatorInput::Value(value) => {
stack.push(value);
},
operator => {
if stack.len() < 2 {
return None;
}
let second = stack.pop().unwrap();
let first = stack.pop().unwrap();
let result = match operator {
CalculatorInput::Add => first + second,
CalculatorInput::Subtract => first - second,
CalculatorInput::Multiply => first * second,
CalculatorInput::Divide => first / second,
CalculatorInput::Value(_) => return None,
};
stack.push(&result.clone());
}
}
}
if stack.len() != 1 {
None
} else {
Some(*stack.pop().unwrap())
}
}
And the error I get:
error[E0716]: temporary value dropped while borrowed
--> src/lib.rs:32:29
|
32 | stack.push(&result.clone());
| ^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
| |
| creates a temporary which is freed while still in use
...
36 | if stack.len() != 1 {
| ----- borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
If I understand correctly, the variable result is no loger live outside of the for loop (outside of the operator match branch indeed), that's why I cloned it, but it still gives me the same error.
How can I make a copy of the result which is owned by the stack Vec (if that's what I should do)?
Just for reference, and in case anybody fins this useful, this is the final solution taking into account all the help received:
use crate::CalculatorInput::{Add,Subtract,Multiply,Divide,Value};
#[derive(Debug)]
pub enum CalculatorInput {
Add,
Subtract,
Multiply,
Divide,
Value(i32),
}
pub fn evaluate(inputs: &[CalculatorInput]) -> Option<i32> {
let mut stack: Vec<i32> = Vec::new();
for input in inputs {
match input {
Value(value) => {
stack.push(*value);
},
operator => {
if stack.len() < 2 {
return None;
}
let second: i32 = stack.pop().unwrap();
let first: i32 = stack.pop().unwrap();
let result: i32 = match operator {
Add => first + second,
Subtract => first - second,
Multiply => first * second,
Divide => first / second,
Value(_) => return None,
};
stack.push(result);
}
}
}
if stack.len() != 1 {
None
} else {
stack.pop()
}
}
No need to clone, because i32 implements the Copy trait.
The problem was that my vec was receiving an &i32 instead of i32, and thus rust infered it to be a Vec<&i32>.
The error is because Rust did not infer the type you expected.
In your code, the type of value is inferred to be &i32 because input is a reference of a element in inputs, and you push a value later, therefore the type of stack is inferred to be Vec<&i32>.
A best fix is to explicitly specify the type of stack:
let mut stack: Vec<i32> = Vec::new();
And because i32 has implemented Copy trait, you should never need to clone a i32 value, if it is a reference, just dereference it.
Fixed code:
#[derive(Debug)]
pub enum CalculatorInput {
Add,
Subtract,
Multiply,
Divide,
Value(i32),
}
pub fn evaluate(inputs: &[CalculatorInput]) -> Option<i32> {
let mut stack: Vec<i32> = Vec::new();
for input in inputs {
match input {
CalculatorInput::Value(value) => {
stack.push(*value);
}
operator => {
if stack.len() < 2 {
return None;
}
let second = stack.pop().unwrap();
let first = stack.pop().unwrap();
let result = match operator {
CalculatorInput::Add => first + second,
CalculatorInput::Subtract => first - second,
CalculatorInput::Multiply => first * second,
CalculatorInput::Divide => first / second,
CalculatorInput::Value(_) => return None,
};
stack.push(result);
}
}
}
if stack.len() != 1 {
None
} else {
Some(stack.pop().unwrap())
}
}
You have the same behavior with this simple exemple
fn main() {
let mut stack = Vec::new();
let a = String::from("test");
stack.push(&a.clone());
//-------- ^
println!("{:?}", stack);
}
and the good way is to not borrow when clone.
fn main() {
let mut stack = Vec::new();
let a = String::from("test");
stack.push(a.clone());
//-------- ^
println!("{:?}", stack);
}
The variable should be used like this stack.push(result.clone()); and change code like this
pub fn evaluate(inputs: &[CalculatorInput]) -> Option<i32> {
let mut stack: Vec<i32> = Vec::new();
//---------------- ^
for input in inputs {
match input {
CalculatorInput::Value(value) => {
stack.push(value.clone());
//----------------- ^
},
operator => {
if stack.len() < 2 {
return None;
}
let second = stack.pop().unwrap();
let first = stack.pop().unwrap();
let result = match operator {
CalculatorInput::Add => first + second,
CalculatorInput::Subtract => first - second,
CalculatorInput::Multiply => first * second,
CalculatorInput::Divide => first / second,
CalculatorInput::Value(_) => return None,
};
stack.push(result.clone());
//-^
}
}
}
if stack.len() != 1 {
None
} else {
Some(stack.pop().unwrap())
//------- ^
}
}

Why does matching on the result of Regex::find complain about expecting a struct regex::Match but found tuple?

I copied this code from Code Review into IntelliJ IDEA to try and play around with it. I have a homework assignment that is similar to this one (I need to write a version of Linux's bc in Rust), so I am using this code only for reference purposes.
use std::io;
extern crate regex;
#[macro_use]
extern crate lazy_static;
use regex::Regex;
fn main() {
let tokenizer = Tokenizer::new();
loop {
println!("Enter input:");
let mut input = String::new();
io::stdin()
.read_line(&mut input)
.expect("Failed to read line");
let tokens = tokenizer.tokenize(&input);
let stack = shunt(tokens);
let res = calculate(stack);
println!("{}", res);
}
}
#[derive(Debug, PartialEq)]
enum Token {
Number(i64),
Plus,
Sub,
Mul,
Div,
LeftParen,
RightParen,
}
impl Token {
/// Returns the precedence of op
fn precedence(&self) -> usize {
match *self {
Token::Plus | Token::Sub => 1,
Token::Mul | Token::Div => 2,
_ => 0,
}
}
}
struct Tokenizer {
number: Regex,
}
impl Tokenizer {
fn new() -> Tokenizer {
Tokenizer {
number: Regex::new(r"^[0-9]+").expect("Unable to create the regex"),
}
}
/// Tokenizes the input string into a Vec of Tokens.
fn tokenize(&self, mut input: &str) -> Vec<Token> {
let mut res = vec![];
loop {
input = input.trim_left();
if input.is_empty() { break }
let (token, rest) = match self.number.find(input) {
Some((_, end)) => {
let (num, rest) = input.split_at(end);
(Token::Number(num.parse().unwrap()), rest)
},
_ => {
match input.chars().next() {
Some(chr) => {
(match chr {
'+' => Token::Plus,
'-' => Token::Sub,
'*' => Token::Mul,
'/' => Token::Div,
'(' => Token::LeftParen,
')' => Token::RightParen,
_ => panic!("Unknown character!"),
}, &input[chr.len_utf8()..])
}
None => panic!("Ran out of input"),
}
}
};
res.push(token);
input = rest;
}
res
}
}
/// Transforms the tokens created by `tokenize` into RPN using the
/// [Shunting-yard algorithm](https://en.wikipedia.org/wiki/Shunting-yard_algorithm)
fn shunt(tokens: Vec<Token>) -> Vec<Token> {
let mut queue = vec![];
let mut stack: Vec<Token> = vec![];
for token in tokens {
match token {
Token::Number(_) => queue.push(token),
Token::Plus | Token::Sub | Token::Mul | Token::Div => {
while let Some(o) = stack.pop() {
if token.precedence() <= o.precedence() {
queue.push(o);
} else {
stack.push(o);
break;
}
}
stack.push(token)
},
Token::LeftParen => stack.push(token),
Token::RightParen => {
let mut found_paren = false;
while let Some(op) = stack.pop() {
match op {
Token::LeftParen => {
found_paren = true;
break;
},
_ => queue.push(op),
}
}
assert!(found_paren)
},
}
}
while let Some(op) = stack.pop() {
queue.push(op);
}
queue
}
/// Takes a Vec of Tokens converted to RPN by `shunt` and calculates the result
fn calculate(tokens: Vec<Token>) -> i64 {
let mut stack = vec![];
for token in tokens {
match token {
Token::Number(n) => stack.push(n),
Token::Plus => {
let (b, a) = (stack.pop().unwrap(), stack.pop().unwrap());
stack.push(a + b);
},
Token::Sub => {
let (b, a) = (stack.pop().unwrap(), stack.pop().unwrap());
stack.push(a - b);
},
Token::Mul => {
let (b, a) = (stack.pop().unwrap(), stack.pop().unwrap());
stack.push(a * b);
},
Token::Div => {
let (b, a) = (stack.pop().unwrap(), stack.pop().unwrap());
stack.push(a / b);
},
_ => {
// By the time the token stream gets here, all the LeftParen
// and RightParen tokens will have been removed by shunt()
unreachable!();
},
}
}
stack[0]
}
When I run it, however, it gives me this error:
error[E0308]: mismatched types
--> src\main.rs:66:22
|
66 | Some((_, end)) => {
| ^^^^^^^^ expected struct `regex::Match`, found tuple
|
= note: expected type `regex::Match<'_>`
found type `(_, _)`
It's complaining that I am using a tuple for the Some() method when I am supposed to use a token. I am not sure what to pass for the token, because it appears that the tuple is traversing through the Token options. How do I re-write this to make the Some() method recognize the tuple as a Token? I have been working on this for a day but I have not found any really good solutions.
The code you are referencing is over two years old. Notably, that predates regex 1.0. Version 0.1.80 defines Regex::find as:
fn find(&self, text: &str) -> Option<(usize, usize)>
while version 1.0.6 defines it as:
pub fn find<'t>(&self, text: &'t str) -> Option<Match<'t>>
However, Match defines methods to get the starting and ending indices the code was written assuming. In this case, since you only care about the end index, you can call Match::end:
let (token, rest) = match self.number.find(input).map(|x| x.end()) {
Some(end) => {
// ...

Can't find crate for `rayon`

I am trying to find the diameter of a BST using parallelization:
extern crate rayon;
use std::cmp::Ordering::*;
use std::ops::Index;
use rayon::prelude::*;
#[derive(Debug)]
struct Node<K> {
left: Option<Box<Node<K>>>,
right: Option<Box<Node<K>>>,
key: K,
}
impl<K> Node<K> {
fn new(k: K) -> Node<K> {
Node {
left: None,
right: None,
key: k,
}
}
}
impl<K: Ord> Node<K> {
fn insert(&mut self, n: Node<K>) {
match n.key.cmp(&self.key) {
Less => {
match self.left {
None => self.left = Some(Box::new(n)),
Some(ref mut l) => l.insert(n),
}
}
Greater => {
match self.right {
None => self.right = Some(Box::new(n)),
Some(ref mut r) => r.insert(n),
}
}
_ => {}
}
}
fn height(&self) -> u32 {
let mut left_he = 1;
if let Some(ref l) = self.left {
left_he = 1 + l.height()
}
let mut right_he = 1;
if let Some(ref r) = self.right {
right_he = 1 + r.height()
}
if left_he > right_he {
return left_he;
}
return right_he;
}
fn rec(&self) -> u32 {
let mut le = 0;
if let Some(ref l) = self.left {
le = l.height()
}
let mut re = 0;
if let Some(ref r) = self.right {
re = r.height()
}
let hei = le + re + 1;
let mut led = 0;
let mut red = 0;
let Some(ref l) = self.left;
let Some(ref r) = self.right;
rayon::join(|| led = l.rec(), || red = r.rec());
let greater_diameter;
if red > led {
greater_diameter = red;
} else {
greater_diameter = led;
}
if hei > greater_diameter {
return hei;
}
return greater_diameter;
}
fn print_recursive(nodes: Vec<&Self>) {
let mut v: Vec<&Self> = vec![];
for n in nodes {
print!("1 ");
match n.left {
None => {}
Some(ref l) => v.push(&*l),
}
match n.right {
None => {}
Some(ref r) => v.push(&*r),
}
}
println!("");
if v.len() > 0 {
Node::print_recursive(v);
}
}
}
#[derive(Debug, Default)]
struct Bst<K> {
root: Option<Box<Node<K>>>,
}
impl<K> Bst<K> {
fn new() -> Bst<K> {
Bst { root: None }
}
}
impl<K: Ord> Bst<K> {
fn insert(&mut self, k: K) {
match self.root {
None => self.root = Some(Box::new(Node::new(k))),
Some(ref mut r) => r.insert(Node::new(k)),
}
}
fn rec(&self) -> u32 {
match self.root {
None => 0,
Some(ref r) => r.rec(),
}
}
fn print(&self) {
match self.root {
None => {}
Some(ref r) => Node::print_recursive(vec![&*r]),
};
}
}
fn main() {
let mut bst1 = Bst::new();
bst1.insert(20);
bst1.insert(21);
bst1.insert(22);
bst1.insert(23);
bst1.insert(24);
bst1.insert(25);
bst1.insert(19);
bst1.insert(18);
bst1.insert(17);
bst1.insert(16);
bst1.insert(15);
bst1.insert(14);
bst1.print();
println!("{}", bst1.rec());
}
When I compile (rustc code.rs), it shows
error: can't find crate for `rayon` [E0463]
My Rust version is rustc 1.8.0 (db2939409 2016-04-11)
You cannot just use an external dependency without telling the compiler where to find it. The easiest way of doing that is to create a Cargo.toml file and then use cargo build to compile your project instead of rustc directly.
To create the Cargo.toml file, you can just go into the project directory and type:
cargo init --bin
This will do two things:
Create the file src/main.rs. You should put your code in here.
Create a Cargo.toml file, which is used by Cargo for storing dependencies and other build information
You can then edit Cargo.toml to add the rayon dependency. The crates.io page for rayon gives you the exact information which you can just paste in there. When you are done, it should look something like this:
[package]
name = "foo"
version = "0.1.0"
authors = ["singh <singh#singh.com>"]
[dependencies]
rayon = "0.3.1"
Once you have this in place, you can build the project with:
cargo build
Or run with:
cargo run
You can get more information in the Cargo guide.

How to implement an addition method of linked list?

I want to create a simple linked list and add a value into it. How should the add method be implemented to make this code output 100 50 10 5 at line 42, the second root.print() call?
use std::rc::Rc;
struct Node {
value: i32,
next: Option<Box<Node>>,
}
impl Node {
fn print(&self) {
let mut current = self;
loop {
println!("{}", current.value);
match current.next {
Some(ref next) => {
current = &**next;
}
None => break,
}
}
}
fn add(&mut self, node: Node) {
let item = Some(Box::new(node));
let mut current = self;
loop {
match current.next {
None => current.next = item,
_ => {}
//Some(next) => { current = next; }
}
}
}
}
fn main() {
let leaf = Node {
value: 10,
next: None,
};
let branch = Node {
value: 50,
next: Some(Box::new(leaf)),
};
let mut root = Node {
value: 100,
next: Some(Box::new(branch)),
};
root.print();
let new_leaf = Node {
value: 5,
next: None,
};
root.add(new_leaf);
root.print();
}
(Playground)
I rewrote the function like this:
fn add(&mut self, node: Node) {
let item = Some(Box::new(node));
let mut current = self;
loop {
match current {
&mut Node {
value: _,
next: None,
} => current.next = item,
_ => {}
//Some(next) => { current = next; }
}
}
}
but the compiler says
error[E0382]: use of moved value: `item`
--> <anon>:28:40
|
28 | None => current.next = item,
| ^^^^ value moved here in previous iteration of loop
|
= note: move occurs because `item` has type `std::option::Option<std::boxed::Box<Node>>`, which does not implement the `Copy` trait
I don't understand why it says that item was previously moved if it's used only once, and how the Some(_) branch should be implemented to iterate through the list?
This is how you need to write it (playground link)
fn add(&mut self, node: Node) {
let item = Some(Box::new(node));
let mut current = self;
loop {
match moving(current).next {
ref mut slot # None => {
*slot = item;
return;
}
Some(ref mut next) => current = next,
};
}
}
Ok, so what is this?
Step 1, we need to return immediately after using the value item. Then the compiler correctly sees that it is only moved from once.
ref mut slot # None => {
*slot = item;
return;
}
Step 2, to loop with a &mut pointer that we update along the way is tricky.
By default, Rust will reborrow a &mut that is dereferenced. It doesn't consume the reference, it just considers it borrowed, as long as the product of the borrow is still alive.
Obviously, this doesn't work very well here. We want a “hand off” from the old current to the new current. We can force the &mut pointer to obey
move semantics instead.
We need this (the identity function forces move!):
match moving(current).next
we can also write it like this:
let tmp = current;
match tmp.next
or this:
match {current}.next
Step 3, we have no current pointer after we looked up inside it, so adapt the code to that.
Use ref mut slot to get a hold on the location of the next value.

Resources