Why I cannot return this `Option<>`? - rust

Given the code in this playground is there a way to fix the error:
Compiling playground v0.0.1 (/playground)
error[E0507]: cannot move out of `self.coach` which is behind a shared reference
--> src/main.rs:20:9
|
20 | self.coach
| ^^^^^^^^^^ move occurs because `self.coach` has type `Option<Box<Coach>>`, which does not implement the `Copy` trait
For more information about this error, try `rustc --explain E0507`.
// #[derive(Default, Clone)]
pub struct Coach {
pub id: Option<i64>,
pub name: String,
pub team: Option<Box<Coach>>,
}
// #[derive(Default, Clone)]
pub struct Team {
pub id: Option<i64>,
pub name: String,
coach: Option<Box<Coach>>,
}
impl Team {
pub fn coach(&self) -> Option<Box<Coach>> {
self.coach
}
}
pub struct RestCoach {
pub id: i64,
pub name: String,
}
impl From<Coach> for RestCoach {
fn from(coach: Coach) -> Self {
Self {
id: coach.id.unwrap(),
name: coach.name,
}
}
}
pub struct RestTeam {
pub id: i64,
pub name: String,
pub coach: Option<RestCoach>,
}
impl From<Team> for RestTeam {
fn from(team: Team) -> Self {
Self {
id: team.id.unwrap(),
name: team.name.clone(),
coach: team.coach().map(|x| RestCoach::from(*x)),
}
}
}
Is using clone() the only fix?

First, when you return Option<T> you are handing ownership of the T to the caller. When someone calls team.coach() do you want to transfer ownership of the coach to the caller and leave the team coachless? Or do you want to give them a reference to the coach?
It's better if the signature is pub fn coach(&self) -> Option<&Coach>. Let the caller borrow the coach, but have the team retain ownership. Also get rid of the Box. It's not relevant to the caller.
Second, coach: Option<Box<Coach>> means that teams own their coaches. I don't think that's the right way to model it. Coaches ought to exist outside of any one team. There are a couple of better ways to model it.
Shared references
Teams could have shared references to coaches. Coaches would need to be owned by some other piece of code. For example, in main() you could have a Vec<Coach> and a Vec<Team>. main() would own both the coaches and the teams, and the teams would merely have references to the coaches without taking ownership of them.
This requires the use of lifetimes. It has zero runtime overhead but it can mean tangling with the borrow checker, which isn't always fun.
pub struct Team<'coach> {
pub id: Option<i64>,
pub name: String,
coach: Option<&'coach Coach>,
}
impl Team<'_> {
pub fn coach(&self) -> Option<&Coach> {
self.coach
}
}
Playground
Shared ownership
Teams could shared ownership of coaches with other teams by using, say, Rc or Arc. No one team would own a coach. This would make sense if a coach could coach multiple teams.
From a coding perspective this is nice because it gets rid of the lifetimes and gets the borrow checker out of your hair, though it does have some minor runtime overhead.
pub struct Team {
pub id: Option<i64>,
pub name: String,
coach: Option<Rc<Coach>>,
}
impl Team {
pub fn coach(&self) -> Option<&Coach> {
self.coach.as_deref()
}
}
Playground
Weak references
Another approach would be to have teams keep Weak references to their coaches. Instead of the teams owning the Rc<Coach> shared pointers you'd have them stored somewhere else outside of the teams. Teams would effectively just have references to the Rc pointers.
They're "weak" references because they don't keep the coaches alive. Some other piece of code would have to own the Rc pointers and keep them alive. This means that the coaches could be dropped at any time independent of any team they're associated with. Team code would have to anticipate the possibility of the weak reference going stale.
pub struct Team {
pub id: Option<i64>,
pub name: String,
coach: Option<Weak<Coach>>,
}
impl Team {
pub fn coach(&self) -> Option<Rc<Coach>> {
self.coach.as_ref().and_then(Weak::upgrade)
}
}
Playground
You'll need to apply a similar thought process to the rest of the program. team: Option<Box<Coach>> needs a similar rethink. Do coaches own teams? Probably not. Coaches work for teams, they don't own them.

Related

Is it possibile to create a static Struct with these HashMap? And is Mutex needed in this case?

