Mutable Arc in Rust - 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);
}
}

Related

Since dyn don't like GATs at all, how can I use generics to handle this case with multiple mods Trait?

Given:
pub struct Needed {
pub repository_commands: Arc<dyn Trait>,
// and similar others...
}
and Trait:
pub trait Trait: Send + Sync + Player + Shirt {}
impl<T: Player + Shirt> Trait for T {}
#[async_trait::async_trait]
pub trait PlayerCreateTrait {
//...
}
#[async_trait::async_trait]
pub trait Player: Send + Sync {
type PlayerCreate<'input>: Send + PlayerCreateTrait;
async fn player_create_start<'input>(
&self,
input: &'input PlayerInput,
) -> Result<Self::PlayerCreate<'input>, String>;
//...
}
#[async_trait::async_trait]
pub trait Shirt: Send + Sync {
//...
}
Right now I have 200+ Handler structs all equals, one for each command of my application and all of them are like this:
pub struct Handler {
needs: Arc<Needed>,
}
Each of them has a different handle() method (based on which command is). And each of them is in a separate file (mod).
This is for example for create_player:
pub struct Handler {
needs: Arc<Needed>,
}
impl Handler {
pub async fn handle(&self, input: &PlayerCreateInput) -> Result<DomainPlayerCreated> {
// create_player
}
}
This is for update_player:
pub struct Handler {
needs: Arc<Needed>,
}
impl Handler {
pub async fn handle(&self, input: &PlayerUpdateInput) -> Result<DomainPlayerUpdated> {
// update_player
}
}
This is for team_engage:
pub struct Handler {
needs: Arc<Needed>,
}
impl Handler {
pub async fn handle(&self, team_id: String, player_ids: Vec<String>) -> Result<DomainTeamEngaged> {
// team_engage
}
}
and so on...
I asked for help (for another issue) and a great and kind person posted me an amazing example.
But in this example there are many news for me, one of them are the associated types.
And I just found out that GATs (generics associated types) are not liked by dyn at all (https://www.rustexplorer.com/b/ama9uo):
error[E0191]: the value of the associated type `PlayerCreate` (from trait `Player`) must be specified
--> src/main.rs:160:42
|
142 | type PlayerCreate<'input>: Send + PlayerCreateTrait;
| --------------------------------------------------- `PlayerCreate` defined here
...
160 | pub repository_commands: Arc<dyn Trait>,
| ^^^^^ help: specify the associated type: `Trait<PlayerCreate = Type>`
So the great user suggested me to use generics to work-around this problem, going from:
// in this example `Needed` struct is not used
pub struct Handler {
pub repository_commands: Arc<dyn Trait>,
}
impl Handler {
pub fn new(repository_commands: Arc<dyn Trait>) -> Self {
Self {
repository_commands,
}
}
pub async fn handle(&self, input: &PlayerInput) -> Result<DomainPlayer, String> {
// ...
}
}
to this (you can interact with the code here: https://www.rustexplorer.com/b/e0d6mm)
struct HandlerInner<C> {
repository_commands: C,
}
#[async_trait::async_trait]
trait ErasedHandler {
async fn handle(&self, input: &PlayerInput) -> Result<DomainPlayer, String>;
}
#[async_trait::async_trait]
impl<C: Send + Sync + Trait> ErasedHandler for HandlerInner<C> {
async fn handle(&self, input: &PlayerInput) -> Result<DomainPlayer, String> {
// ...
}
}
pub struct Handler(Arc<dyn ErasedHandler>);
impl Handler {
pub fn new<C: 'static + Trait>(repository_commands: C) -> Self {
Self(Arc::new(HandlerInner {
repository_commands,
}))
}
pub async fn handle(&self, input: &PlayerInput) -> Result<DomainPlayer, String> {
self.0.handle(input).await
}
}
but I cannot understand how to do this in my case: the complete and interactive code is on this playground here.
As you can see there are many mods there:
pub mod command {
pub mod player {
//...
}
pub mod shirt {
//...
}
pub mod team {
//...
}
}
is there a "simpler" way to avoid ErasedHandler and all that?
Since I have 200+ equals handlers (one for each command) altough with different handle method, maybe using generics is a great solution, but how in this case?

Proper way to implement simple collection in rust [duplicate]

This question already has answers here:
Why can't I store a value and a reference to that value in the same struct?
(4 answers)
Closed 6 months ago.
I'm trying to create a simple collection:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=361258962c9a25b953aab2a9e4999cc9
use std::collections::HashMap;
pub struct User {
pub id: u32,
pub name: String,
}
pub struct UsersIndex<'a> {
list: Vec<User>,
index: HashMap<u32, &'a User>,
}
impl UsersIndex<'_> {
pub fn new() -> Self {
UsersIndex {
list: Vec::new(),
index: HashMap::new(),
}
}
pub fn add(&mut self, user: User) {
self.list.push(user);
self.index.insert(user.id, &user);
}
pub fn get(&self, id: u32) -> Option<&&User> {
self.index.get(&id)
}
}
but can not fix the errors:
use of moved value: user
user does not live long enough
As I understand I have to take ownership of User, but google doesn't help me how to do it.
Rust says that I need to implement the Copy trait, but User contains a field of type String.
The issue with this code is the following:
pub fn add(&mut self, user: User) {
self.list.push(user); // Here, you move user to the list. The list owns user
self.index.insert(user.id, &user); // Then, you create a reference of a moved value
}
So, in your UserIndex struct, you want to store values and references of these values. These are called self-referential structs. With the ownership rules of Rust, you need to use unsafe Rust code to achieve this. If I were you, I'd think of a different way of implementing your collection following the Rust conventions. For example, you could do something like this:
use std::collections::HashMap;
pub struct User {
pub id: u32,
pub name: String,
}
pub struct UsersIndex {
index: HashMap<u32, User>, // I only use the HashMap. The HashMap owns the User structs
}
impl UsersIndex {
pub fn new() -> Self {
UsersIndex {
index: HashMap::new(),
}
}
pub fn add(&mut self, user: User) {
self.index.insert(user.id, user); // user is moved to the HashMap
}
pub fn get(&self, id: u32) -> Option<&User> { // Instead of a nested reference, we get a regular reference
self.index.get(&id)
}
}
fn main() {
let user = User {
id: 42,
name: "test".to_string(),
};
let mut index = UsersIndex::new();
index.add(user);
match index.get(42) {
Some(usr) => println!("{}", usr.name),
_ => println!("Not Found"),
}
}
Here you can find a playground with this implementation.
EDIT
If you need different HashMaps for the same User structs depending on the key used, you can use Rc smart pointers. They allow you to create more than one pointer that owns the same struct. It would look more or less like this:
use std::rc::Rc;
use std::collections::HashMap;
pub struct User {
pub id: u32,
pub name: String,
}
pub struct UsersIndex {
index: HashMap<u32, Rc<User>>, // Keys will be the user indeces
name: HashMap<String, Rc<User>>, // Keys will be the user names
}
impl UsersIndex {
pub fn new() -> Self {
UsersIndex {
index: HashMap::new(),
name: HashMap::new()
}
}
pub fn add(&mut self, user: User) {
// user will be moved, so we copy the keys before that:
let user_id = user.id;
let user_name = user.name.clone();
let user_rc = Rc::new(user); // We create the Rc pointer; user is moved to user_rc
self.index.insert(user_id, user_rc.clone()); // Rc pointers can be cloned
self.name.insert(user_name, user_rc); // user_rc is moved to the self.name HashMap
}
pub fn get(&self, id: u32) -> Option<Rc<User>> {
match self.index.get(&id) {
Some(user) => Some(user.clone()),
None => None
}
}
}
fn main() {
let user = User {
id: 42,
name: "test".to_string(),
};
let mut index = UsersIndex::new();
index.add(user);
match index.get(42) {
Some(usr) => println!("{}", usr.name),
_ => println!("Not Found"),
}
}
Here you can find a playground with this new implementation.
Again, if you also need the User structs to be mutable, then you'll probably need to use an Rc<RefCell<User>> (link here).
Hope you find this useful!

