How to deserialize messages within Actix actors? - rust

My intention is receiving events through WebSockets and use them on the closures of main.
This works when the messages are pure text (String), but the idea is deserializing that text into some structs.
In this example I've added only Data, Error and Event, but in other cases, it could be different, so I've used generics to do that, but I'm a little lost. The compiler has suggested several things that I've tried, but I don't know how to "force" that the message is casted into a specific type (Data in this example, but EventManager could be used on other parts, so it should be generic).
I've attached this code, that tries to show my idea, although it doesn't compile:
events.rs:
use actix::*;
use actix_web::ws::{Client, Message, ProtocolError};
use futures::Future;
use serde::de;
use serde_json::from_str;
struct MyActor<T> {
manager: EventManager<T>,
}
impl<T: 'static> Actor for MyActor<T> {
type Context = Context<Self>;
}
impl<T: 'static> StreamHandler<Message, ProtocolError> for MyActor<T> {
fn handle(&mut self, msg: Message, _ctx: &mut Context<Self>) {
match msg {
Message::Text(text) => {
debug!("Received {}", text);
for idx in 0..self.manager.events.len() {
let data =
from_str(&text).expect(&format!("Error when deserializing {:?}", text));
(self.manager.events[idx].handler)(data)
}
}
_ => panic!(),
}
}
}
pub struct Event<T> {
handler: Box<Fn(T) + 'static>,
}
pub struct EventManager<T> {
events: Vec<Event<T>>,
}
impl<T: 'static> EventManager<T>
where
T: serde::Deserialize<'static>,
{
pub fn new() -> Self {
Self { events: vec![] }
}
pub fn capture<F>(&mut self, function: F)
where
F: for<'h> Fn(T) + 'static,
{
let event = Event {
handler: Box::new(function),
};
self.events.push(event);
}
pub fn run(self) {
let runner = System::new("example");
debug!("run");
Arbiter::spawn(
Client::new("example")
.connect()
.map(|(reader, _writer)| {
MyActor::create(|ctx| {
MyActor::add_stream(reader, ctx);
MyActor { manager: self }
});
})
.map_err(|err| {}),
);
runner.run();
}
}
main.rs:
#[macro_use]
extern crate log;
extern crate actix;
extern crate actix_web;
extern crate env_logger;
extern crate futures;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
pub mod events;
use actix::*;
use serde::de;
use serde::de::{Deserialize, Deserializer};
use events::EventManager;
#[derive(Debug, Message, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Data {
Error(Error),
Event(Event),
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Error {
message: String,
code: String,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Event {
name: String,
content: String,
}
fn main() {
env_logger::init();
let mut client = EventManager::<Data>new();
client.capture(|data| debug!("event: {:?}", data));
client.run();
}
All the code could be see in https://github.com/foochi/how-deserialize-within-actix

There are some fixes to get it compile.
The trick to get it compile is to use Higher-Rank Trait Bounds (HTRB) trait bounds instead of declaring 'static lifetimes.
Follow the compiler suggestion and bind the T: serde::Deserialize<'_> trait:
impl<T> StreamHandler<Message, ProtocolError> for MyActor<T>
where
for<'de> T: serde::Deserialize<'de> + 'static,
Then change also the Deserialize<'static> trait bound associated to theEventManager impl with a HTRB trait bound to get it compatible with the requirement of StreamHandler implementation:
impl<T: 'static> EventManager<T>
where
for<'de> T: serde::Deserialize<'de>,
Finally, if you correct the line the create the client with the right sintax:
let mut client: EventManager<Data> = EventManager::new();
the example code should compile.
Note: For capture the use of a Higher Trait Bound for declaring the Fn requirement is redundant, do simply:
pub fn capture<F>(&mut self, function: F)
where
F: Fn(T) + 'static,

Related

Is it possible to cast Arc<dyn T> into Arc<Mutex<dyn T>>?

In rust, I can convert Arc<i32> into Arc<Mutex<i32>>:
let num = 5;
let arc_num = Arc::new(num);
let mtx_num = Arc::new(Mutex::new(*(arc_num.deref())));
But when it comes to trait, such conversion fails:
use std::sync::{Arc, Mutex};
use std::ops::Deref;
pub trait T {}
#[derive(Copy, Clone)]
pub struct Var {
}
impl T for Var {}
pub fn convert(var: Arc<dyn T>) -> Arc<Mutex<dyn T>> {
return Arc::new(Mutex::new(*(var.deref())));
}
because *(var.deref()) doesn't have a size known at compile-time.
So is it possible at all to convert Arc<dyn T> into Arc<Mutex<dyn T>>?
Only with help from the trait in question like this:
use std::sync::{Arc, Mutex};
pub trait T {
fn mutexme(self: Arc<Self>) -> Arc<Mutex<dyn T>>;
}
#[derive(Copy, Clone)]
pub struct Var {}
impl T for Var {
fn mutexme(self: Arc<Self>) -> Arc<Mutex<dyn T>> {
Arc::new(Mutex::new(*self))
}
}
pub fn convert(var: Arc<dyn T>) -> Arc<Mutex<dyn T>> {
var.mutexme()
}
The problem is that the compiler doesn't know the size of dyn T so it can't reserve enough space on the stack or copy the data there.
Even if you somehow overcame that problem your dyn T might not be Copy or even Clone because trait T doesn't require that and if it did it wouldn't be object safe since Clone isn't.
You also don't need to import Deref because you can use it with it's operator * like I did above.

How to define a generic data type as Message in actix

Is there a way to write this code with #[derive(Message)] and #[rtype(result = "...")].
pub struct MyMsg<T> {
data: T
}
impl<T: 'static> Message for MyMsg<T> {
type Result = Result<MyMsg<T>, Error>;
}
I tried this but the compiler complains about the required lifetime bounds.
#[derive(Message)]
#[rtype(result = "Result<MyMsg<T>, Error>")]
pub struct MyMsg<T> {
pub data: T,
}
I assume you use anyhow, because otherwise Result<..., Error> wouldn't make much sense. (as Error is a trait, not a type)
Then, I don't understand your problem, it just works:
use actix_derive::Message;
use anyhow::Error;
#[derive(Message)]
#[rtype(result = "Result<MyMsg<T>, Error>")]
pub struct MyMsg<T: 'static> {
pub data: T,
}
If you expand that with cargo expand, you can see that you get:
#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
use actix_derive::Message;
use anyhow::Error;
#[rtype(result = "Result<MyMsg<T>, Error>")]
pub struct MyMsg<T: 'static> {
pub data: T,
}
impl<T: 'static> ::actix::Message for MyMsg<T> {
type Result = Result<MyMsg<T>, Error>;
}

