modifying a field while pattern matching on it - pointers

I tried my hands at Rust for the first time today (writing a XML tokenizer), and naturally don’t understand everything:
I have a struct with field that can take an enum value:
enum State { Outside, InATag(~str) }
struct Tokenizer { state: State }
In a impl Tokenizer, I want to match on the current state, and change it in some cases, however this always gives a use of moved value error.
H to access and/or declare the state field so that I can match on it and change its value inside a match branch?
Sorry for the confusion, I meant to change the Tokenizer’s state field, not the state’s String field!
match self.state {
InATag(name) => self.state = Outside,
Outside => ()
}

Without a more concrete example, it is hard to tell whether this would solve your problem, but you can use ref within a match pattern to make a reference to the matched substructure, and you can use ref mut to make that reference mutable.
So, in your example:
enum State { Outside, InATag(~str) }
struct Tokenizer { state: State }
fn main() {
let mut t = Tokenizer { state: InATag(~"foo") };
match t.state {
InATag(ref mut _s) => { *_s = ~"bar"; }
Outside => { /* impossible */ }
}
io::println(fmt!("Hello World: %?", t));
}
or if you need to match other parts of the Tokenizer state, this works too:
fn main() {
let mut t = Tokenizer { state: InATag(~"foo") };
match t {
Tokenizer { state: InATag(ref mut _s) } => { *_s = ~"bar"; }
Tokenizer { state: Outside } => { /* impossible */ }
}
io::println(fmt!("Hello World: %?", t));
}
Note that when doing this sort of code, it can be pretty easy to inadvertently run into borrow-check violations due to aliasing. For example, here is a relatively small change to the second example above that won't compile:
fn main() {
let mut t = Tokenizer { state: InATag(~"foo") };
match &t {
&Tokenizer { state: InATag(ref mut _s) } => { *_s = ~"bar"; }
&Tokenizer { state: Outside } => { /* impossible */ }
}
io::println(fmt!("Hello World: %?", t));
}
causes the following message from rustc:
/tmp/m.rs:7:35: 7:46 error: illegal borrow: creating mutable alias to enum content
/tmp/m.rs:7 &Tokenizer { state: InATag(ref mut _s) } => { *_s = ~"bar"; }
^~~~~~~~~~~
error: aborting due to previous error
because you do not want an outstanding borrow &t while you are also creating mutable aliases to the internals of t

Okay, with the clarified variant of the question, here is my revised answer:
enum State { Outside, InATag(~str) }
struct Tokenizer { state: State }
impl Tokenizer {
fn toggle(&mut self) {
match self {
&Tokenizer { state: InATag(*) } => { self.state = Outside }
&Tokenizer { state: Outside } => { self.state = InATag(~"baz") }
}
}
}
fn main() {
let mut t1 = Tokenizer { state: InATag(~"foo") };
match t1 {
Tokenizer { state: InATag(*) } => { t1.state = Outside }
Tokenizer { state: Outside } => { /* impossible */ }
}
io::println(fmt!("Hello t1: %?", t1));
let mut t2 = Tokenizer { state: InATag(~"bar") };
t2.toggle();
io::println(fmt!("World t2: %?", t2));
}
I admit, I actually did not expect it to be as easy as the above, and I can easily believe that small changes to the above code could cause it to start failing to borrow-check. But without a more fleshed out example from the asker, it is hard to tell whether the above code would suit his purposes or not.
Oh, here's the output when I compile and run the code:
% rustc /tmp/m.rs
warning: no debug symbols in executable (-arch x86_64)
% /tmp/m
Hello t1: {state: Outside}
World t2: {state: Outside}
%

Related

Get Box Pointer from reference in rust