Add an element to a mutable vector list in Rust

Here is a link to a playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=1e82dcd3d4b7d8af89c5c00597d2d938
I am a newbie learning rust and trying to simply update a mutable vector on a struct.
struct Friend<'a> {
name: &'a str
}
impl <'a> Friend<'a> {
fn new(name: &'a str) -> Self { Self { name } }
}
struct FriendsList<'a> {
name: &'a str,
friends: Vec<Friend<'a>>
}
impl <'a> FriendsList<'a> {
fn new(name: &'a str, friends: Vec<Friend<'a>>) -> Self { Self { name, friends } }
fn add_new_friend(&self, friend: Friend) {
// how to make this work?
todo!()
// self.friends.push(friend)
}
}
fn main() {
let friends_list = FriendsList::new("George",
vec![
Friend::new("bob"),
Friend::new("bobby"),
Friend::new("bobbo")
]
);
}
specifically how do I make this fn add_new_friend(&self, friend: Friend) method work? That is, push a new element to field friends on the FriendsList struct. Is there a more idiomatic approach? When I try making things mutable, I get a whole bunch of errors I am not sure how to fix...
You have to borrow self mutably:
impl <'a> FriendsList<'a> {
// [...]
fn add_new_friend(&mut self, friend: Friend<'a>) {
self.friends.push(friend)
}
}

