How to use self in a for loop in Rust - rust

I am pretty new to Rust and just starting doing a little "compiler" and after having used the pointer system I encountered a problem with the move system:
for constraint in constraints {
self.get_or_create_node(constraint.0.to_string(), 0, &constraint.1);
}
This system uses a recursive function which create a tree for a path that I call a constraint but I use Strings to name my nodes so my struct cannot be copied. So the self in the loop throws a move error, how could I prevent it?
Edit here's the get_or_create_node method:
fn get_or_create_node(mut self, node_name: String, current_level: i32, value: &String) {
let path: Vec<&str> = node_name.split('.').collect();
if current_level + 1 == path.len().try_into().unwrap() {
self.value = value.to_string();
} else {
for node in self.nodes {
if path.get(current_level as usize).expect("Path in if statement is false") == &node.value.as_str() {
node.get_or_create_node(node_name.clone(), current_level + 1, value);
}
}
}
}

As I mentioned in the comments, you're taking self by value (hence taking ownership) when you really don't need it. Take a &mut self argument instead.
fn get_or_create_node(&mut self, node_name: String, current_level: i32, value: &String)

Related

Cannot get wrapping of filter to compile

I have the goal of wrapping an Iterator<Item = rusb::Device<_> to Iterator<Item = LitraDevice>. The latter contains specific implementation.
To make this work I tried the following code:
use std::iter::Filter;
use rusb;
const VENDOR: u16 = 0x046d;
const PRODUCT: u16 = 0xc900;
struct LitraDevice {
dev: rusb::Device<rusb::GlobalContext>,
}
pub struct LitraDevices {
unfiltered: rusb::DeviceList<rusb::GlobalContext>,
}
struct LitraDeviceIterator<'a> {
it: Filter<rusb::Devices<'a, rusb::GlobalContext>, for<'r> fn(&'r rusb::Device<rusb::GlobalContext>) -> bool>,
}
impl LitraDevices {
pub fn new() -> Self {
let unfiltered = rusb::devices().unwrap();
LitraDevices { unfiltered }
}
fn can_not_handle<'r>(dev: &'r rusb::Device<rusb::GlobalContext>) -> bool {
let desc = dev.device_descriptor().unwrap();
match (desc.vendor_id(), desc.product_id()) {
(VENDOR, PRODUCT) => (),
_ => return true,
}
match desc.class_code() {
LIBUSB_CLASS_HID => return true, // Skip HID devices, they are handled directly by OS libraries
_ => return false,
}
}
pub fn iter<'a>(self) -> LitraDeviceIterator<'a> {
let it = self.unfiltered.iter().filter(Self::can_not_handle);
LitraDeviceIterator{
it,
}
}
}
impl <'a> Iterator for LitraDeviceIterator<'a> {
type Item = LitraDevice;
fn next(&mut self) -> Option<Self::Item> {
let n = self.it.next();
match n {
Some(Device) => return Some(LitraDevice{dev: n.unwrap()}),
None => return None,
}
}
}
Now I really cannot figure out how to code LitraDeviceIterator so that it wraps the filtered iterator.
All code iterations I have tried so far turn into a generic nightmare very quickly.
I rewrote your iter() to yield LitraDevice, you can surely take it wherever you wanted to go from there.
The first underlying issue is that filter() yields references, but in cases like these, you actually mean to move yielded items while filtering. That's what filter_map() is capable of. That way, you can scrap the references, greatly simplifying your code.
(This code does not work yet, read on)
pub fn iter(self) -> impl Iterator<Item = LitraDevice> {
self.unfiltered.iter().filter_map(|dev| {
(!Self::can_not_handle(&dev))
.then_some(dev)
.map(|dev| LitraDevice { dev })
})
}
Now, there's a second little issue at play her: rusb::DeviceList<T : UsbContext>>::iter(&self) returns rusb::Devices<'_, T>, '_ being the anonymous lifetime inferred from &self. Meaning, while you can drive rusb::Devices<'_, T> to yield Device<T>s, you can not actually keep it around longer than self.unfiltered. More specifically, as you consume self in iter(), you can not return an iterator referencing that rusb::Devices<'_, T> from iter(). One solution is to immediately collect, then again moving into an iterator.
pub fn iter(self) -> impl Iterator<Item = LitraDevice> {
let devices = self.unfiltered.iter().collect::<Vec<_>>();
devices.into_iter().filter_map(|dev| {
(!Self::can_not_handle(&dev))
.then_some(dev)
.map(|dev| LitraDevice { dev })
})
}

