Changing enum value of struct in iterator - rust

pub struct Server {
devices: Vec<Device>,
}
pub struct Device {
configuration: Configuration,
}
pub enum Configuration {
Gradient {
stops: Vec<String>,
brightness: f32,
duration: i32,
random_starting_point: bool,
},
}
I want to update the configurations of certain devices dynamically through the method:
fn update_configuration(&mut self, devices: Vec<Device>, configuration: Configuration) {
self.devices
.iter_mut()
.filter(|device| devices.contains(device.get_id()))
.for_each(|device| {
(*device).configuration = configuration;
});
}
The compiler outputs:
error[E0507]: cannot move out of `configuration`, a captured variable in an `FnMut` closure
device.update_configuration(configuration);
^^^^^^^^^^^^^ move occurs because `configuration` has type `device::Configuration`, which does not implement the `Copy` trait
And since I have a Vec<String> in that enum value I can't implement the Copy trait. I do have a basic understanding of memory management (stack, heap) and pointers but I can't quite wrap my head around it completely.
My questions
How do I achieve such a field change?
Is this the idiomatic way to update such a field in a struct?

In Rust every piece of data can have at most 1 unique owner. You're taking a single instance of Configuration and trying to share it across potentially multiple Devices. The simplest way to solve your problem would be to derive an implementation of Clone which will allow you to make clones of the Configuration enum whenever you try to share it.
#[derive(Clone)]
pub enum Configuration {}
And then clone it in your loop:
self.devices
.iter_mut()
.filter(|device| devices.contains(device.get_id()))
.for_each(|device| {
(*device).configuration = configuration.clone();
});
Note: this will give a unique clone of Configuration to every Device which is what I'm assuming you want.

Related

How do I avoid Enum + Trait pattern when a struct is not object safe?

I get the implications of object safety, but I'm trying to find an idiomatic way to solve for this situation.
Say I have two structs that share common behavior and also need to derive PartialEq for comparison in another part of the program:
trait Growl:PartialEq {
fn growl(&self);
}
#[derive(PartialEq)]
struct Pikachu;
#[derive(PartialEq)]
struct Porygon;
impl Growl for Pikachu {
fn growl(&self) {
println!("pika");
}
}
impl Growl for Porygon {
fn growl(&self) {
println!("umm.. rawr?");
}
}
In another struct, I want to hold a Vec of these objects. Since I can't use a trait object with Vec<Box<Growl>>...
struct Region{
pokemon: Vec<Box<dyn Growl>>,
}
// ERROR: `Growl` cannot be made into an object
... I need to get more creative. I read this article, which suggests using an enum or changing the trait. I haven't yet explored type erasure, but it seems heavy-handed for my use case. Using an enum like this is what I've ended up doing but it feels unnecessarily complex
enum Pokemon {
Pika(Pikachu),
Pory(Porygon),
}
Someone coming through this code in the future now needs to understand the individual structs, the trait (which provides all functionality for the structs), and the wrapper enum type to make changes.
Is there a better solution for this pattern?
I read this article, which suggests using an enum or changing the trait. I haven't yet explored type erasure, but it seems heavy-handed for my use case.
Type erasure is just a synonym term for dynamic dispatch - even your original Box<dyn Growl> "erases the type" of the Pokemon. What you want here is to continue in the same vein, by creating a new trait better taylored to your use case and providing a blanket implementation of that trait for any type that implements the original trait.
It sounds complex, but it's actually very simple, much simpler than erased-serde, which has to deal with serde's behemoth traits. Let's go through it step by step. First, you create a trait that won't cause issues with dynamic dispatch:
/// Like Growl, but without PartialEq
trait Gnarl {
// here you'd have only the methods which are actually needed by Region::pokemon.
// Let's assume it needs growl().
fn growl(&self);
}
Then, provide a blanket implementation of your new Gnarl trait for all types that implement the original Growl:
impl<T> Gnarl for T
where
T: Growl,
{
fn growl(&self) {
// Here in the implementation `self` is known to implement `Growl`,
// so you can make use of the full `Growl` functionality, *including*
// things not exposed to `Gnarl` like PartialEq
<T as Growl>::growl(self);
}
}
Finally, use the new trait to create type-erased pokemon:
struct Region {
pokemon: Vec<Box<dyn Gnarl>>,
}
fn main() {
let _region = Region {
pokemon: vec![Box::new(Pikachu), Box::new(Porygon)],
};
}
Playground