Say I have a function like this:
fn foo(item: &FooType) -> Box<FooType>{
Box::new(item)
}
I get the following error:
mismatched types: expected enum FooType, found &FooType
I'm assuming I need to do some reference/boxing and lifetime magic, but as a rust beginner, I'm not 100% sure how to get this working.
I think there is no definitive answer since it depends on what you expect.
If you want to obtain a heap-allocated clone of something you want to keep usable, then cloning in foo1() can help.
A better solution could be to pass a value not a reference, as in foo2(), because this way the call site can decide if a clone is necessary or if moving the original value into the box is enough.
You may also want the box to hold the reference instead of the value, as in foo3(), but this is like a code-smell to me (many indirections that make reasoning about lifetimes very complicated).
#[derive(Debug, Clone)]
struct FooType {
value: usize,
}
fn foo1(item: &FooType) -> Box<FooType> {
Box::new(item.clone())
}
fn foo2(item: FooType) -> Box<FooType> {
Box::new(item)
}
fn foo3(item: &FooType) -> Box<&FooType> {
Box::new(item)
}
fn main() {
let ft_a = FooType { value: 12 };
let bft_a = foo1(&ft_a);
println!("bft_a: {:?}", bft_a);
println!("ft_a: {:?}", ft_a);
println!("~~~~~~~~~~~~~~~~~~");
let ft_b = FooType { value: 34 };
let bft_b = foo2(ft_b);
println!("bft_b: {:?}", bft_b);
// println!("ft_b: {:?}", ft_b); // borrow of moved value: `ft_b`
println!("ft_b is consumed");
println!("~~~~~~~~~~~~~~~~~~");
let ft_c = FooType { value: 56 };
let bft_c = foo2(ft_c.clone());
println!("bft_c: {:?}", bft_c);
println!("ft_c: {:?}", ft_c);
println!("~~~~~~~~~~~~~~~~~~");
let ft_d = FooType { value: 78 };
let bft_d = foo3(&ft_d);
println!("bft_d: {:?}", bft_d);
println!("ft_d: {:?}", ft_d);
}
/*
bft_a: FooType { value: 12 }
ft_a: FooType { value: 12 }
~~~~~~~~~~~~~~~~~~
bft_b: FooType { value: 34 }
ft_b is consumed
~~~~~~~~~~~~~~~~~~
bft_c: FooType { value: 56 }
ft_c: FooType { value: 56 }
~~~~~~~~~~~~~~~~~~
bft_d: FooType { value: 78 }
ft_d: FooType { value: 78 }
*/
The compiler is complaining because in the function's signature you specified Box<FooType> as the return type, and you are giving it a Box<&FooType> when you wrap the ìtem in a Box.
Change the function's signature so that it receives a FooType rather than a reference to it like this:
fn foo(item: FooType) -> Box<FooType>{
Box::new(item)
}

rust futures::select modifying local variable in loop

