Actix and Diesel - passing a closure utilizing QueryDsl? - rust

I'm using Actix and Diesel. The way I set it up is that I have a DbExecutor - an async worker which takes messages and returns the results of the queries they represent, like so:
#[derive(Message)]
#[rtype(result = "Result<User>")]
pub struct RetrieveUser {
pub uid: i64,
}
impl Handler<RetrieveUser> for DbExecutor {
// ...
fn handle(&mut self, msg: InsertFile, _: &mut Self::Context) -> Self::Result {
use crate::schema::users::dsl::*;
// ...
Ok(users.filter(uid.eq(msg.uid)).execute(connection))
}
}
fn my_route_handler() {
db_executor.send(RetrieveUser{ uid: 123 });
//...
}
However, there is a table which doesn't fit neatly into these simple queries, and I would like to specify the filters from the side of the message sender. I was thinking I could send a message containing a closure which takes the users object, and then execute it on the side of the DbExecutor, returning the results:
fn my_ideal_route_handler(){
db_executor.send(RetrieveUsers { predicate: |users| users.filter(uid.eq(123)) });
}
However, I am stuck, seeing as all Messages have to implement Copy, and the Diesel types are confusing - I am not sure how to specify the type I need generically enough, while getting it to compile, eg.:
// FAILS
#[derive(Message)]
#[rtype(result = "Result<Vec<User>>")]
pub struct RetrieveUsers {
pub predicate: dyn FnOnce(dyn QueryDsl) -> dyn RunQueryDsl<PgConnection>,
}
I am also not sure whether this approach is even sensible at all, so I am open to other suggestions which would:
allow me to query the table dynamically
still keep most of the database handling separate and not all across the project as if I were passing the plain database connection around
(ideally) utilize concurrent access to the database

Related

no method named "query_one" found for struct "PooledConnection"

I'm trying to make a method in a struct that interacts with a tokio_postgres pool. The code looks something like this:
pub struct DatabaseHandler<M> where M: ManageConnection {
pool: Pool<M>
}
impl<M> DatabaseHandler<M> where M: ManageConnection {
pub async fn exists(&self, contract_address: &str) -> Result<bool, DatabaseError<M::Error>> {
let conn = self.pool.get().await?;
let result = conn.query_one(
"SELECT contract_address FROM contracts WHERE contract_address = $1",
&[
&contract_address.trim_start_matches("0x")
]
).await?;
Ok(result.is_some())
}
}
The type of pool is Pool<PostgresConnectionManager<NoTls>>, but I'm wanting to use generics here to accept other possible types as well (for example, one that uses TLS for connections).
The problem with this implementation is when using the query_one method (as well as other methods like transaction), I get this error:
no method named 'query_one' found for struct 'PooledConnection<'_, M>' in the current scope E0599 method not found in 'PooledConnection<'_, M>'
I understand why I get this error, since those methods don't exist in the ManageConnection trait. What I'm struggling with is what trait to use for the generics for these methods to be used. I tried using ManageConnection + GenericClient, as well as just GenericClient, but had the same problem. It also appears that the methods in GenericClient are not public.

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 can I create a builder which allows non-consuming and consuming functions

I want to create a builder for a struct representing an analytics event. once the event is "sent" the builder should be consumed.
I read this primer:
https://doc.rust-lang.org/1.0.0/style/ownership/builders.html
so to allow simple chaining without reassignment (which might be required since there are many execution branches), my builder looks like this (simplified)
pub struct AnalyticsEvent {
}
impl AnalyticsEvent {
pub fn new() -> Self {
AnalyticsEvent { }
}
pub fn add_property(&mut self) -> &mut AnalyticsEvent {
self
}
// now I want the "send" to consume the event
pub fn send(self) {
/// ....
}
}
link to playground
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=fbe9e261a419608f2c592799f22ba9f9
You can't mix both in the same chain, since your non-consuming methods only return &mut T there's no way for self-consuming methods to be called on them.
So either keep the builder interface as-is and replace
event.add_property().send();
by
event.add_property();
event.send();
or change the builder interface to always work on owned objects, requiring the odd reassignment in some cases.
In the latter case you could mitigate the issue by adding convenience methods e.g. a map which would enclose the conditional situation:
event.add_property()
.add_property()
.map(|e| if condition {
e.add_property()
} else {
e
})
.add_property()
.send();