I need a Store struct like this:
pub struct Store {
pub players: HashMap<(String, i64), Player>,
pub teams: HashMap<(String, i64), Team>,
}
impl Store {
pub fn new() -> Self {
Self {
players: HashMap::new(),
team: HashMap::new(),
}
}
}
The values in those HashMap are used as "shared, request-scoped memory" and then deleted (using .remove(k)).
QUESTIONs
Since I don't care if two or more requests write/read the same entries at the same time (very unlikely) should I still use Mutex?
// Like this?
let store = Arc::new(Mutex::new(Store::new()))
// Or this?
pub fn new() -> Self {
Self {
players: Mutex::new(HashMap::new()),
team: Mutex::new(HashMap::new()),
}
}
Since the store is created when the application starts and is never destroyed, would it be useful to create a 'static one thus avoiding the use of Arc too?
// Something like:
const store: &mut Store = &mut Store::new();
UPDATE:
I'm trying to use this store to avoid nested structs issues like:
struct Player {
id: String,
team: Box<Team>, // see the Box here
}
So I'm trying to use flat, plain data like:
struct Player {
id: String,
team_id: String,
}
but I need something to use as store.

Serialize complicated data structure

I'm having trouble serializing the following struct. I have narrowed it down to, that the problem lies within the variable objects, containing trait structs within a HashMap. I'll try to explain my circumstances:
I have the following main struct, which i'm interested in obtaining data from:
#[derive(Serialize)]
pub struct System {
pub objects: HashMap<(u32, u32), Box<dyn CommonObjects>>,
pub paths: Vec<Path>,
pub loops: Vec<Loop>,
pub physics: Physics,
pub run_limit_loops: u32,
pub run_limit_paths: u32,
pub error_tol_loops: f64,
pub error_tol_paths: f64,
pub unknown_flow_outlets: u32,
pub unknown_pumps_id: u32,
pub system: u32,
}
The kind of structs which are contained within objects are as the following:
pub struct Outlet {
// Variables found in all structs contained within 'objects'
pub Q: f64,
pub hL: f64,
pub ob: u32,
pub id: u32,
pub active: bool,
pub system: u32,
pub con_Q: HashMap<u32, f64>,
// Variables found only in this struct.
pub p_dyn: f64,
pub flow_specified: String,
pub submerged: bool,
}
pub struct Pipe {
// Variables found in all structs contained within 'objects'
pub Q: f64,
pub hL: f64,
pub ob: u32,
pub id: u32,
pub active: bool,
pub system: u32,
pub con_Q: HashMap<u32, f64>,
// Variables found only in this struct.
pub Re: f64,
pub f: f64,
}
These struct has some variables which are only used within themselves, and some variables which are common for all structs contained within objects (p_dyn is only used within Outlet, while Q is used for all structs contained within objects) To get these variables, get-function are defined, both within the local struct, and by the trait CommonObject. All i am interested in, is serializing objects in order to get all the variables in a string format, both the common ones, and the ones only appearing locally within a struct, so that i can send the variables to other programs to further visualization.
In this following code the error occurs:
// Where the system struct originates from.
let systems: Vec<System> = system_analyse::analyse_system(data);
// I try to only serialize the objects contained within one of the system structs.
let jsonstringresult = serde_json::to_string(&systems[0].objects);
match jsonstringresult {
Ok(v) => {
println!("{:?}", &v);
v
},
Err(e) => {
// The error message originates from here.
println!("An error occured at serializing: {}", e);
String::new()
}
}
I get the following error:
An error occured at serializing: key must be a string
I have found this thread discussing the issue of serializing dynamic traits, and i've followed the instructions and added the following to the trait:
pub trait CommonObjects: erased_serde::Serialize {
...
}
serialize_trait_object!(CommonObjects);
Which makes the code compile in the first place. I've also found this site getting the same error, but the issue there seems to be with enums. Maybe the problem in this site is related to my problem, but i cant figure out how if so.
I'm open to all sort of feedback and even fundamentally change the structure of the code if so necessary.
A quick way to serialize a HashMap with non-string keys to Json is to use the serde_as macro from the serde_with crate.
use serde_with::serde_as;
#[serde_as]
#[derive(Serialize)]
pub struct System {
#[serde_as(as = "Vec<(_, _)>")]
pub objects: HashMap<(u32, u32), Box<dyn CommonObjects>>,
//...
}
The #[serde_as(as = "Vec<(_, _)>")] encodes the map as a sequence of tuples, representing pairs of keys and values. In Json, this will become an array of 2-element arrays.

How to modify the &mut self contents and return self