I have a struct G like this
struct G { /* some member */ }
impl G {
async fn ref_foo(&self) { /* some code uses G's member */ }
async fn mut_foo(&mut self) { /* some code modifies G's member */ }
}
which is responsible to handle requests from a mpsc::Receiver, like this -- which won't compile:
async fn run_loop(mut rx: impl Stream<Item = Task> + FusedStream + Unpin) {
let mut g = G {};
let mut QS = FuturesUnordered::new();
loop {
select! {
t = rx.select_next_some() => match t {
TR {..} => QS.push(g.ref_foo()),
TM {..} => QS.push(g.mut_foo()),
},
_ = QS.select_next_some() => {},
}
}
}
the above code won't compile due to multiple mutable reference to g.
Target:
What I want is that the loop runs in parallel for any number of ref_foo tasks, and when it needs to run a mut_foo task, it waits until every ref_foo task finish, and then run the mut_foo task, then it can run other tasks as usual.
/ g.ref_foo() \ / ...
| g.ref_foo() | | ...
g.mut_foo() => < g.ref_foo() > => g.mut_foo() => g.mut_foo() => < ...
| g.ref_foo() | | ...
\ g.ref_foo() / \ ...
Additional Infomation:
I used to move implementation of mut_foo to the select loop, and remove async on g.mut_foo() so that no mutable reference would be used in stream QS.
But this implementation is really cubersome and undoubtedly broke G's design.
Just now, I come up with another implementation by make a wrapper:
async fn run_task(mut g: G, t: Task) -> G {
match t {
TR {..} => g.ref_foo().await,
TM {..} => g.mut_foo().await,
};
g
}
while in the select loop:
async fn run_loop(mut rx: impl Stream<Item = Task> + FusedStream + Unpin) {
let g0 = G {};
let mut QS = FuturesUnordered::new();
let mut getter = FuturesUnordered::new();
getter.push(ready(g0));
loop {
select! {
t = rx.select_next_some() => {
let mut g = getter.select_next_some().await;
QS.push(run_task(g, t));
},
mut g = QS.select_next_some() => getter.push(ready(g)),
}
}
}
this one compiles, but it's not so "async" as it can possibly be. In this implementation, ref_foo tasks are also running sequentially.
Question:
Are there more material I should learn to solve this problem? The technics I'm using comes from rust-async-book
Do I HAVE TO use RefCell to solve this problem? IMHO, this should be a trivial problem that can be solved without breaking rust's borrowing rules (by using RefCell).
Can I change my wrap run_task and the select loop so that ref_foo runs in parallel? I have problem in the implementation because G is flowing getter => QS => getter => ..., there's no long-term G instance, and I cannot figure out where I can store it.
Append some of my thoughts:
Since mut_foo can not be run in parallel, I am trying to solve this problem by removing async keyword on mut_foo -- with little progress. The core problem is that, immutable ref to G is needed for parallel running of ref_foo, but I have to get rid of all these immutable ref G when it's time for mut_foo. The fact do not change whether mut_foo is async or not ( or "whether mut_foo returns ref G or not").
I've solved Question 3 with a lot of if statements. I hope there are some more elegant implementations. And, I really appreciate any learning material as stated in Question 1.
here's the full code that compiles (simplified):
use tokio::runtime;
use std::thread;
use std::time::Duration;
use futures::{
select, StreamExt, SinkExt,
future::{ready},
stream::{FusedStream, FuturesUnordered, Stream},
};
struct G;
impl G {
async fn ref_foo(&self) { println!("ref_foo +++"); tokio::time::sleep(Duration::from_millis(500)).await; println!("ref_foo ---"); }
async fn mut_foo(&mut self) { println!("mut_foo +++"); tokio::time::sleep(Duration::from_millis(500)).await; println!("mut_foo ---"); }
}
#[derive(Clone)]
enum Task {
TR,
TM,
}
// wrappers
async fn run_ref_task(g: &G, task: Task) {
match task {
Task::TR => g.ref_foo().await,
_ => {},
};
}
async fn run_mut_task(mut g: G, task: Task) -> G {
match task {
Task::TM => g.mut_foo().await,
_ => {},
};
g
}
async fn run_loop(mut rx: impl Stream<Item = Task> + FusedStream + Unpin) {
let g0 = G;
let mut getter = FuturesUnordered::new();
getter.push(ready(g0));
// the following streams stores only `ready(task)`
let mut mut_tasks = FuturesUnordered::new(); // for tasks that's scheduled in this loop
let mut ref_tasks = FuturesUnordered::new();
let mut mut_delay = FuturesUnordered::new(); // for tasks that's scheduled in next loop
let mut ref_delay = FuturesUnordered::new();
loop {
println!("============ avoid idle loops ============");
let g = getter.select_next_some().await;
{
let mut queries = FuturesUnordered::new(); // where we schedule ref_foo tasks
loop {
println!("------------ avoid idle ref_task loops ------------");
select! {
task = rx.select_next_some() => {
match &task {
Task::TR => ref_delay.push(ready(task)),
Task::TM => mut_tasks.push(ready(task)),
};
if mut_delay.is_empty() && ref_tasks.is_empty() && queries.is_empty() { break; }
},
task = mut_delay.select_next_some() => {
mut_tasks.push(ready(task));
if mut_delay.is_empty() && ref_tasks.is_empty() && queries.is_empty() { break; }
}
task = ref_tasks.select_next_some() => {
queries.push(run_ref_task(&g, task));
}
_ = queries.select_next_some() => {
if mut_delay.is_empty() && ref_tasks.is_empty() && queries.is_empty() { break; }
},
}
}
}
getter.push(ready(g));
{
let mut queries = FuturesUnordered::new(); // where we schedule mut_foo tasks
loop {
println!("------------ avoid idle mut_task loops ------------");
select! {
task = rx.select_next_some() => {
match &task {
Task::TR => ref_tasks.push(ready(task)),
Task::TM => mut_delay.push(ready(task)),
};
if ref_delay.is_empty() && mut_tasks.is_empty() && queries.is_empty() { break; }
},
task = ref_delay.select_next_some() => {
ref_tasks.push(ready(task));
if ref_delay.is_empty() && mut_tasks.is_empty() && queries.is_empty() { break; }
}
g = getter.select_next_some() => {
if let Some(task) = mut_tasks.next().await {
queries.push(run_mut_task(g, task));
} else {
getter.push(ready(g));
if ref_delay.is_empty() && queries.is_empty() { break; }
}
}
g = queries.select_next_some() => {
getter.push(ready(g));
if ref_delay.is_empty() && mut_tasks.is_empty() && queries.is_empty() { break; }
}
}
}
}
}
}
fn main() {
let (mut tx, rx) = futures::channel::mpsc::channel(10000);
let th = thread::spawn(move || thread_main(rx));
let tasks = vec![Task::TR, Task::TR, Task::TM, Task::TM, Task::TR, Task::TR, Task::TR, Task::TM, Task::TM];
let rt = runtime::Builder::new_multi_thread().enable_time().build().unwrap();
rt.block_on(async {
loop {
for task in tasks.clone() {
tx.send(task).await.expect("");
}
tokio::time::sleep(Duration::from_secs(10)).await;
}
});
th.join().expect("");
}
fn thread_main(rx: futures::channel::mpsc::Receiver<Task>) {
let rt = runtime::Builder::new_multi_thread().enable_time().build().unwrap();
rt.block_on(async {
run_loop(rx).await;
});
}