Temporarily cache owned value between iterator adapters

I'd like to know if there's a way to cache an owned value between iterator adapters, so that adapters later in the chain can reference it.
(Or if there's another way to allow later adapters to reference an owned value that lives inside the iterator chain.)
To illustrate what I mean, let's look at this (contrived) example:
I have a function that returns a String, which is called in an Iterator map() adapter, yielding an iterator over Strings. I'd like to get an iterator over the chars() in those Strings, but the chars() method requires a string slice, meaning a reference.
Is this possible to do, without first collecting the Strings?
Here's a minimal example that of course fails:
fn greet(c: &str) -> String {
"Hello, ".to_owned() + c
}
fn main() {
let names = ["Martin", "Helena", "Ingrid", "Joseph"];
let iterator = names.into_iter().map(greet);
let fails = iterator.flat_map(<str>::chars);
}
Playground
Using a closure instead of <str>::chars - |s| s.chars() - does of course not work either. It makes the types match, but breaks lifetimes.
Edit (2022-10-03): In response to the comments, here's some pseudocode of what I have in mind, but with incorrect lifetimes:
struct IteratorCache<'a, T, I>{
item : Option<T>,
inner : I,
_p : core::marker::PhantomData<&'a T>
}
impl<'a, T, I> Iterator for IteratorCache<'a, T,I>
where I: Iterator<Item=T>
{
type Item=&'a T;
fn next(&mut self) -> Option<&'a T> {
self.item = self.inner.next();
if let Some(x) = &self.item {
Some(&x)
} else {
None
}
}
}
The idea would be that the reference could stay valid until the next call to next(). However I don't know if this can be expressed with the function signature of the Iterator trait. (Or if this can be expressed at all.)
I don't think something like this exists yet, and collecting into a Vec<char> creates some overhead, but you can write such an iterator yourself with a little bit of trickery:
struct OwnedCharsIter {
s: String,
index: usize,
}
impl OwnedCharsIter {
pub fn new(s: String) -> Self {
Self { s, index: 0 }
}
}
impl Iterator for OwnedCharsIter {
type Item = char;
fn next(&mut self) -> Option<Self::Item> {
// Slice of leftover characters
let slice = &self.s[self.index..];
// Iterator over leftover characters
let mut chars = slice.chars();
// Query the next char
let next_char = chars.next()?;
// Compute the new index by looking at how many bytes are left
// after querying the next char
self.index = self.s.len() - chars.as_str().len();
// Return next char
Some(next_char)
}
}
fn greet(c: &str) -> String {
"Hello, ".to_owned() + c
}
fn main() {
let names = ["Martin", "Helena", "Ingrid", "Joseph"];
let iterator = names.into_iter().map(greet);
let chars_iter = iterator.flat_map(OwnedCharsIter::new);
println!("{:?}", chars_iter.collect::<String>())
}
"Hello, MartinHello, HelenaHello, IngridHello, Joseph"

How to access the value of a field in a tracing span?