I am having a struct and respective impl (add_account) as well.
Struct
pub struct Departments {
pub id: String,
pub linked_accounts: Vec<Account>,
}
Impl
impl Departments {
pub fn add_account(&mut self, acct: Account) -> Self {
let mut vec: Vec<Account> = self.linked_accounts; //*Error here*
vec.push(acct);
Self {
id: self.id, //*Error here*
linked_accounts: vec,
}
}
}
Calling area
getting value from DB and adding account and update back to DB
match db.get::<Departments>(id).await? {
None => bail!("No records found"),
Some(departments) => {
let mut departments = departments;
//calling area
departments.add_account(Account::Credit);
let id = Id::new(Departments::KIND, &id);
gh.update::<_, Departments>(
id,
departments.clone(),
)
.await?;
}
}
Error as 'Cannot move self' while assigning self values inside.
There are a couple of ways to interpret your question. In all the cases, the answer starts with "Your function signature is wrong", but what exactly it should be, depends on your usecase.
But most certainly, it should be one of:
pub fn add_account(&mut self, acct: Account)
pub fn add_account(&mut self, acct: Account) -> &mut Self
pub fn add_account(mut self, acct: Account) -> Self
I think the biggest misconception you are having is that you think you need to return Self. The way you are using add_account, by simply calling it on departments.add_account(Account::Credit) does not require you to return Self. You can directly modify the self object:
pub struct Departments {
pub id: String,
pub linked_accounts: Vec<Account>,
}
impl Departments {
pub fn add_account(&mut self, acct: Account) {
self.linked_accounts.push(acct);
}
}
Now, there is a usecase where you want to return some form of Self, and that is if you want to be able to chain those calls:
departments
.add_account(Account::Credit)
.add_account(Account::Debit)
.add_account(Account::Savings);
This is usually done by returning &mut Self:
pub struct Departments {
pub id: String,
pub linked_accounts: Vec<Account>,
}
impl Departments {
pub fn add_account(&mut self, acct: Account) -> &mut Self {
self.linked_accounts.push(acct);
self
}
}
Note that this still doesn't require you to instantiate a new Self object, like you were doing in your code.
The actual error
In case you want to understand the original error:
The &mut self argument means that you only borrow self, and you have to give it back at some point. (happens automatically at the end of the function)
let mut vec: Vec<Account> = self.linked_accounts; moves the linked_accounts member out of self. This is only possible when we take ownership of self instead of borrowing it, because then, we can dismantle it to our pleasing. But as we need to give it back, we cannot just move members out of it.
I didn't talk about the actual error in more detail, because it was just an artifact of the incorrect function signature and didn't really contribute meaningfully to a solution.
Either way, I think there are a couple of misunderstandings of yours as to how ownership works, so I recommend reading the ownership chapter of the Rust book.
The reason why I think you have misunderstandings, is because it is literally impossible to return Self if your function signature contains &mut self. Self is owned, and you cannot create an owned object from a borrowed one without copying it.
Yes, you are trying to create a copy of it in your attempt to implement it, but the usage example you posted shows me that you don't actually want to create a copy.
In a meantime you can also Clone Self.
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=45c902d55a8f3e190893f82f720fdae2

How to create a vector based on an `&[Box<dyn CustomTrait>]`?

I have a custom trait that I use as the element type in a slice:
pub trait IConstraint {
// members here
}
pub struct Scenario<'a> {
pub constraints: &'a [Box<dyn IConstraint>]
}
I would like to offer an add_constraint method that does a copy-on-write of the slice. Something like this:
impl<'a> Scenario<'a> {
pub fn add_constraint(&mut self, constraint: Box<dyn IConstraint<TNodeState>>) {
let mut constraints: Vec<Box<dyn IConstraint<TNodeState>>> = Vec::new();
constraints.copy_from_slice(self.constraints);
constraints.push(constraint);
self.constraints = &constraints;
}
}
The problem is I get this error:
the trait bound Box<dyn IConstraint<TNodeState>>: std::marker::Copy is not satisfied
the trait std::marker::Copy is not implemented for Box<dyn IConstraint<TNodeState>>
Ok, so the Box<T> doesn't implement the Copy trait. Fair enough. But how do I address that? Ideally, I'd reuse the boxes or at least the constraints because they are immutable. But if I can't do that due to rust ownership rules, how can I implement the Copy trait on a box type? I've tried various ways and they all produce errors.
This attempt produces "Copy not allowed on types with destructors":
impl<TNodeState> Copy for Box<dyn IConstraint<TNodeState>> {
}
What about Clone? I can switch to constraints.clone_from_slice(self.constraints);, but then implementing the Clone trait on IConstraint produces a bunch of "IConstraint cannot be made into an object" errors.
Even if I could get box to be cloneable, then of course I get the anticipated borrow lifetime flaw from my add_constraint method:
borrowed value does not live long enough
So do I have to throw out my add_constraint function idea altogether and force the owner of my struct to manually copy it? Given my actual struct contains 3 fields, that gets tedious as the owner now has to deconstruct the fields into locals in order to drop the immutable borrow, allowing the original vector to be mutated:
fn add_remove_constraint() {
let mut scenario = Scenario::<&str, bool, 3_usize>::new(&["A", "B", "C"]);
let mut constraints: Vec<Box<dyn IConstraint<bool>>> = Vec::new();
constraints.push(Box::new(SelectionCountConstraint {
nodes: [1, 2],
min: 1,
max: 2,
}));
scenario = Scenario {
constraints: &constraints,
..scenario
};
assert_eq!(1, scenario.get_constraints().len());
let nodes = scenario.nodes;
let selection_state = scenario.selection_state;
constraints.pop();
scenario = Scenario {
constraints: &constraints,
nodes,
selection_state,
};
assert_eq!(0, scenario.get_constraints().len());
}
I think you got it all wrong. As said in the comments, your add_constraint will never work, because you are referencing something you create in the same function in the first place (which will be dropped after the function scope expires).
You should own a container over those IConstraint trait, but inside you should have an &dyn IConstraint or Box<dyn IConstraint>.
Adding an item to them is trivial in that case:
pub trait IConstraint {
// members here
}
pub struct Scenario<'a> {
pub constraints: Vec<&'a dyn IConstraint>
}
impl<'a> Scenario<'a> {
pub fn add_constraint(&mut self, constraint: &'a dyn IConstraint) {
self.constraints.push(constraint);
}
}
Playground
This should solve your problem since references are Copy.