Searching a Vec for a match

My first Rust program compiles and runs:
use structopt::StructOpt;
use pcap::{Device,Capture};
use std::process::exit;
#[derive(StructOpt)]
struct Cli {
/// the capture device
device: String,
}
fn main() {
let devices = Device::list();
let args = Cli::from_args();
let mut optdev :Option<Device> = None;
for d in devices.unwrap() {
//println!("device: {:?}", d);
if d.name == args.device {
optdev = Some(d);
}
}
let dev = match optdev {
None => {
println!("Device {} not found.", args.device);
exit(1);
},
Some(dev) => dev,
};
let mut cap = Capture::from_device(dev).unwrap()
.promisc(true)
.snaplen(100)
.open().unwrap();
while let Ok(packet) = cap.next() {
println!("received packet! {:?}", packet);
}
}
I have some complex code which iterates through the Vec of devices, testing each one's .name property against args.device.
I'm guessing that there is a method of 'looking-up' an entry in a Vec, such that I can replace all the optdev lines with something like:
let dev = match devices.unwrap().look_up(.name == args.device) {
None => {
println!("Device {} not found.", args.device);
exit(1);
},
Some(dev) => dev,
};
What is the syntax for such a look_up()?
Or is there a more idiomatic way of doing this?
What is the syntax for such a look_up()?
Iterator::find. Since the operation is not specific to vectors (or slices), it doesn't live there, and is applicable to any iterator instead.
It'd look something like this:
let dev = match devices.unwrap().into_iter().find(|d| d.name == args.device) {
None => {
println!("Device {} not found.", args.device);
exit(1);
},
Some(dev) => dev,
};
or
let dev = if let Some(dev) = devices.unwrap().into_iter().find(|d| d.name == args.device) {
dev
} else {
println!("Device {} not found.", args.device);
exit(1);
};
(side-note: you may also want to use eprintln for, well, error reporting).
Though a somewhat cleaner error handling could be along the lines of (note: not tested so there might be semantic or syntactic mistakes):
use std::fmt;
use std:errors::Error;
#[derive(Debug)]
struct NoDevice(String);
impl fmt::Display for NoDevice {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Device {} not found", self.0)
}
}
impl Error for NoDevice {}
fn main() -> Result<(), Box<dyn Error>> {
let devices = Device::list()?;
let args = Cli::from_args();
let dev = devices.into_iter()
.find(|d| d.name == args.device)
.ok_or_else(|| NoDevice(args.device))?
let mut cap = Capture::from_device(dev)?
.promisc(true)
.snaplen(100)
.open()?;
while let Ok(packet) = cap.next() {
println!("received packet! {:?}", packet);
}
}