I'm using the tracing library in my project and there is one thing I'm not able to figure out: How can I access a value (that I set in my span when I create it) in my Layer?
My layer looks like this:
impl<S> Layer<S> for CustomLayer where S: Subscriber {
fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest {
Interest::sometimes() //hardcoding so enabled() will be called everytime a span is created
}
fn enabled(&self, metadata: &Metadata<'_>, ctx: Context<'_, S>) -> bool {
if metadata.is_span() {
// How do I access value of key here?
if value == X {
true
} else if value == Y {
false
}
}
true // default
}
}
You can access the data in a Span if you have access to either its ValueSet (as found in new_span() or on_new_span() via Attributes) or a Record entry for it (as found in record() or on_record()). With that you can use the visitor pattern to find the information you desire. Here's a simple implementation that checks if a field exists and its value is a matching string:
use std::fmt::Debug;
use tracing::field::{ValueSet, Visit, Field};
use tracing::span::Record;
struct MatchStrVisitor<'a> {
field: &'a str,
value: &'a str,
matched: bool,
}
impl Visit for MatchStrVisitor<'_> {
fn record_debug(&mut self, _field: &Field, _value: &dyn Debug) {}
fn record_str(&mut self, field: &Field, value: &str) {
if field.name() == self.field && value == self.value {
self.matched = true;
}
}
}
fn value_in_valueset(valueset: &ValueSet<'_>, field: &str, value: &str) -> bool {
let mut visitor = MatchStrVisitor { field, value, matched: false };
valueset.record(&mut visitor);
visitor.matched
}
fn value_in_record(record: &Record<'_>, field: &str, value: &str) -> bool {
let mut visitor = MatchStrVisitor { field, value, matched: false };
record.record(&mut visitor);
visitor.matched
}
This is pretty rudimentary but hopefully demonstrates what is possible. One thing to note is that the "value" that is stored is either a primitive value (i64, u64, bool, str, etc.) or in a type-erased form via &dyn Debug. Those are the only types of values you can receive from the visitor.
Addressing OP's case in particular, as explained in this issue you cannot access this information in the enabled() method since that occurs before any values are recorded. You will need to make your determination in the new_span() method, and use span extensions via the registry to track whether you consider the span is "enabled" in your other methods.
Here's another rudimentary example:
use tracing::span::Attributes;
use tracing::{Subscriber, Metadata, Id, Event};
use tracing::subscriber::Interest;
use tracing_subscriber::layer::{Context, Layer};
use tracing_subscriber::registry::LookupSpan;
struct CustomLayer;
struct CustomLayerEnabled;
impl<S> Layer<S> for CustomLayer where S: Subscriber + for <'a> LookupSpan<'a> {
fn register_callsite(&self, _metadata: &'static Metadata<'static>) -> Interest {
Interest::sometimes()
}
fn enabled(&self, metadata: &Metadata<'_>, _ctx: Context<'_, S>) -> bool {
metadata.is_span()
}
fn on_new_span(&self, attrs: &Attributes<'_>, id: &Id, ctx: Context<'_, S>) {
if value_in_valueset(attrs.values(), "myfield", "myvalue") {
ctx.span(id).unwrap().extensions_mut().insert(CustomLayerEnabled);
}
}
fn on_event(&self, event: &Event<'_>, ctx: Context<'_, S>) {
let span_id = event.parent().unwrap();
if let None = ctx.span(span_id).unwrap().extensions().get::<CustomLayerEnabled>() {
return;
}
// ... rest of your logic
}
}
Note: I've completely rewritten this answer taking info from the comments and my newfound experience.

How does ownership of variables work between iterations?