Mutable Arc in Rust

Earlier I had a Sync + Send trait SyncMessenger:
trait Messenger {
fn send_message(&self, user_id: UserId, text: &str);
}
trait SyncMessenger: Messenger + Sync + Send {}
It's implementation:
pub struct DiscordMessenger {
discord: Arc<Discord>, // (Discord is Sync and Send already)
}
impl Messenger for DiscordMessenger {
fn send_message(&self, user_id: UserId, text: &str) {
self.discord.send_message(user_id, text, false);
}
}
impl SyncMessenger for DiscordMessenger {}
And using it:
struct Bot {
messenger: Arc<SyncMessenger>,
}
impl Bot {
pub fn new() -> Bot {
Bot { messenger: Arc::new(DiscordMessenger::new()) }
}
fn messenger(&self) -> Arc<SyncMessenger> {
self.messenger.clone()
}
}
struct PingCommand {
fn fire(&mut self, bot: &mut Bot) {
bot.messenger().send_message(UserId(0), "Pong");
}
}
Everything worked fine. Now I want to implement TestMessenger which does not really send a message through a network but toggles a flag in Self instead:
#[cfg(test)]
struct TestMessenger {
pub message_sent: bool,
}
impl Messenger for TestMessenger {
fn send_message(&mut self, user_id: UserId, text: &str) { // we have `&mut self` here
self.message_sent = true;
}
}
So I need to change send_message(&self) to send_message(&mut self) everywhere (in traits and in implementations). I did that but after I can't compile my user code:
struct PingCommand {
fn fire(&mut self, bot: &mut Bot) {
bot.messenger().send_message(UserId(0), "Pong");
}
}
Gives error:
|
12 | let _ = bot.messenger().send_message(UserId(0),
| ^^^^^^^^^^^^^^^ cannot borrow as mutable
error: aborting due to previous error
I have found something that works but it looks very ugly to me (and requires unwrap() which I would like to avoid):
let _ = Arc::get_mut(&mut bot.messenger()).unwrap().send_message(UserId(0),
So the question here is how to do that as much simple as possible, without unwrap()s, static methods like Arc::get_mut? Why simple fn messenger(&self) -> Arc<SyncMessenger> is not possible to call mut methods?
You can use interior mutability to change data behind immutable references.
use std::cell::Cell;
struct TestMessenger {
pub message_sent: Cell<bool>,
}
impl Messenger for TestMessenger {
fn send_message(&self, user_id: UserId, text: &str) {
self.message_sent.set(true);
}
}
This struct is for single-treaded case. You'll need std::sync::Mutex instead of Cell to have Sync for TestMessenger.
Note that trait methods implemented should be strictly checked for compliance: send_message(&mut self, user_id: UserId, text: &str) is not compliant with send_message(&self, user_id: UserId, text: &str) due to the former's mutable reference to self, and the compiler would eventually complain.
Therefore, interior mutability is required here, so that state changes may happen behind an immutable reference. In this case, since you're dealing with other thread-safe components, you may consider using the thread-safe AtomicBool.
use std::sync::atomic::AtomicBool;
#[cfg(test)]
struct TestMessenger {
pub message_sent: AtomicBool,
}
impl Messenger for TestMessenger {
fn send_message(&self, user_id: UserId, text: &str) { // we have `&mut self` here
self.message_sent.store(true, Ordering::AcqRel);
}
}

Resources