How to replace combinators with Future?

I have a function which returns Future. It accepts another function which accepts one argument and returns Future. Second function can be implemented as combinators chain passed into first function. It looks like this:
use bb8::{Pool, RunError};
use bb8_postgres::PostgresConnectionManager;
use tokio_postgres::{error::Error, Client, NoTls};
#[derive(Clone)]
pub struct DataManager(Pool<PostgresConnectionManager<NoTls>>);
impl DataManager {
pub fn new(pool: Pool<PostgresConnectionManager<NoTls>>) -> Self {
Self(pool)
}
pub fn create_user(
&self,
reg_req: UserRequest,
) -> impl Future<Item = User, Error = RunError<Error>> {
let sql = "long and awesome sql";
let query = move |mut conn: Client| { // function which accepts one argument and returns Future
conn.prepare(sql).then(move |r| match r {
Ok(select) => {
let f = conn
.query(&select, &[&reg_req.email, &reg_req.password])
.collect()
.map(|mut rows| {
let row = rows.remove(0);
row.into()
})
.then(move |r| match r {
Ok(v) => Ok((v, conn)),
Err(e) => Err((e, conn)),
});
Either::A(f)
}
Err(e) => Either::B(future::err((e, conn))),
})
};
self.0.run(query) // function which returns Future and accepts another function
}
}
But I want to write code of create_user as a struct implementing Future.
struct UserCreator(Pool<PostgresConnectionManager<NoTls>>, UserRequest);
impl UserCreator {
fn new(pool: Pool<PostgresConnectionManager<NoTls>>, reg_req: UserRequest) -> Self {
Self(pool, reg_req)
}
}
How to implement Future for this struct that works as first function? Please help me with an example.
Now I tried to make it like this, but nothing is computed and execution always blocks.
impl Future for UserCreator {
type Item = User;
type Error = RunError<Error>;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
// Code which which works like `DataManager.create_user`
let sql = "long and awesome sql";
let reg_req = &self.1;
let query = move |mut conn: Client| {
conn.prepare(sql).then(move |r| match r {
Ok(select) => {
let f = conn
.query(&select, &[&reg_req.email, &reg_req.password])
.collect()
.map(|mut rows| {
let row = rows.remove(0);
row.into()
})
.then(move |r| match r {
Ok(v) => Ok((v, conn)),
Err(e) => Err((e, conn)),
});
Either::A(f)
}
Err(e) => Either::B(future::err((e, conn))),
})
};
self.0.run(query).poll()
}
}

Recursive search of node in tree