Compilation error with tokio::run() and Send marker

I am trying to build a library defining a generic datasource which can pull data from various sources, synchronously and asynchronously.
When building the async piece, I ran into the following compilation issue which I don't understand how to address:
Here is my simplified code (playground link)
extern crate futures; // futures = "0.1.24"
extern crate tokio; // tokio = "0.1.8"
extern crate serde_json;
use futures::Future;
use serde_json::Value;
use std::collections::HashMap;
trait DataSource {
type Data;
fn read_async(&self, Option<HashMap<String, Value>>) -> Box<futures::Future<Item=Option<Self::Data>, Error=String>>
where Self::Data: 'static + Send;
}
struct DataSourceImpl;
impl DataSource for DataSourceImpl {
type Data = Vec<String>;
fn read_async(&self, _params: Option<HashMap<String, Value>>) -> Box<futures::Future<Item=Option<Self::Data>, Error=String>>
where Self::Data: 'static + Send
{
Box::new(futures::future::ok(Some(vec!["some data".to_string()])))
}
}
fn main() {
let datasource = DataSourceImpl{};
let params = HashMap::new();
tokio::run(datasource.read_async(Some(params))
.map(|content| {
println!("Content read = {:?}", &content);
()
})
.map_err(|err| {
println!("Error {}", &err);
()
})
);
}
I got the following compilation error:
error[E0277]: `dyn futures::Future<Item=std::option::Option<std::vec::Vec<std::string::String>>, Error=std::string::String>` cannot be sent between threads safely
--> src/main.rs:45:13
|
45 | runtime.spawn(future);
| ^^^^^ `dyn futures::Future<Item=std::option::Option<std::vec::Vec<std::string::String>>, Error=std::string::String>` cannot be sent between threads safely
|
= help: the trait `std::marker::Send` is not implemented for `dyn futures::Future<Item=std::option::Option<std::vec::Vec<std::string::String>>, Error=std::string::String>`
= note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique<dyn futures::Future<Item=std::option::Option<std::vec::Vec<std::string::String>>, Error=std::string::String>>`
= note: required because it appears within the type `std::boxed::Box<dyn futures::Future<Item=std::option::Option<std::vec::Vec<std::string::String>>, Error=std::string::String>>`
= note: required because it appears within the type `futures::Map<std::boxed::Box<dyn futures::Future<Item=std::option::Option<std::vec::Vec<std::string::String>>, Error=std::string::String>>, [closure#src/main.rs:34:14: 37:10]>`
= note: required because it appears within the type `futures::MapErr<futures::Map<std::boxed::Box<dyn futures::Future<Item=std::option::Option<std::vec::Vec<std::string::String>>, Error=std::string::String>>, [closure#src/main.rs:34:14: 37:10]>, [closure#src/main.rs:38:18: 41:10]>`
Yet when looking into the standard library, I found the following implementations:
impl<T: ?Sized> Send for Box<T> where T: Send
impl<T> Send for Option<T> where T: Send
impl<T> Send for Vec<T> where T: Send
impl Send for String
impl Send for [failure::]Error
What am I missing?
If I get rid of the trait and replace the Box<Future<...>> by impl Future<...> then it works (playground link for the new code); yet I don't understand what is wrong with the trait & Box implementation...
extern crate failure;
extern crate futures; // futures = "0.1.24"
extern crate tokio; // tokio = "0.1.8"
extern crate serde_json;
use futures::Future;
use serde_json::Value;
use std::collections::HashMap;
fn read_async(_params: Option<HashMap<String, Value>>) -> impl futures::Future<Item=Option<Vec<String>>, Error=failure::Error> {
futures::future::ok(Some(vec!["some data".to_string()]))
}
fn main() {
let params = HashMap::new();
let future = read_async(Some(params))
.map(|content| {
println!("Content read = {:?}", &content);
()
})
.map_err(|err| {
println!("Error {}", &err);
()
});
tokio::run(future);
}
Looks like I just needed to change the function signature to
fn read_async(
&self,
_: Option<HashMap<String, Value>>,
) -> Box<Future<Item = Option<Self::Data>, Error = String> + Send> {
// ^^^^^^^
Indeed, Box<T> should be Send when T is Send, but I have to spell it out because Future doesn't derive it manually/automatically.
Thanks to Tobz for pointing this out.

associated type `Context` not found when implementing actix-web's Handler

I have the following code based on the actix-web Database Integration sample.
extern crate actix;
extern crate actix_web;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;
extern crate r2d2;
extern crate r2d2_mysql;
use actix::prelude::*;
use actix_web::{middleware::Logger, server, App, FutureResponse, HttpRequest, HttpResponse};
mod dbservices {
use actix::prelude::*;
use actix_web::dev::Handler;
use model::DataDictionary;
use r2d2::Pool;
use r2d2_mysql::*;
use std::io;
pub struct MysqlConnection {
db_pool: mysql::PooledConn,
}
impl Actor for MysqlConnection {
type Context = SyncContext<Self>;
}
impl MysqlConnection {
pub fn new(db_url: &str) -> MysqlConnection {
unimplemented!();
}
}
pub struct GetDD;
impl Message for GetDD {
type Result = io::Result<Vec<DataDictionary>>;
}
impl Handler<GetDD> for MysqlConnection {
type Result = io::Result<Vec<DataDictionary>>;
fn handle(&mut self, msg: GetDD, _: &mut Self::Context) -> Self::Result {
unimplemented!();
}
}
}
mod model {
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DataDictionary {
id: i32,
name: String,
}
}
struct State {
db: Addr<MysqlConnection>,
}
fn get_dd(req: HttpRequest<State>) -> FutureResponse<HttpResponse> {
req.clone()
.state()
.db
.send(GetDD)
.from_err()
.and_then(|result| Ok.json(result))
.responder()
}
fn main() {
std::env::set_var("RUST_LOG", "actix_web=debug,info");
const db_url: str = "mysql://connstring";
let addr = SyncArbiter::start(3, move || dbservices::MysqlConnection::new(db_url));
server::new(|| {
App::new()
.middleware(Logger::default())
.middleware(Logger::new("%a %{User-Agent}i"))
.prefix("/api")
.scope("/dd", |dp_scope| {
dp_scope.resource("/", |r| r.h(dbservices::GetDD()))
})
}).bind("127.0.0.1:8088")
.unwrap()
.run();
}
I'm getting the following error when compiling. I'm not sure what I'm doing wrong:
error[E0220]: associated type `Context` not found for `Self`
--> src/main.rs:43:50
|
43 | fn handle(&mut self, msg: GetDD, _: &mut Self::Context) -> Self::Result {
| ^^^^^^^^^^^^^ associated type `Context` not found
Here are my dependencies from Cargo.toml:
[dependencies]
actix-web = "0.6.14"
actix = "0.6.1"
chrono = { version = "0.4.2", features = ["serde"] }
serde = "1.0.60"
serde_derive = "1.0.60"
serde_json = "1.0.17"
log = "0.4.1"
env_logger ="0.5.10"
futures = "0.2.1"
r2d2 = "*"
[dependencies.r2d2_mysql]
git = "https://github.com/outersky/r2d2-mysql"
version="*"
Creating a minimal MCVE almost always makes the problem easier to see:
extern crate actix;
extern crate actix_web;
use actix::prelude::*;
use actix_web::dev::Handler;
use std::io;
pub struct MysqlConnection;
impl Actor for MysqlConnection {
type Context = SyncContext<Self>;
}
pub struct DummyMessage;
impl Message for DummyMessage {
type Result = io::Result<String>;
}
impl Handler<DummyMessage> for MysqlConnection {
type Result = io::Result<String>;
fn handle(&mut self, _: DummyMessage, _: &mut Self::Context) -> Self::Result {
unimplemented!();
}
}
fn main() {}
error[E0220]: associated type `Context` not found for `Self`
--> src/main.rs:22:53
|
22 | fn handle(&mut self, _: DummyMessage, _: &mut Self::Context) -> Self::Result {
| ^^^^^^^^^^^^^ associated type `Context` not found
Problem 1 — multiple versions
actix-web = "0.6.14"
actix = "0.6.1"
This brings in two different versions of actix:
$ cargo tree -d
actix v0.5.8
└── actix-web v0.6.14
└── repro v0.1.0 (file:///private/tmp/repro)
actix v0.6.1
└── repro v0.1.0 (file:///private/tmp/repro)
Pick a single one, actix 0.5.8.
See also:
Why is a trait not implemented for a type that clearly has it implemented?
Problem 2 — wrong trait
You bring in actix_web::dev::Handler:
pub trait Handler<S>: 'static {
type Result: Responder;
fn handle(&mut self, req: HttpRequest<S>) -> Self::Result;
}
You are implementing actix::Handler:
pub trait Handler<M>
where
Self: Actor,
M: Message,
{
type Result: MessageResponse<Self, M>;
fn handle(&mut self, msg: M, ctx: &mut Self::Context) -> Self::Result;
}
actix::Handler has Actor as its supertrait, which means that it can access the associated type Context. actix_web::dev::Handler does not have the supertrait, so it doesn't know about Self::Context.
Pick the appropriate trait and implement it correctly.
You can replace Self::Context with SyncContext<Self>
This is actually strange since there is only single associated type Context but for some reason Rust wants you to specify specifically associated type: <Self as Actor>::Context which should not be required since you have single Context type
Are there any other errors that prevent your struct from compiling?

Two similar code snippets but only one triggers a lifetime error

#![feature(rustc_private)]
extern crate rustc;
use rustc::hir::intravisit as hir_visit;
use rustc::hir;
use std::marker::PhantomData;
// ----------------------------------------------------------------------------
// Why does this compile?
// ----------------------------------------------------------------------------
pub struct Map<'a> {
pub _m: PhantomData<&'a ()>,
}
pub struct SomeVisitor<'a, 'tcx: 'a> {
pub map: &'a Map<'tcx>,
}
pub enum NestedVisitorMap<'this, 'tcx: 'this> {
None,
OnlyBodies(&'this Map<'tcx>),
All(&'this Map<'tcx>),
}
pub trait Visitor<'v>: Sized {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v>;
}
impl<'v, 'tcx> Visitor<'v> for SomeVisitor<'v, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
NestedVisitorMap::All(self.map)
}
}
// ----------------------------------------------------------------------------
// Why does this *not* compile?
// ----------------------------------------------------------------------------
pub struct SomeVisitor2<'a, 'tcx: 'a> {
pub map: &'a hir::map::Map<'tcx>,
}
impl<'v, 'tcx> hir_visit::Visitor<'v> for SomeVisitor2<'v, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> hir_visit::NestedVisitorMap<'this, 'v> {
hir_visit::NestedVisitorMap::All(self.map)
}
}
fn main() {}
playground
NestedVisitorMap and Visitor
I recently ran into a lifetime issue and I decided to recreate it without any dependencies. The odd thing is that I can not recreate the lifetime error. To me both implementations look the same from the outside, but only one compiles successfully. Why is that?
rustc 1.21.0-nightly (e26688824 2017-08-27)
Update:
The problem seems to be the RefCell inside Map.
#[derive(Clone)]
pub struct Map<'hir> {
inlined_bodies: RefCell<rustc::util::nodemap::DefIdMap<&'hir hir::Body>>,
}
If there is a RefCell with a inner lifetime, it will trigger an error.
playground
Update2:
It turns out that I just mixed up lifetime subtyping. playground
I still don't know why only RefCell causes the error.

Resources