this is the trait definition
pub trait MessageResponse<A: Actor, M: Message> {
fn handle<R: ResponseChannel<M>>(self, ctx: &mut A::Context, tx: Option<R>);
}
and this the implementation:
enum Responses {
GotPing,
GotPong,
}
impl<A, M> MessageResponse<A, M> for Responses
where
A: Actor,
M: Message<Result = Responses>,
{
fn handle<R: ResponseChannel<M>>(self, _: &mut A::Context, tx: Option<R>) {
if let Some(tx) = tx {
tx.send(self);
}
}
}
im a beginner in Rust and it would be awesome if someone simplifies this for me.
Related
I have traits for senders and receivers of a specific message type.
pub trait Sends {
type Message;
fn send(&self) -> Self::Message;
}
pub trait Receives {
type Message;
fn receive(&mut self, msg: Self::Message);
}
I want to be able to store a compatible pair of sender and receiver in a struct with a run() method that passes messages, i.e. receiver.receive(sender.send()).
My intuition is that this run() method should not require knowledge of the message type (because all occurrences of the message type are handled internally), so the struct and its method should not expose the message type. I think keeping track of the message types also becomes impractical when you have a bigger sender-receiver network.
What is the best way to do this? I tried it out with Any, which mostly works. However,
I'm having difficulty actually creating a SendAny from a Send, and same for the receiver.
I hope there is a more elegant and efficient way, since this introduces boilerplate and needless boxing/unboxing.
Here is what I've got so far:
trait SendsAny {
fn send_any(&self) -> Box<dyn Any>;
}
impl<T> SendsAny for T
where
T: Sends,
T::Message: 'static,
{
fn send_any(&self) -> Box<dyn Any> {
Box::new(self.send())
}
}
// Similar for ReceivesAny
struct SendAndReceive {
// These have to have matching Message types
tx: Box<dyn SendsAny>,
rx: Box<dyn ReceivesAny>,
}
impl SendAndReceive {
fn new<M: 'static>(
tx: Box<dyn Sends<Message = M>>,
rx: Box<dyn Receives<Message = M>>,
) -> Self {
// This doesn't work
let tx = tx as Box<dyn SendsAny>;
todo!()
}
fn run(&mut self) {
self.rx.receive_any(self.tx.send_any());
}
}
You should make the type that binds the Sends and Receives together, here SendAndReceiveInner. And then use a trait object, Box<dyn SendAndReceiveAny> to use it in the type-erased form in SendAndReceive.
struct SendAndReceiveInner<R, S>
where
S: Sends,
R: Receives<Message = S::Message>,
{
tx: S,
rx: R,
}
trait SendAndReceiveAny {
fn run(&mut self);
}
impl<R, S> SendAndReceiveAny for SendAndReceiveInner<R, S>
where
S: Sends,
R: Receives<Message = S::Message>,
{
fn run(&mut self) {
self.rx.receive(self.tx.send());
}
}
struct SendAndReceive {
inner: Box<dyn SendAndReceiveAny>,
}
impl SendAndReceive {
fn new<R, S>(tx: S, rx: R) -> Self
where
S: Sends + 'static,
R: Receives<Message = S::Message> + 'static,
{
Self {
inner: Box::new(SendAndReceiveInner{ tx, rx }),
}
}
fn run(&mut self) {
self.inner.run();
}
}
This has a lot less boxing involved but still a bit of boilerplate. You could just use it in the Box<dyn ...> form since the outermost SendAndReceive isn't doing much at this point, but encapsulation and API presentation is up to the reader.
I don't quite know if this is what you are looking for, but you could make the SendAndReceive generic on the sender and receiver:
pub trait Sends {
type Message;
fn send(&self) -> Self::Message;
}
pub trait Receives {
type Message;
fn receive(&mut self, msg: Self::Message);
}
struct SendAndReceive<R,S>
where S: Sends, R: Receives<Message=S::Message>
{
// These have to have matching Message types
tx: S,
rx: R,
}
impl<R,S> SendAndReceive<R,S>
where S: Sends, R: Receives<Message=S::Message>
{
fn new(tx: S,rx: R,) -> Self {
Self{tx, rx}
}
fn run(&mut self) {
self.rx.receive(self.tx.send());
}
}
The struct is therefore agnostic to the type of the message but generic on the sender/receiver. Also avoid the whole Any machinery.
You could also go the other way and make the struct generic on the message:
pub trait Sends {
type Message;
fn send(&self) -> Self::Message;
}
pub trait Receives {
type Message;
fn receive(&mut self, msg: Self::Message);
}
struct SendAndReceive<M> {
// These have to have matching Message types
tx: Box<dyn Sends<Message=M>>,
rx: Box<dyn Receives<Message=M>>,
}
impl<M> SendAndReceive<M> {
fn new(
tx: Box<dyn Sends<Message = M>>,
rx: Box<dyn Receives<Message = M>>,
) -> Self {
Self{tx,rx}
}
fn run(&mut self) {
self.rx.receive(self.tx.send());
}
}
This again avoids Any and doesn't need to be generic on the sender/receiver but must be generic on the message type.
I don't know whether these two are what you are looking for, but I don't see any other way to avoid run needing specific types/traits.
I have a program that hides mutable state behind a RwLock. What I'd like to do is that when it's borrowed mutably (RW_LOCK.write()), on drop it should do something (namely, try to write to file, clean up the data behind the rwlock, etc.)
For example:
let DATA: RwLock<Data> = RwLock::new(Data { content: Default::default() } );
fn do_something() {
let mut state = DATA.write().unwrap();
state.change(5);
// ...
// Here, just before `state` goes out of scope (where it gets dropped and `RwLock` will allow
// other threads read/write access to `Data`, I would like for `RwLock` to auto-run `state.cleanup()`.
}
Is there a way to do this, or do I have to reimplement RwLock?
You can do this with a wrapper type:
Playground
use std::ops::{Deref, DerefMut, Drop};
use std::sync::{RwLock, RwLockWriteGuard};
type CleanupClosure<'a> = Fn(&mut RwLockWriteGuard<'a, Data>);
struct Data {
content: String,
}
impl Data {
fn change(&mut self, num: i32) {
println!("Changed to {}", num);
self.content = num.to_string();
}
}
struct RwLockWriteWrapper<'a, F: CleanupClosure<'a>>(RwLockWriteGuard<'a, Data>, F);
impl<'a, F: CleanupClosure<'a>> Deref for RwLockWriteWrapper<'a, F> {
type Target = RwLockWriteGuard<'a, Data>;
fn deref(&self) -> &RwLockWriteGuard<'a, Data> {
&self.0
}
}
impl<'a, F: CleanupClosure<'a>> DerefMut for RwLockWriteWrapper<'a, F> {
fn deref_mut(&mut self) -> &mut RwLockWriteGuard<'a, Data> {
&mut self.0
}
}
impl<'a, F: CleanupClosure<'a>> Drop for RwLockWriteWrapper<'a, F> {
fn drop(&mut self) {
println!("Cleaning up!");
self.1(&mut self.0)
}
}
fn main() {
let data: RwLock<Data> = RwLock::new(Data {
content: "Start".to_owned(),
});
do_something(&data);
do_something(&data);
}
fn do_something(data: &RwLock<Data>) {
// Write your own cleanup logic here
let mut state = RwLockWriteWrapper(data.write().unwrap(), |state| {
state.content = "Cleaned up".to_owned()
});
println!("do_something start: {}", state.content);
state.change(5);
println!("do_something after change: {}", state.content);
} // Automatically run cleanup here
It does require you to remember to wrap the type when you call .write() on it. You can wrap RwLock itself in another type that would return RwLockWriteWrapper to automate that as well.
This does become quite verbose, so I found a crate that impls the deref trait for you.
I am still not sure what closures you mentioned in the title meant.
You can create a wrapper that implements Drop:
struct CleanOnDrop<D, F>
where
F: FnOnce(&mut D),
{
data: D,
cleanup: Option<F>,
}
impl<D, F> CleanOnDrop<D, F>
where
F: FnOnce(&mut D),
{
pub fn new(data: D, cleanup: F) -> Self {
Self { data, cleanup: Some(cleanup) }
}
}
impl<D, F> Drop for CleanOnDrop<D, F>
where
F: FnOnce(&mut D)
{
fn drop(&mut self) {
if let Some(mut cleanup) = self.cleanup.take() {
cleanup(&mut self.data);
}
}
}
For convenience, you may want to implement Deref and DerefMut too, so that you can call methods on it directly:
use std::ops::{Deref, DerefMut};
impl<D, F> Deref for CleanOnDrop<D, F>
where
F: FnOnce(&mut D),
{
type Target = D;
fn deref(&self) -> &D {
&self.data
}
}
impl<D, F> DerefMut for CleanOnDrop<D, F>
where
F: FnOnce(&mut D),
{
fn deref_mut(&mut self) -> &mut D {
&mut self.data
}
}
Use the wrapper like this:
let data = RwLock::new(CleanOnDrop::new(
Data {
content: Default::default(),
},
|state| {
state.cleanup();
},
));
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.
I have a Widget trait parametrised on a context type:
trait Widget<C> {
fn f<'a>(&self, ctx: &'a mut C);
}
Some widgets whose context types are the same, but contain references so are parameterised:
struct Ctxt<'c> {
data: &'c u32,
}
struct W1 {}
struct W2 {}
impl<'c> Widget<Ctxt<'c>> for W1 { // and W2
fn f<'a>(&self, ctx: &'a mut Ctxt<'c>) {
unimplemented!()
}
}
I have a multi-widget which wants to store several of these:
struct WV {
widgets: Vec<Box<Widget<Ctxt<????>>>>,
}
impl<'c> Widget<Ctxt<'c>> for WV {
fn f<'a>(&self, ctx: &'a mut Ctxt<'c>) {
for w in &self.widgets {
w.f(ctx);
}
}
}
It looks like I need a Vec<Box<Widget<for<'c> Ctxt<'c>>>>; but you can't do that! Alternatively, only specifying the lifetime in the definition of f:
impl Widget<Ctxt> for W {
fn f<'a, 'c>(&self, ctx: &'a mut Ctxt<'c>) {
unimplemented!()
}
}
This doesn't work either (missing lifetime parameter for Ctxt).
The purpose of the context is to pass a mutable reference to something long-lived which is only needed during f; the &mut reference can't be stored in W1 etc. I don't really want to specify any lifetimes for Ctxt.
How can I store multiple implementers of the trait, which allow passing in a context containing references?
After a night's sleep, I think I have an answer. I can defer the selection of the Ctxt lifetime by indirecting through a new trait CtxtWidget, and impl<'c> Widget<Ctxt<'c>> for the new trait:
trait Widget<C> {
fn f<'a>(&self, ctx: &'a mut C);
}
struct W1 {}
struct W2 {}
struct Ctxt<'c> {
data: &'c u32,
}
trait CtxtWidget {
fn ctxt_f<'a, 'c>(&self, ctx: &'a mut Ctxt<'c>);
}
impl CtxtWidget for W1 {
fn ctxt_f<'a, 'c>(&self, ctx: &'a mut Ctxt<'c>) {
unimplemented!()
}
}
impl CtxtWidget for W2 {
fn ctxt_f<'a, 'c>(&self, ctx: &'a mut Ctxt<'c>) {
unimplemented!()
}
}
impl<'c> Widget<Ctxt<'c>> for Box<CtxtWidget> {
fn f<'a>(&self, ctx: &'a mut Ctxt<'c>) {
self.ctxt_f(ctx);
}
}
struct WV {
pub widgets: Vec<Box<CtxtWidget>>,
}
fn main() {
let mut wv = WV{widgets: Vec::new()};
wv.widgets.push(Box::new(W1{}));
wv.widgets.push(Box::new(W2{}));
let u = 65u32;
let mut ctxt = Ctxt{data: &u};
for widget in &wv.widgets {
widget.f(&mut ctxt);
}
}
(playground)
In effect CtxtWidget is roughly equivalent to for<'c> Widget<Ctxt<'c>>.
I'd still be interested in any other solutions (including intrusive changes if there's a better way to do this).
trait Actor{
fn actor(&self);
}
trait Health{
fn health(&self);
}
struct Plant;
impl Actor for Plant{
fn actor(&self){
println!("Plant Actor");
}
}
struct Monster{
health: f32
}
impl Actor for Monster{
fn actor(&self){
println!("Monster Actor");
}
}
impl Health for Monster{
fn health(&self){
println!("Health: {}",self.health);
}
}
fn main() {
let plant = Box::new(Plant);
let monster = Box::new(Monster{health: 100f32});
let mut actors : Vec<Box<Actor>> = Vec::new();
actors.push(plant);
actors.push(monster);
for a in &actors{
a.actor();
/* Would this be possible?
let health = a.get_trait_object::<Health>();
match health{
Some(h) => {h.health();},
None => {println!("Has no Health trait");}
}
*/
}
}
I am wondering if something like this could be possible?
let health = a.get_trait_object::<Health>();
match health{
Some(h) => {h.health();},
None => {println!("Has no Health trait");}
}
It is not possible to do this in Rust at present, nor is it likely to ever become possible; it is, however, possible to construct similar abstractions as part of your trait:
trait Actor {
fn health(&self) -> Option<&dyn Health>;
}
trait Health { }
impl Actor for Monster {
fn health(&self) -> Option<&dyn Health> { Some(self) }
}
impl Health for Monster { }
impl Actor for Plant {
fn health(&self) -> Option<&dyn Health> { None }
}
Rust is expected to get negative bounds at some point; when that comes, you’ll be able to have something like this:
trait MaybeImplements<Trait: ?Sized> {
fn as_trait_ref(&self) -> Option<&Trait>;
}
macro_rules! impl_maybe_implements {
($trait_:ident) => {
impl<T: $trait_> MaybeImplements<dyn $trait_> for T {
fn as_trait_ref(&self) -> Option<&dyn $trait_> {
Some(self)
}
}
impl<T: !$trait_> MaybeImplements<dyn $trait_> for T {
fn as_trait_ref(&self) -> Option<&dyn $trait_> {
None
}
}
}
}
impl_maybe_implements!(Health);
trait Actor: MaybeImplements<dyn Health> {
}
let health: Option<&dyn Health> = actor.as_trait_ref();
This will reduce the boilerplate from every implementation of a trait to just one per trait, but that stage is not yet upon us. Still, you could take the middle ground of the two approaches:
trait MaybeImplements<Trait: ?Sized> {
fn as_trait_ref(&self) -> Option<&Trait>;
}
macro_rules! register_impl {
($trait_:ident for $ty:ty) => {
impl MaybeImplements<dyn $trait_> for $ty {
fn as_trait_ref(&self) -> Option<dyn $trait_> {
Some(self)
}
}
}
(!$trait_:ident for $ty:ty) => {
impl MaybeImplements<dyn $trait_> for $ty {
fn as_trait_ref(&self) -> Option<dyn $trait_> {
None
}
}
}
}
register_impl!(Health for Monster);
register_impl!(!Health for Plant);
Play around with different ways of handling it until you find something you like! The possibilities are limitless! (Because Rust is Turing‐complete.)
As of 1.0, no. Rust doesn't provide any dynamic downcasting support, with the exception of Any; however, that only allows you to downcast to a value's specific concrete type, not to arbitrary traits that said concrete type implements.
I believe you could implement such casting manually, but that would require unsafe code that would be easy to get wrong; not the sort of thing I want to try and summarise in an SO answer.