How can I determine if I have a unique Arc when it's dropped?

I've an Arc<Mutex<Thing>> field in a struct which is cloned many times. It is shared between concurrent threads. Drop::drop is called for each clone as it goes out of scope. Is there any way to determine when Drop::drop is called for the last (unique) Arc<Mutex<Thing>>?
It's clear that strong_count is subject to data races (I've seen them). So, you can't count on Arc::strong_count() == 1 (no pun intended).
I found that I couldn't use Arc::try_unwrap() due to a move issue.
Arc::is_unique() is private.
Other than keeping a Arc<AtomicUsize> field, which is incremented on clone and decremented on drop, is there any way to determine if a drop is for a unique Arc<Mutex<Thing>>?
Here's an MRE:
use std::sync::{Arc};
#[derive(Debug)]
enum Action {
One, Two, Three
}
// Thing trait which operates on an Action, which should be a enum, allowing for
// different action sets.
trait Thing<T> {
fn disconnected(&self);
fn action(&self, action: T);
}
// There are many instances of an ActionController.
// There may be zero or more clones of an instance.
// The final drop of the instances should call thing.disconnected()
// In a multi-core environment, the same instance may be running on multiple cores
// ActionController should not be generic.
#[derive(Clone)]
struct ActionController {
id: usize,
thing: Arc<dyn Thing<Action>>,
}
impl ActionController {
fn new(id: usize, thing: Box<dyn Thing<Action>>) -> Self {
Self { id, thing: Arc::from(thing) }
}
fn invoke(&self, action: Action) {
self.thing.action(action);
}
}
//
// To work around the drop issue, I've implemented Clone for ActionController which
// performs a fetch_add(1) on clone and a fetch_sub(1) on drop. This provides
// suficient information to call disconnected() -- but it just seems like there's
// got to be a better way.
impl Drop for ActionController {
fn drop(&mut self) {
// drop will be called for each clone of an Controller instance. When
// the unique instance is dropped, disconnected() must be called
self.thing.disconnected();
}
}
struct Controlled {}
impl Thing<Action> for Controlled {
fn disconnected(&self) { println!("disconnected")}
fn action(&self, action: Action) {println!("action: {:#?}", action)}
}
fn bad() {
let controlled = Controlled{};
let controlled = Box::new(controlled) as Box<dyn Thing<Action>>;
let controller = ActionController::new(1, controlled);
let clone = controller.clone();
controller.invoke(Action::One);
clone.invoke(Action::Two);
drop (controller);
clone.invoke(Action::Three);
}
fn main() {
bad();
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn incorrect() {
bad();
}
}
Arc::try_unwrap is probably the intended way to do this - is it possible to restructure your code to avoid the move issues you were running into?
Why do you want to know? If you have some extra cleanup code that needs to be executed before the Mutex<Thing> is dropped, maybe you could use an Arc<MyLockedThing> instead, where MyLockedThing is a struct containing a Mutex<Thing> that impls Drop to do the cleanup?
It seems like you want to be notified when the data inside the Arc is to be dropped. If so, this can be done by implementing Drop on the type "inside" the Arc.
Define a newtype:
struct ThingAction(Box<dyn Thing<Action>>);
impl Thing<Action> for ThingAction {
fn disconnected(&self) {
self.0.disconnected()
}
fn action(&self, action: Action) {
self.0.action(action)
}
}
And implement Drop:
impl Drop for ThingAction {
fn drop(&mut self) {
self.disconnected()
}
}
Then use the newtype:
#[derive(Clone)]
struct ActionController {
id: usize,
thing: Arc<ThingAction>,
}
impl ActionController {
fn new(id: usize, thing: Box<dyn Thing<Action>>) -> Self {
Self { id, thing: Arc::new(ThingAction(thing)) }
}
I don't think there's any perfect way to do this without stdlib support (go checkout out Arc::drop).
Weak::strong_count or Weak::upgrade is less subject to races so if you downgrade your Arc then drop it, if the weakref's strong count is 0 or trying to upgrade it fails you know the Arc is dead, but there is no guarantee the current thread killed it, two might have concurrently dropped the Arc at the same time before either had the time to check for the weakref's strong count.
I think the only bulletproof way would be to get notified by a Drop stored inside the Arc, that you're guaranteed is only called once.

Store a collection of heterogeneous types with generic type parameters in Rust

I'm trying to implement a basic ECS in Rust. I want a data structure storing, for each component, a storage of that particular component. Because some components are common while others are rare, I want different types of storage policies such as VecStorage<T> and HashMapStorage<T>.
As components are unknown to the game engine's ECS, I came up with:
trait AnyStorage: Debug {
fn new() -> Self
where
Self: Sized;
}
#[derive(Default, Debug)]
struct StorageMgr {
storages: HashMap<TypeId, Box<AnyStorage>>,
}
with VecStorage and HashMapStorage<T> implementing the AnyStorage trait. Since AnyStorage doesn't know T, I added one more trait implemented by both concrete storages: ComponentStorage<T>.
While I was able to register new components (i.e. add a new Box<AnyStorage> in StorageMgr's storages), I didn't find a way to insert components.
Here is the erroneous code:
pub fn add_component_to_storage<C: Component>(&mut self, component: C) {
let storage = self.storages.get_mut(&TypeId::of::<C>()).unwrap();
// storage is of type: &mut Box<AnyStorage + 'static>
println!("{:?}", storage); // Prints "VecStorage([])"
storage.insert(component); // This doesn't work
// This neither:
// let any_stor: &mut Any = storage;
// let storage = any_stor.downcast_ref::<ComponentStorage<C>>();
}
I know that my problem comes from the fact that storage's type is &mut Box<AnyStorage>; can I obtain the concrete VecStorage from it?
The whole point of doing all this is that I want components to be contiguous in memory and to have different storage for each component type. I can not resolve myself to use Box<Component>, or I don't see how.
I reduced my problem to a minimal code on Rust Playground.
I wasn't sure if something like this was possible but I've finally figured it out. There are a couple things to note as to why your posted example was failing.
Trait AnyStorage in your example did not implement ComponentStorage<T>, therefore because you were storing your "storage"s in a HashMap<TypeId, Box<AnyStorage>>, Rust could not guarantee that every stored type implemented ComponentStorage<T>::insert() because it only knew that they were AnyStorages.
If you did combine the two traits into one simply called Storage<T> and stored them in a HashMap<TypeId, Box<Storage<T>>, every version of Storage would have to store the same type because of the single T. Rust doesn't have a way to dynamically type the values of a map based on the TypeId of the key, as a solution like this would require. Also, you can't replace T with Any because Any isn't Sized, which Vec and all other storage types require. I'm guessing you knew all of this which is why you used two different traits in your original example.
The solution I ended up using stored the Storage<T>s as Anys in a HashMap<TypeId, Box<Any>>, and then I downcasted the Anys into Storage<T>s inside the implementation functions for StorageMgr. I've put a short example below, and a full version is on Rust Playground here
.
trait Component: Debug + Sized + Any {
type Storage: Storage<Self>;
}
trait Storage<T: Debug>: Debug + Any {
fn new() -> Self
where
Self: Sized;
fn insert(&mut self, value: T);
}
struct StorageMgr {
storages: HashMap<TypeId, Box<Any>>,
}
impl StorageMgr {
pub fn new() -> Self {
Self {
storages: HashMap::new(),
}
}
pub fn get_storage_mut<C: Component>(&mut self) -> &mut <C as Component>::Storage {
let type_id = TypeId::of::<C>();
// Add a storage if it doesn't exist yet
if !self.storages.contains_key(&type_id) {
let new_storage = <C as Component>::Storage::new();
self.storages.insert(type_id, Box::new(new_storage));
}
// Get the storage for this type
match self.storages.get_mut(&type_id) {
Some(probably_storage) => {
// Turn the Any into the storage for that type
match probably_storage.downcast_mut::<<C as Component>::Storage>() {
Some(storage) => storage,
None => unreachable!(), // <- you may want to do something less explosive here
}
}
None => unreachable!(),
}
}
}

Resources