How can I simultaneously access data from and call a method from a struct?

For my first project I wanted to create a terminal implementation of Monopoly. I have created a Card, Player, and App structs. Originally my plan was to create an array inside the App struct holding a list of cards which I could then randomly select and run an execute() method on, which would push a log to the logs field of the App. What I thought would be best was this:
pub struct Card {
pub group: u8,
pub name: String,
pub id: u8,
}
impl Card {
pub fn new(group: u8, name: String, id: u8) -> Card {
Card { group, name, id }
}
pub fn execute(self, app: &mut App) {
match self.id {
1 => {
app.players[app.current_player].index = 24;
app.push_log("this works".to_string(), "LOG: ".to_string());
}
_ => {}
}
}
}
pub struct Player<'a> {
pub name: &'a str,
pub money: u64,
pub index: u8,
pub piece: char,
pub properties: Vec<u8>,
pub goojf: u8, // get out of jail freeh
}
impl<'a> Player<'a> {
pub fn new(name: &'a str, piece: char) -> Player<'a> {
Player {
name,
money: 1500,
index: 0,
piece,
properties: Vec::new(),
goojf: 0,
}
}
}
pub struct App<'a> {
pub cards: [Card; 1],
pub logs: Vec<(String, String)>,
pub players: Vec<Player<'a>>,
pub current_player: usize,
}
impl<'a> App<'a> {
pub fn new() -> App<'a> {
App {
cards: [Card::new(
11,
"Take a ride on the Penn. Railroad!".to_string(),
0,
)],
logs: vec![(
String::from("You've begun a game!"),
String::from("BEGIN!:"),
)],
players: vec![Player::new("Joe", '#')],
current_player: 0,
}
}
pub fn draw_card(&mut self) {
if self.players[self.current_player].index == 2
|| self.players[self.current_player].index == 17
|| self.players[self.current_player].index == 33
{
self.cards[0].execute(self);
}
}
pub fn push_log(&mut self, message: String, status: String) {
self.logs.push((message, status));
}
}
fn main() {}
However this code throws the following error:
error[E0507]: cannot move out of `self.cards[_]` which is behind a mutable reference
--> src/main.rs:76:13
|
76 | self.cards[0].execute(self);
| ^^^^^^^^^^^^^ move occurs because `self.cards[_]` has type `Card`, which does not implement the `Copy` trait
I managed to fix this error by simply declaring the array of cards in the method itself, however, this seem to be pretty brute and not at all efficient, especially since other methods in my program depend on cards. How could I just refer to a single array of cards for all of my methods implemented in App or elsewhere?
As others have pointed out, Card::execute() needs to take &self instead of self, but then you run into the borrow checker issue, which I'll spend the rest of this answer discussing.
It may seem odd, but Rust is actually protecting you here. The borrow checker does not look into functions to see what they do, so it has no idea that Card::execute() won't do something to invalidate the referenced passed as the first argument. For example, if App::cards was a vector instead of an array, it could clear the vector.
Something that could actually practically happen here to cause undefined behavior would be if Card::execute() took a string slice from self.name and then cleared the card's name attribute through the mutable reference to app. None of these actions would be prohibited, and you'd be left with an invalid reference to a string slice. This is why the borrow checker isn't letting you make this method call, and this is exactly the kind of accident that Rust is designed to prevent.
There's a few ways around this. One option is to only pass the pieces of the App value needed to complete the task. You can borrow different parts of the same value. The problem here is that the reborrow of self overlaps with the borrow self.cards[0]. Passing each field separately isn't very ergonomic though, as in this case you'll wind up having to pass a reference to pretty much everything else on App.
It looks like the Card values don't actually contain any game state, and are used as data for the game engine. If this is the case, then the cards can live outside of App, like so:
pub struct App<'a> {
// Changed to an unowned slice.
pub cards: &'a [Card],
pub logs: Vec<(String, String)>,
pub players: Vec<Player<'a>>,
pub current_player: usize,
}
impl<'a> App<'a> {
pub fn new(cards: &'a [Card]) -> App<'a> {
App {
cards,
// ...
Then in your main() you can initialize the data and borrow it:
fn main() {
let cards: [Card; 1] = [Card::new(
11,
"Take a ride on the Penn. Railroad!".to_string(),
0,
)];
let app = App::new(&cards);
}
This solves the compilation problem. I'd suggest making other changes, as well:
App should probably be renamed GameState or something to emphasize that this struct should contain only mutable game state, and no immutable reference data.
Player's name field should probably be an owned String instead of an unowned &str, otherwise some other entity in the program will need to own a string slice for the duration of the program so that Player can borrow it.
Does a card need to be able to mutate the cards in self? If you know that execute will not need access to cards, the easiest solution is to split App into further structs so you can better limit the access of the function.
Unless there is another layer to your program that interacts with App as a singular object, requiring everything be in a single struct to perform operations will likely only constrain your code. If possible it is better to split it into its core components so you can be more selective when sharing references and avoid needing to make so many fields pub.
Here is a rough example:
pub struct GameState<'a> {
pub players: Vec<Player<'a>>,
pub current_player: usize,
}
/// You may want to look into using https://crates.io/crates/log instead to make logging easier.
pub struct Logs {
entries: Vec<(String, String)>,
}
impl Logs {
/// Use ToOwned so you can use both both &str and String
pub fn push<S: ToOwned<String>>(&mut self, message: S, status: S) {
self.entries.push((message.to_owned(), status.to_owned()));
}
}
pub struct Card {
group: u8,
name: String,
id: u8,
}
impl Card {
pub fn new(group: u8, name: String, id: u8) -> Self {
Card { group, name, id }
}
/// Use &self because there is no reason we need are required to consume the card
pub fn execute(&self, state: &mut GameState, logs: &mut Logs) {
if self.id == 1{
state.players[state.current_player].index = 24;
logs.push("this works", "LOG");
}
}
}
Also as a side note, execute consumes a card when called since it does not take a reference. Since Card does not implement Copy, that would require it be removed from cards so it can be moved.
Misc Tips and Code Review
Using IDs
It looks like you frequently use IDs to distinguish between items. However, I think your code will look cleaner and be easier to write if you used more human readable types. For example, do cards need an ID? Usually it is preferable to define your struct based on how the data is used. Last time I played monopoly, I don't remember picking up a card and referring to the card ID to determine what to do. I would instead recommend defining a Card by how it is used in the came. If I am remembering correctly, each card contains a short message telling the player what to do. Technically a card could consist of just the message, but you can instead make your code a bit cleaner by separating out the action to an enum so actions are not hard coded to the text on the card.
pub struct Card {
text: String,
action: CardAction,
}
// Note: enums which can also hold data, are more commonly referred to as
// "tagged unions" in computer science. It can be a pain to search for them if
// you don't know what they are called.
pub enum CardAction {
ProceedToGo,
GoToJail,
GainOrLoseMoney(i64),
// etc.
}
On a similar note, it looks like you are trying to be memory conscious by using the smallest type required for a given value. I would recommend against this thinking. If a value of 253u8 is equally as invalid as 324234i32, then the smaller type is not doing anything to help you. You might as well use i32/u32 or i64/u64 since most systems will have an easier time operating on these types. The same thing goes for indices and using other integer types instead of usize since choosing to use another type will only give you more work converting it to and from a usize.
Sharing Owned References
Depending on your design philosophy you might want to store a reference to a struct in multiple places. This can be done using a reference counter Rc<T>. Here are some quick examples. Note that these can not be shared between threads.
let property: Rc<Property> = Rc::new(Property::new(/* etc */));
// Holds an owned reference to the same property as property that can be accessed immutably
let ref_to_property: Rc<Property> = property.clone();
// Or if you want interior mutability you can use Rc<RefCell<T>> instead.
let mutable_property = Rc::new(RefCell::new(Property::new(/* etc */)));

How to offer an API that stores values of different types and can return them with the original type restored?

I want to offer a safe API like below FooManager. It should be able to store arbitrary user-defined values that implement a trait Foo. It should also be able to hand them back later - not as trait object (Box<dyn Foo>) but as the original type (Box<T> where T: Foo). At least conceptually it should be possible to offer this as a safe API, by using generic handles (Handle<T>), see below.
Additional criteria:
The solution should work in stable Rust (internal usage of unsafe blocks is perfectly okay though).
I don't want to modify the trait Foo, as e.g. suggested in How to get a reference to a concrete type from a trait object?. It should work without adding a method as_any(). Reasoning: Foo shouldn't have any knowledge about the fact that it might be stored in containers and be restored to the actual type.
trait Foo {}
struct Handle<T> {
// ...
}
struct FooManager {
// ...
}
impl FooManager {
// A real-world API would complain if the value is already stored.
pub fn keep_foo<T: Foo>(&mut self, foo: Box<T>) -> Handle<T> {
// ...
}
// In a real-world API this would return an `Option`.
pub fn return_foo<T: Foo>(&mut self, handle: Handle<T>) -> Box<T> {
// ...
}
}
I came up with this (Rust Playground) but not sure if there's a better way or if it's safe even. What do you think of that approach?

PhantomData type usage in rust

I was going through some rust source code and I found a data type called PhantomData. I was going through the rust documentation and searched through the internet a lot. However, I couldn't understand the actual use of this data type with rust. If possible, could somebody please explain me this in simple manner?
pub struct GPIOD {
_marker: PhantomData<*const ()>,
}
The PhantomData struct is meant to signal to the compiler that a type or lifetime is being used in some way that is transparent to the compiler.
To quote the docs:
Adding a PhantomData field to your type tells the compiler that your type acts as though it stores a value of type T, even though it doesn't really. This information is used when computing certain safety properties.
For example, if we look at the iterator type for a slice [T]: std::slice::Iter<'a, T> and its declaration using the src button we'll see that it's actually declared as such:
struct Iter<'a, T: 'a> {
start: *const T,
end: *const T,
_phantom: PhantomData<&'a T>,
}
std makes frequent use of pointer arithmetic to make optimizations more readily available (Although that is not to endorse the usage of pointer arithmetic in user code). In this case, we need to assure ourselves that the data that is pointed to by the two raw pointers (Which carry no lifetimes) outlive the struct, so we keep a PhantomData<&'a T> to tell the compiler to act like as if Iter owned a &'a T therefore enforcing lifetime rules for it.
In addition to the other answer, I'd like to add an example. As said in the other answer, PhantomData allows to add an arbitrary lifetime dependence between 2 structure.
Suppose that you have a struct that manages a logging tool with a message receiver, and a struct that represents an actual logger that sends messages to the manager. Although the logger does not directly depends on the manager, the manager must outlive the logger to prevent send errors.
The naive code does not create any dependency between the 2 structs:
struct LogManager {
// ...
}
impl LogManager {
fn logger(&self) -> Logger {
// returns a fresh `Logger` that holds no reference to `LogManager`...
}
}
struct Logger {
// ...
}
Now, if the Logger holds a phantom reference, we can force a dependency between the 2 structs:
struct Logger<'a> {
// ...
_marker: PhantomData<'a ()>,
}
and in the impl block:
impl LogManager {
fn logger(&self) -> Logger {
Logger {
// ...
// Here, `Logger` will have a lifetime dependent of the `LogManager`'s
// lifetime due to `PhantomData`:
_marker: PhantomData,
}
}
}
Now, no instance of Logger can outlive the LogManager where it comes from.

It is possible to use std::rc::Rc with a trait type?

The code looks like this:
// Simplified
pub trait Field: Send + Sync + Clone {
fn name(&self);
}
#[deriving(Clone)]
pub enum Select {
SelectOnly(Vec<Rc<Field>>),
SelectAll
}
The error is:
the trait `core::kinds::Sized` is not implemented for the type `Field+'static`
Is there any other way to have the vector with reference-counted immutable objects of trait type?
I suppose that I can rewrite the code like this:
#[deriving(Clone)]
pub enum Select {
SelectOnly(Vec<Rc<Box<Field>>>),
SelectAll
}
Is it the right way?
It is possible to create an trait object with an Rc as of Rust 1.1. This compiles:
use std::rc::Rc;
trait Field: Send + Sync {
fn name(&self);
}
enum Select {
Only(Vec<Rc<Field>>),
All,
}
// ---
struct Example;
impl Field for Example {
fn name(&self) {}
}
fn main() {
let fields: Vec<Rc<Field>> = vec![Rc::new(Example)];
Select::Only(fields);
}
Note that your original example used Clone, but you cannot make such a trait into a trait object because it is not object safe. I've removed it to answer the question.
I also removed the redundancy of the enum variant names.
I believe that it should be possible with DST, but Rust is not there just yet. The major motivation for DST was exactly the desire to use trait objects with any kind of smart pointer. As far as I know, this should be possible by 1.0 release.
As a temporary workaround, indeed, you can use Rc<Box<T>>, though this kind of double indirection is unfortunate.
It will be possible after #18248 and #16918.

Resources