First of all I'm new with Rust :-)
The problem:
I want to create a module called RestServer that contain the methods ( actix-web ) to add routes and start the server.
struct Route
{
url: String,
request: String,
handler: Box<dyn Fn(HttpRequest) -> HttpResponse>
}
impl PartialEq for Route {
fn eq(&self, other: &Self) -> bool {
self.url == other.url
}
}
impl Eq for Route {}
impl Hash for Route {
fn hash<H: Hasher>(&self, hasher: &mut H) {
self.url.hash(hasher);
}
}
this is the route structure, this structure containe the the route url, the request type ( GET, POST etc ) and hanlder is the function that have to catch the request and return a HTTPResponse
pub struct RestServer
{
scopes: HashMap<String, Rc<HashSet<Route>>>,
routes: HashSet<Route>,
host: String,
}
impl RestServer {
pub fn add_route(self, req: &str, funct: impl Fn(HttpRequest) -> HttpResponse + 'static,
route: &str, scope: Option<&str>) -> RestServer
{
let mut routes_end = self.routes;
let mut scopes_end = self.scopes;
let url = self.host;
let route = Route {
url: String::from(route),
request: String::from(req),
handler: Box::new(funct)
};
if let Some(x) = scope {
if let Some(y) = scopes_end.get(x) {
let mut cloned_y = Rc::clone(y);
cloned_y.insert(route);
scopes_end.insert(String::from(x), cloned_y);
}else {
let mut hash_scopes = HashSet::new();
hash_scopes.insert(route);
scopes_end.insert(String::from(x), Rc::new(hash_scopes));
}
} else {
routes_end.insert(route);
}
RestServer {
scopes: scopes_end,
routes: routes_end,
host: String::from(url)
}
}
the latest code is the implementation of RestServer.
The most important part is the add_route function, this function receive as paramente the route that is a string, the function handler, the request string and the scope.
First i create the route object.
I check if the scope exist into the HashMap, if yes i have to take the actual scope and update the HashSet.
When i build the code i get the following error
error[E0596]: cannot borrow data in an `Rc` as mutable
--> interface/src/rest/mod.rs:60:17
|
60 | cloned_y.insert(route);
| ^^^^^^^^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not
implemented for `std::rc::Rc<std::collections::HashSet<rest::Route>>`
I know that the compiler give me some help but honestly i have no idea how to do that or if i can do with some easy solution.
After a large search in google i found a solution in RefCell, but is not so much clear
Thanks in advance for your help
You cannot borrow a reference-counting pointer as mutable; this is because one of the guarantees it provides is only possible if the structure is read-only.
You can, however, get around it, but it will require some signature changes.
Enter interior mutability
Interior mutability is a concept you may know from other programming languages in the form of mutexes, atomics and synchronization primitives. In practice, those structures allow you to temporarily guarantee that you are the only accessor of a given variable.
In Rust, this is particularly good, as it allows us to extract a mutable reference to an interior member from a structure that only requires immutable references to itself to function. Perfect to fit in Rc.
Depending on what you need for your needs, you will find the Cell and RefCell structures to be exactly what you need for this. These are not thread-safe, but then again, neither is Rc so it's not exactly a deal-breaker.
In practice, it works very simply:
let data = Rc::new(RefCell::new(true));
{
let mut reference = data.borrow_mut();
*reference = false;
}
println!("{:?}", data);
playground
(If you ever want the threaded versions, Arc replaces Rc and Mutex or RwLock replaces Cell/RefCell)
Related
I am new to rust, and having trouble figuring out the correct design pattern for what I am trying to do. In my program, there are Position structs, which reference a single coordinate system that they "belong" to. I have understood that rust must therefore be able to guarantee that coordinate_system reference outlives the Position. So far so good.
The issue is in a function such as transform_to_parent, where I want to create a new Position which is dependent on the lifetime of the exact coordinate_system that it later references, and not on the lifetime of the self parameter through which it accesses the coordinate system. This seems to be the only thing that lifetime specifiers would allow.
If I add a lifetime specifier to the following code, it compiles, but understandably complains when I let the old Position that I transformed from goes out of scope.
pub struct Position<'a> {
// Position data omitted
coordinate_system: &'a CoordinateSystem<'a>,
}
impl<'a> Position<'a> {
fn transform_to_parent<'b>(self: &'b Self) -> Option<Position<'b>> {
Some(Position {
coordinate_system: self.coordinate_system.origin?.coordinate_system
})
}
}
pub struct CoordinateSystem<'a> {
origin: Option<&'a Position<'a>>,
}
// Test case
fn main() {
// child_system is the child coordinate system of root_system, and has its origin at child_origin
let root_system = CoordinateSystem { origin: None };
let child_origin = Position { coordinate_system: &root_system };
let child_system = CoordinateSystem { origin: Some(&child_origin) };
let mut p2 = Position { coordinate_system: &child_system };
{
let p1 = Position { coordinate_system: &child_system };
if let Some(x) = p1.transform_to_parent() { // Error: "borrowed value does not live long enough"
p2 = x;
}
}
// No-op, just pretend to use p2 again, after p1 has gone out of scope
p2;
}
Is it possible for Rust to bind the lifetime of the function result to the lifetime of self.coordinate_system.get_origin()?.coordinate_system (i.e. the parent coordinate system), instead of the self? Is there a correct design pattern for something like this?
I assume that a ref-counting system would work, but I think that would be bad design, because there is clear ownership of the coordinate systems, and because the lifetime information should be deducible somehow.
Just use the 'a lifetime from the field:
impl<'a> Position<'a> {
fn transform_to_parent(&self) -> Option<Position<'a>> {
Some(Position {
coordinate_system: self.coordinate_system.origin?.coordinate_system
})
}
}
I have this entrypoint where ctx is passed by a parent:
pub mod instructions;
#[program]
pub mod solana_anchor_coinflip {
use super::*;
pub fn flip(ctx: Context<Play>, data: FlipArgs) -> Result<()> {
instructions::play::play(ctx, data)
}
}
Then, instructions/play.rs has this:
pub fn play(ctx: Context<Play>, data: FlipArgs) -> Result<()> {
ctx.accounts.game.flip(ctx, data) // <== cannot move out of `ctx` because it is borrowed
}
#[derive(Accounts)]
pub struct Play<'info> {
#[account(mut)]
pub game: Account<'info, Game>,
pub player: Signer<'info>,
}
and ctx is finally passed to game.rs:
impl Game {
pub fn flip(&mut self, ctx: Context<Play>, data: FlipArgs) -> Result<()> {
self.charge_fee(ctx);
match data.heads_or_tails {
true => self.play_heads(ctx), // <== use of moved value: `ctx`
false => self.play_tails(ctx),
}
}
fn charge_fee(&self, ctx: Context<Play>) -> Result<()> {
let player = &ctx.accounts.player;
// ...
Ok(())
}
}
How to correctly borrow ctx from lib.rs > play.rs > game.rs?
As said in the comments, you are not borrowing ctx, you're just moving it. See the relevant documentation to understand the differences, alongside with examples to illustrate that.
If you read through that, you will understand why you just need to change the signature of your functions:
// in instructions/play.rs
pub fn play(ctx: &Context<Play>, data: FlipArgs) -> Result<()> { // <-- takes a `&Context<Play>`
ctx.accounts.game.flip(ctx, data) // and passes the borrow
}
// game.rs
impl Game {
pub fn flip(&mut self, ctx: &Context<Play>, data: FlipArgs) -> Result<()> { // <-- takes a &Context<Play>
self.charge_fee(ctx); // <-- here you pass the borrow
// also, unused `Result`, which is _bad_
if data.heads_or_tails { // an `if` statement is a `match` over a `bool`
self.play_heads(ctx) // <-- here you pass the borrow too, which is fine, because `&T: Copy`
} else {
self.play_tails(ctx) // <-- same as above
}
}
fn charge_fee(&self, ctx: &Context<Play>) -> Result<()> { // <-- takes a `&Context<Play>`
let player = &ctx.accounts.player;
// ...
Ok(())
}
}
However, despite this patch, there is a chance that you need to refactor your code anyways after understanding borrow, for multiple motives:
Given the context of your question, it's impossible to tell if play should take borrow to a Context<Play>, or an owned value, because both could work (in the second case, you would have to pass a borrow to the method call, ie ctx.accounts.game.flip(&ctx, data).
You seem to pass data as an owned value all along, just like you do with ctx, but since it was a mistake with ctx, it might be for data too (and for many other parts of your code).
I'm not sure whether the current version will compile anyways do the flip requiring &mut self, that is, it needs a mutable borrow to ctx.accounts.game in the play function. However, that would also require a mutable borrow of ctx (unless it doesn't, but that's a bit too advanced: learn about borrows before learning about interior mutability) for the duration of the call, which would invalidate any borrow to be passed as an argument.
As an advice, I would suggest you to wrap your head around Rust's core concepts (which can be efficiently done by reading the Rust Book) before designing the architecture of a complex application, because Rust has some very peculiar patterns, even if you are used other programming languages. Otherwise, you will keep fighting against the compiler trying to adapt the code you had in mind when you still did not fully understand the borrowing and ownership in Rust to something that works.
I have two structs:
Client, which stores a callback and calls it in response to receiving new data. As an example, you can think of this as a websocket client, and we want to provide a hook for incoming messages.
BusinessLogic, which wants to hold a Client initialized with a callback that will update its local value in response to changes that the Client sees.
After following compiler hints, I arrived at the following minimal example:
Rust playground link
use rand::Rng;
struct Client<'cb> {
callback: Box<dyn FnMut(i64) + 'cb>,
}
impl<'cb> Client<'cb> {
fn do_thing(&mut self) {
// does stuff
let value = self._get_new_value();
// does more stuff
(self.callback)(value);
// does even more stuff
}
fn _get_new_value(&self) -> i64 {
let mut rng = rand::thread_rng();
rng.gen()
}
}
struct BusinessLogic<'cb> {
value: Option<i64>,
client: Option<Client<'cb>>,
}
impl<'cb> BusinessLogic<'cb> {
fn new() -> Self {
Self {
value: None,
client: None,
}
}
fn subscribe(&'cb mut self) {
self.client = Some(Client {
callback: Box::new(|value| {
self.value = Some(value);
})
})
}
}
fn main() {
let mut bl = BusinessLogic::new();
bl.subscribe();
println!("Hello, world!");
}
Problem is, I am still getting the following compiler error:
Compiling playground v0.0.1 (/playground)
error[E0597]: `bl` does not live long enough
--> src/main.rs:51:5
|
51 | bl.subscribe();
| ^^^^^^^^^^^^^^ borrowed value does not live long enough
...
54 | }
| -
| |
| `bl` dropped here while still borrowed
| borrow might be used here, when `bl` is dropped and runs the destructor for type `BusinessLogic<'_>`
For more information about this error, try `rustc --explain E0597`.
error: could not compile `playground` due to previous error
I understand why I'm seeing this error: the call to subscribe uses a borrow of bl with a lifetime of 'cb, which is not necessarily contained within the scope of main(). However, I don't see how to resolve this issue. Won't I always need to provide a lifetime for the callback stored in Client, which will end up bleeding through my code in the form of 'cb lifetime annotations?
More generally, I'm interested in understanding what is the canonical way of solving this callback/hook problem in Rust. I'm open to designs different from the one I have proposed, and if there are relevant performance concerns for various options, that would be useful to know also.
What you've created is a self-referential structure, which is problematic and not really expressible with references and lifetime annotations. See: Why can't I store a value and a reference to that value in the same struct? for the potential problems and workarounds. Its an issue here because you want to be able to mutate the BusinessLogic in the callback, but since it holds the Client, you can mutate the callback while its running, which is no good.
I would instead suggest that the callback has full ownership of the BusinessLogic which does not directly reference the Client:
use rand::Rng;
struct Client {
callback: Box<dyn FnMut(i64)>,
}
impl Client {
fn do_thing(&mut self) {
let value = rand::thread_rng().gen();
(self.callback)(value);
}
}
struct BusinessLogic {
value: Option<i64>,
}
fn main() {
let mut bl = BusinessLogic {
value: None
};
let mut client = Client {
callback: Box::new(move |value| {
bl.value = Some(value);
})
};
client.do_thing();
println!("Hello, world!");
}
if you need the subscriber to have backwards communication to the Client, you can pass an additional parameter that the callback can mutate, or simply do it via return value
if you need more complicated communication from the Client to the callback, either send a Message enum as the argument, or make the callback a custom trait instead of just FnMut with additional methods
if you need a single BusinessLogic to operate from multiple Clients use Arc+Mutex to allow shared ownership
Running into an ownership issue when attempting to reference multiple values from a HashMap in a struct as parameters in a function call. Here is a PoC of the issue.
use std::collections::HashMap;
struct Resource {
map: HashMap<String, String>,
}
impl Resource {
pub fn new() -> Self {
Resource {
map: HashMap::new(),
}
}
pub fn load(&mut self, key: String) -> &mut String {
self.map.get_mut(&key).unwrap()
}
}
fn main() {
// Initialize struct containing a HashMap.
let mut res = Resource {
map: HashMap::new(),
};
res.map.insert("Item1".to_string(), "Value1".to_string());
res.map.insert("Item2".to_string(), "Value2".to_string());
// This compiles and runs.
let mut value1 = res.load("Item1".to_string());
single_parameter(value1);
let mut value2 = res.load("Item2".to_string());
single_parameter(value2);
// This has ownership issues.
// multi_parameter(value1, value2);
}
fn single_parameter(value: &String) {
println!("{}", *value);
}
fn multi_parameter(value1: &mut String, value2: &mut String) {
println!("{}", *value1);
println!("{}", *value2);
}
Uncommenting multi_parameter results in the following error:
28 | let mut value1 = res.load("Item1".to_string());
| --- first mutable borrow occurs here
29 | single_parameter(value1);
30 | let mut value2 = res.load("Item2".to_string());
| ^^^ second mutable borrow occurs here
...
34 | multi_parameter(value1, value2);
| ------ first borrow later used here
It would technically be possible for me to break up the function calls (using the single_parameter function approach), but it would be more convenient to pass the
variables to a single function call.
For additional context, the actual program where I'm encountering this issue is an SDL2 game where I'm attempting to pass multiple textures into a single function call to be drawn, where the texture data may be modified within the function.
This is currently not possible, without resorting to unsafe code or interior mutability at least. There is no way for the compiler to know if two calls to load will yield mutable references to different data as it cannot always infer the value of the key. In theory, mutably borrowing both res.map["Item1"] and res.map["Item2"] would be fine as they would refer to different values in the map, but there is no way for the compiler to know this at compile time.
The easiest way to do this, as already mentioned, is to use a structure that allows interior mutability, like RefCell, which typically enforces the memory safety rules at run-time before returning a borrow of the wrapped value. You can also work around the borrow checker in this case by dealing with mut pointers in unsafe code:
pub fn load_many<'a, const N: usize>(&'a mut self, keys: [&str; N]) -> [&'a mut String; N] {
// TODO: Assert that keys are distinct, so that we don't return
// multiple references to the same value
keys.map(|key| self.load(key) as *mut _)
.map(|ptr| unsafe { &mut *ptr })
}
Rust Playground
The TODO is important, as this assertion is the only way to ensure that the safety invariant of only having one mutable reference to any value at any time is upheld.
It is, however, almost always better (and easier) to use a known safe interior mutation abstraction like RefCell rather than writing your own unsafe code.
I want my method of struct to perform in a synchronized way. I wanted to do this by using Mutex (Playground):
use std::sync::Mutex;
use std::collections::BTreeMap;
pub struct A {
map: BTreeMap<String, String>,
mutex: Mutex<()>,
}
impl A {
pub fn new() -> A {
A {
map: BTreeMap::new(),
mutex: Mutex::new(()),
}
}
}
impl A {
fn synchronized_call(&mut self) {
let mutex_guard_res = self.mutex.try_lock();
if mutex_guard_res.is_err() {
return
}
let mut _mutex_guard = mutex_guard_res.unwrap(); // safe because of check above
let mut lambda = |text: String| {
let _ = self.map.insert("hello".to_owned(),
"d".to_owned());
};
lambda("dd".to_owned());
}
}
Error message:
error[E0500]: closure requires unique access to `self` but `self.mutex` is already borrowed
--> <anon>:23:26
|
18 | let mutex_guard_res = self.mutex.try_lock();
| ---------- borrow occurs here
...
23 | let mut lambda = |text: String| {
| ^^^^^^^^^^^^^^ closure construction occurs here
24 | if let Some(m) = self.map.get(&text) {
| ---- borrow occurs due to use of `self` in closure
...
31 | }
| - borrow ends here
As I understand when we borrow anything from the struct we are unable to use other struct's fields till our borrow is finished. But how can I do method synchronization then?
The closure needs a mutable reference to the self.map in order to insert something into it. But closure capturing works with whole bindings only. This means, that if you say self.map, the closure attempts to capture self, not self.map. And self can't be mutably borrowed/captured, because parts of self are already immutably borrowed.
We can solve this closure-capturing problem by introducing a new binding for the map alone such that the closure is able to capture it (Playground):
let mm = &mut self.map;
let mut lambda = |text: String| {
let _ = mm.insert("hello".to_owned(), text);
};
lambda("dd".to_owned());
However, there is something you overlooked: since synchronized_call() accepts &mut self, you don't need the mutex! Why? Mutable references are also called exclusive references, because the compiler can assure at compile time that there is only one such mutable reference at any given time.
Therefore you statically know, that there is at most one instance of synchronized_call() running on one specific object at any given time, if the function is not recursive (calls itself).
If you have mutable access to a mutex, you know that the mutex is unlocked. See the Mutex::get_mut() method for more explanation. Isn't that amazing?
Rust mutexes do not work the way you are trying to use them. In Rust, a mutex protects specific data relying on the borrow-checking mechanism used elsewhere in the language. As a consequence, declaring a field Mutex<()> doesn't make sense, because it is protecting read-write access to the () unit object that has no values to mutate.
As Lukas explained, your call_synchronized as declared doesn't need to do synchronization because its signature already requests an exclusive (mutable) reference to self, which prevents it from being invoked from multiple threads on the same object. In other words, you need to change the signature of call_synchronized because the current one does not match the functionality it is intended to provide.
call_synchronized needs to accept a shared reference to self, which will signal to Rust that it can be called from multiple threads in the first place. Inside call_synchronized a call to Mutex::lock will simultaneously lock the mutex and provide a mutable reference to the underlying data, carefully scoped so that the lock is held for the duration of the reference:
use std::sync::Mutex;
use std::collections::BTreeMap;
pub struct A {
synced_map: Mutex<BTreeMap<String, String>>,
}
impl A {
pub fn new() -> A {
A {
synced_map: Mutex::new(BTreeMap::new()),
}
}
}
impl A {
fn synchronized_call(&self) {
let mut map = self.synced_map.lock().unwrap();
// omitting the lambda for brevity, but it would also work
// (as long as it refers to map rather than self.map)
map.insert("hello".to_owned(), "d".to_owned());
}
}