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.
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
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With