I want to build a tree using exactly two structs: Node and Tree and then recursively search for a target node from the tree. If a target is found, return true, else return false.
The challenge for me here is how to recursively call the find function, since it is only defined on Tree not Node.
pub struct Node<T> {
value: T,
left: Option<Box<Node<T>>>,
right: Option<Box<Node<T>>>,
}
pub struct Tree<T> {
root: Option<Box<Node<T>>>,
}
impl<T: Ord> Tree<T> {
/// Creates an empty tree
pub fn new() -> Self {
Tree { root: None }
}
// search the tree
pub fn find(&self, key: &T) -> bool {
let root_node = &self.root; // root is Option
match *root_node {
Some(ref node) => {
if node.value == *key {
return true;
}
let target_node = if *key < node.value {
&node.left
} else {
&node.right
};
match *target_node {
Some(sub_node) => sub_node.find(key),
None => {
return false;
}
}
}
None => return false,
}
}
}
fn main() {
let mut mytree: Tree<i32> = Tree::new();
let node1 = Node {
value: 100,
left: None,
right: None,
};
let boxed_node1 = Some(Box::new(node1));
let root = Node {
value: 200,
left: boxed_node1,
right: None,
};
let boxed_root = Some(Box::new(root));
let mytree = Tree { root: boxed_root };
let res = mytree.find(&100);
}
The current code reports the error:
error: no method named `find` found for type `Box<Node<T>>` in the current scope
--> src/main.rs:36:48
|
36 | Some(sub_node) => sub_node.find(key),
| ^^^^
|
= note: the method `find` exists but the following trait bounds were not satisfied: `Node<T> : std::iter::Iterator`
= help: items from traits can only be used if the trait is implemented and in scope; the following traits define an item `find`, perhaps you need to implement one of them:
= help: candidate #1: `std::iter::Iterator`
= help: candidate #2: `core::str::StrExt`
I understand that find is only implemented on Tree, so there is an error, but I don't think it is efficient to implement find on both Tree and Node. Any hint to solve this?
You need to move the majority of the implementation to the Node type, then leave only a small shim in Tree:
impl<T: Ord> Tree<T> {
pub fn find(&self, key: &T) -> bool {
self.root.as_ref().map(|n| n.find(key)).unwrap_or(false)
}
}
impl<T: Ord> Node<T> {
// search the tree
pub fn find(&self, key: &T) -> bool {
if self.value == *key {
return true;
}
let target_node = if *key < self.value {
&self.left
} else {
&self.right
};
target_node.as_ref().map(|n| n.find(key)).unwrap_or(false)
}
}
However, I might avoid multiple comparisons by just matching on the result:
pub fn find(&self, key: &T) -> bool {
use ::std::cmp::Ordering::*;
match self.value.cmp(key) {
Equal => true,
Less => self.left.as_ref().map(|n| n.find(key)).unwrap_or(false),
Greater => self.right.as_ref().map(|n| n.find(key)).unwrap_or(false),
}
}
Or
pub fn find(&self, key: &T) -> bool {
use ::std::cmp::Ordering::*;
let child = match self.value.cmp(key) {
Equal => return true,
Less => self.left.as_ref(),
Greater => self.right.as_ref(),
};
child.map(|n| n.find(key)).unwrap_or(false)
}
I found it is hard to understand target_node.as_ref().map(|n| n.find(key)).unwrap_or(false). I just started to learn the iterator. Is that possible to explain the long expression step by step?
Just follow the type signatures of each function:
self is a &Node<T>
&self.left / &self.right / target_node are a &Option<Box<Node<T>>>
Option::as_ref converts an &Option<T> to Option<&T>. Now we have Option<&Box<Node<T>>>.
Option::map applies a function (which may change the contained type) to the option if it is Some, otherwise it leaves it None.
The function we apply is Node::find, which takes a &Node<T> and returns a bool.
Box<T> implements Deref so any methods on T appear on Box<T>.
Automatic dereferencing allows us to treat &Box<T> as Box<T>.
Now we have Option<bool>
Option::unwrap_or returns the contained value if there is one, otherwise the fallback value provided. The final type is bool.
There is no usage of the Iterator trait. Both Iterator and Option have a map method. If you are interested in the fact that they have the same name and do similar things, that [is what people refer to as a monad. Understanding monads is interesting but not required to actually use them.
Implement the find method on Node and create a stub find method for Tree which could look like this:
impl<T: Ord> Tree<T> {
pub fn find(&self, key: &T) -> bool {
match self.root.as_ref() {
None => false,
Some(x) => x.find(key)
}
}
}

Resources