How to specify a Rust struct field must satisfy a trait when the struct has async methods?

Creating an authentication server.
I want a PGUserRepo struct, which implements a UserRepo trait async fn create.
The PGUserRepo should have a field that implements the Hasher trait.
However when I try to restrict the PGUserRepo field to be a dyn Hasher I get the error
"the trait std::marker::Send is not implemented for `(dyn domain::hasher::Hasher + 'static)".
If I make the PGUserRepo field the concrete implementing type, ArgonHasher, no error. But I don't want the PGUserRepo to care about what kind of Hasher was given to it, just that it implements the Hasher trait.
I have tried wrapping the hasher field in various combinations of Box, Arc, and Mutex, but I do not understand the root of why calling it an ArgonHasher is fine but saying it is some implementer of Hasher is not.
Code, collapsed to one file for convenience:
pub trait Hasher {
fn hash(&self, password: String) -> Result<String, HasherError>;
}
pub struct ArgonHasher {}
impl Hasher for ArgonHasher {
fn hash(&self, password: String) -> Result<String, HasherError> {
let result = argon2id13::pwhash(
&password.as_bytes(),
argon2id13::OPSLIMIT_INTERACTIVE,
argon2id13::MEMLIMIT_INTERACTIVE,
);
match result {
Ok(hashed_password_result) => match std::str::from_utf8(&hashed_password_result.0) {
Ok(hashed_password_utf8) => Ok(String::from(hashed_password_utf8)),
Err(e) => Err(HasherError::from(e)),
},
Err(e) => Err(HasherError::from(e)),
}
}
}
impl From<()> for HasherError {
fn from(_: ()) -> Self {
HasherError::HasherError {
message: String::from(""),
}
}
}
impl From<std::str::Utf8Error> for HasherError {
fn from(cause: std::str::Utf8Error) -> Self {
HasherError::HasherError {
message: format!("{}", cause),
}
}
}
#[async_trait]
pub trait UserRepo {
async fn create(&self, user: User) -> Result<User, UserRepoError>;
}
#[derive(Debug)]
pub enum UserRepoError {
UserAlreadyExistsError { field: String, value: String },
UserRepoError { message: String },
}
impl fmt::Display for UserRepoError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *&self {
UserRepoError::UserAlreadyExistsError { field, value } => {
f.write_str(&format!("User with {}={} already exists", field, value))
}
UserRepoError::UserRepoError { message } => f.write_str(&message),
}
}
}
pub struct PGUserRepo {
conn_pool: PgPool,
hasher: &'static dyn Hasher,
}
impl PGUserRepo {
pub fn new(conn_pool: PgPool, hasher: &'static dyn Hasher) -> Self {
PGUserRepo { conn_pool, hasher }
}
}
#[async_trait]
impl UserRepo for PGUserRepo {
async fn create(&self, user: User) -> Result<User, UserRepoError> {
# Compiler error is on this function
# hasher is not even used in this function yet, it's just a field on PGuserRepo
}
Bonus: I don't really need the Hasher trait hash to have a reference to self but without it I get "error[E0038]: the trait domain::hasher::Hasher cannot be made into an object".
The marker trait Send is used to indicate when a type is safe to be transferred between threads. It is implemented by default when the compiler deems it to be safe. However, you have a trait object hasher that has no constraint on if it can be shared between threads safely.
This comes up here because async code is usually handled via multiple threads and the async_trait enforces that.
The fix is to indicate that only Hashers that can be shared between threads are allowed. You can do this by using the Sync trait:
pub struct PGUserRepo {
conn_pool: PgPool,
hasher: &'static (dyn Hasher + Sync),
}
See Understanding the Send trait to learn more about the difference between Sync and Send and their purpose.

items from traits can only be used if the trait is implemented and in scope

I tried to implement the Observer pattern from Heads-up Design Patterns, which was originally written in Java:
use std::cell::RefCell;
use std::rc::Rc;
use std::borrow::BorrowMut;
trait Subject {
fn registerObserver(&mut self, observer: Rc<RefCell<Observer>>);
fn removeObserver(&mut self, observer: Rc<RefCell<Observer>>);
fn notifyObserver(&self, observer: Rc<RefCell<Observer>>);
}
trait Observer {
fn update(&mut self, data: f32);
}
struct Teacher {
observers: Vec<Rc<RefCell<Observer>>>,
data: f32,
}
impl Teacher {
pub fn print(&self) {
println!("teacher = {:}", self.data);
}
}
impl Subject for Teacher {
fn registerObserver(&mut self, observer: Rc<RefCell<Observer>>) {
self.observers.push(observer);
}
fn removeObserver(&mut self, observer: Rc<RefCell<Observer>>) {
println!("Teacher.removeObserver(...) not implemented yet...")
}
fn notifyObserver(&self, observer: Rc<RefCell<Observer>>) {
for observer in self.observers {
let mut loc_obs = observer.borrow_mut();
loc_obs.update(self.data);
}
}
}
struct Student {
data: f32,
}
impl Student {
pub fn print(&self) {
println!("student = {:}", self.data);
}
}
impl Observer for Student {
fn update(&mut self, data: f32) {
self.data = data;
}
}
fn main() {
let mut teacher = Teacher {
observers: Vec::new(),
data: 42.,
};
teacher.print();
}
Playground
The compiler tells me
error[E0599]: no method named `update` found for type `&mut std::rc::Rc<std::cell::RefCell<Observer + 'static>>` in the current scope
--> src/main.rs:35:21
|
35 | loc_obs.update(self.data);
| ^^^^^^
|
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item `update`, perhaps you need to implement it:
candidate #1: `Observer`
Where is my error?
use std::borrow::BorrowMut;
You've brought in the trait BorrowMut, which defines the trait method BorrowMut::borrow_mut, shadowing the inherent method RefCell::borrow_mut. You can tell this because your type is not what you expect:
for type &mut std::rc::Rc<std::cell::RefCell<Observer + 'static>>
The simplest fix is to remove that import. You can also disambiguate between them.
You then have further issues around trying to take ownership of a borrowed value and lots of non-idiomatic names that create boatloads of warnings. You should address all of those.

Resources