I am trying to learn rust and thought of implementing a linked list as a practice problem to understand Ownership/Borrow concepts and I am having a hard time.
The push method of LinkedList should work as:
t = 0 | root: None | push 5
t = 1 | root: { value: 5, next: None } | push 6
t = 2 | root: { value: 5, next: { value: 6, None } } |
Here's the code trying to do the same:
#[derive(Debug, Clone)]
struct Node {
value: u32,
next: Option<Box<Node>>,
}
impl Node {
fn new(value: u32) -> Node {
Node { value, next: None }
}
}
#[derive(Debug, Clone)]
struct LinkedList {
root: Option<Box<Node>>,
}
impl LinkedList {
fn new(node: Option<Box<Node>>) -> LinkedList {
LinkedList { root: node }
}
fn push(self, node: Option<Box<Node>>) {
let maybe_node = self.root;
loop {
match maybe_node {
Some(tail_node) => { // use of moved value. std::boxed::Box<Node> doesn't implement copy trait. --- (1)
if tail_node.next.is_none() {
tail_node.next = node; // tail_node is not mutable. --- (2)
break;
};
}
_ => (),
}
}
}
}
fn main() {
let mut node = Node::new(0);
let linked_list = LinkedList::new(Some(Box::new(node)));
for number in 1..5 {
node = Node::new(number);
linked_list.push(Some(Box::new(node))); // move occurs. Value moved here in a previous iteration --- (3)
}
println!("{:?}", linked_list);
}
I don't understand the "move occurs" errors (1, 3) it isn't clear to me where the value moved? It appears iterations are causing the ownership to change but I can't see how.
Also, the error (2) Is my implementation the best way?
In Rust there two ways is which ownership is handled, and that is either move semantic or borrow semantic. Here are some rules to go about understanding it.
The first rule is that each piece of data can have only a single owner at same time. If you assign some variable to some other variable, then you effectively move the data, and the data becomes owned by new owner.
The second rule is that if you have some data, which is owned by someone, but you would like to read it, then you can borrow it. Borrowing is essentially obtaining a reference to data, which is owned by someone else.
Now back to your problem. In your function declaration you have declared the first parameter as self
fn push(self, node: Option<Box<Node>>) {
let maybe_node = self.root;
loop {
match maybe_node {
Some(tail_node) => { // use of moved value. std::boxed::Box<Node> doesn't implement copy trait. --- (1)
if tail_node.next.is_none() {
tail_node.next = node; // tail_node is not mutable. --- (2)
break;
};
}
_ => (),
}
}
}
this essentially means that when you call your function you are taking the ownership of self, and thus you are invalidating any previous owner. What happens in the loop is that in the first iteration the value is moved into the function and is no longer owned by linked_list. In second iteration you again try to access the data, but it is no longer valid, since it was moved into the function.
To circumvent your problem you will need to declare your function as follows:
fn push(&mut self, node: Option<Box<Node>>) {
let maybe_node = self.root;
loop {
match maybe_node {
Some(tail_node) => { // use of moved value. std::boxed::Box<Node> doesn't implement copy trait. --- (1)
if tail_node.next.is_none() {
tail_node.next = node; // tail_node is not mutable. --- (2)
break;
};
}
_ => (),
}
}
}
With declaration above you are saying that you are borrowing self, and that you would like to make changes to it ( that is the reason we have &mut and not just & ).
For more details please refer to the chapter about ownership in Rust book.

How to return a reference to a global vector or an internal Option?

I'm trying to create a method that can return a reference to Data that is either in a constant global array or inside an Option in an item. The lifetimes are certainly different, but it's safe to assume that the lifetime of the data is at least as long as the lifetime of the item. While doing this, I expected the compiler to warn if I did anything wrong, but it's instead generating wrong instructions and the program is crashing with SIGILL.
Concretely speaking, I have the following code failing in Rust 1.27.2:
#[derive(Debug)]
pub enum Type {
TYPE1,
TYPE2,
}
#[derive(Debug)]
pub struct Data {
pub ctype: Type,
pub int: i32,
}
#[derive(Debug)]
pub struct Entity {
pub idata: usize,
pub modifier: Option<Data>,
}
impl Entity {
pub fn data(&self) -> &Data {
if self.modifier.is_none() {
&DATA[self.idata]
} else {
self.modifier.as_ref().unwrap()
}
}
}
pub const DATA: [Data; 1] = [Data {
ctype: Type::TYPE2,
int: 1,
}];
fn main() {
let mut itemvec = vec![Entity {
idata: 0,
modifier: None,
}];
eprintln!("vec[0]: {:p} = {:?}", &itemvec[0], itemvec[0]);
eprintln!("removed item 0");
let item = itemvec.remove(0);
eprintln!("item: {:p} = {:?}", &item, item);
eprintln!("modifier: {:p} = {:?}", &item.modifier, item.modifier);
eprintln!("DATA: {:p} = {:?}", &DATA[0], DATA[0]);
let itemdata = item.data();
eprintln!("itemdata: {:p} = {:?}", itemdata, itemdata);
}
Complete code
I can't understand what I'm doing wrong. Why isn't the compiler generating a warning? Is it the removal of the (non-copy) item of the vector? Is it the ambiguous lifetimes?
How to return a reference to a global vector or an internal Option?
By using Option::unwrap_or_else:
impl Entity {
pub fn data(&self) -> &Data {
self.modifier.as_ref().unwrap_or_else(|| &DATA[self.idata])
}
}
but it's instead generating wrong instructions and the program is crashing with SIGILL
The code in your question does not have this behavior on macOS with Rust 1.27.2 or 1.28.0. On Ubuntu I see an issue when running the program in Valgrind, but the problem goes away in Rust 1.28.0.
See also:
Why should I prefer `Option::ok_or_else` instead of `Option::ok_or`?
What is this unwrap thing: sometimes it's unwrap sometimes it's unwrap_or

Resources