From a7029ba91137f465a7bf4bc8f1f651182dff6643 Mon Sep 17 00:00:00 2001 From: Matthieu Le Brazidec Date: Mon, 8 Jul 2019 23:02:52 +0200 Subject: [PATCH 01/22] Allowed contexts to wait for futures/streams/io. Also moved `TcpClient`, `TcpServer` and `UdpSocket` from `Runtime` to a new trait called `NetworkManager`, replacing them, in `Runtime`, with this new trait. --- aktoro-context/Cargo.toml | 1 + aktoro-context/src/channel.rs | 2 +- aktoro-context/src/context.rs | 96 ++++++++++++++++ aktoro-context/src/message.rs | 201 +++++++++++++++++++++++++++++++++- aktoro-raw/src/action.rs | 2 +- aktoro-raw/src/channel.rs | 2 +- aktoro-raw/src/context.rs | 25 +++++ aktoro-raw/src/event.rs | 2 +- aktoro-raw/src/lib.rs | 2 + aktoro-raw/src/message.rs | 35 +++++- aktoro-raw/src/net.rs | 51 +++++++++ aktoro-raw/src/runtime.rs | 38 +++---- aktoro-raw/src/spawned.rs | 2 +- aktoro-raw/src/tcp.rs | 18 +-- aktoro-raw/src/udp.rs | 4 +- aktoro-runtime/src/lib.rs | 2 + aktoro-runtime/src/net.rs | 14 +++ aktoro-runtime/src/runtime.rs | 13 +-- aktoro-runtime/src/tcp.rs | 32 +++++- src/lib.rs | 1 + 20 files changed, 493 insertions(+), 50 deletions(-) create mode 100644 aktoro-raw/src/net.rs create mode 100644 aktoro-runtime/src/net.rs diff --git a/aktoro-context/Cargo.toml b/aktoro-context/Cargo.toml index 0bf5f5d..7cf1c20 100644 --- a/aktoro-context/Cargo.toml +++ b/aktoro-context/Cargo.toml @@ -9,6 +9,7 @@ edition = "2018" [dependencies] crossbeam-utils = "0.6" futures-core-preview = "0.3.0-alpha.17" +futures-io-preview = "0.3.0-alpha.17" futures-util-preview = "0.3.0-alpha.17" [dependencies.aktoro-channel] diff --git a/aktoro-context/src/channel.rs b/aktoro-context/src/channel.rs index e2b7ca6..7ac822c 100644 --- a/aktoro-context/src/channel.rs +++ b/aktoro-context/src/channel.rs @@ -49,7 +49,7 @@ where fn try_send(&mut self, msg: M) -> raw::SenderRes where A: raw::Handler, - M: Send, + M: Send + 'static, { let (msg, recv) = Message::new(msg); diff --git a/aktoro-context/src/context.rs b/aktoro-context/src/context.rs index 365f752..f665509 100644 --- a/aktoro-context/src/context.rs +++ b/aktoro-context/src/context.rs @@ -1,4 +1,5 @@ use std::collections::VecDeque; +use std::future::Future; use std::pin::Pin; use std::task::Context as FutContext; use std::task::Poll; @@ -7,6 +8,9 @@ use aktoro_channel::error::TrySendError; use aktoro_raw as raw; use aktoro_raw::Updater as RawUpdater; use futures_core::Stream; +use futures_io::AsyncRead; +use futures_util::FutureExt; +use futures_util::StreamExt; use crate::channel; use crate::channel::Receiver; @@ -15,6 +19,9 @@ use crate::control; use crate::control::Controlled; use crate::control::Controller; use crate::event::Event; +use crate::message::AsyncMessageFut; +use crate::message::AsyncMessageStream; +use crate::message::AsyncReadStream; use crate::update; use crate::update::Updated; use crate::update::Updater; @@ -32,6 +39,12 @@ pub struct Context { /// Whether the status has been recently updated /// and the runtime should be notified. update: bool, + // TODO + futs: Vec>>>, + // TODO + streams: Vec>>>, + // TODO + reads: Vec>>>, /// A list of the actor's unhandled events. events: VecDeque>>, /// An actor's message channel sender. @@ -64,6 +77,9 @@ where ctrler, ctrled, update: false, + futs: Vec::new(), + streams: Vec::new(), + reads: Vec::new(), events: VecDeque::new(), sender, recver, @@ -123,6 +139,42 @@ where fn updater(&mut self) -> &mut Updater { &mut self.updter } + + fn wait(&mut self, fut: F, map: M) + where + F: Future + Unpin + Send + 'static, + M: Fn(O) -> T + Send + 'static, + A: raw::Handler, + T: Send + 'static, + { + self.futs.push(Box::pin( + AsyncMessageFut::new(fut.map(map)), + )); + } + + fn subscribe(&mut self, stream: S, map: M) + where + S: Stream + Unpin + Send + 'static, + M: Fn(I) -> T + Send + 'static, + A: raw::Handler, + T: Send + 'static, + { + self.streams.push(Box::pin( + AsyncMessageStream::new(stream.map(map)), + )); + } + + fn read(&mut self, read: R, map: M) + where + R: AsyncRead + Unpin + Send + 'static, + M: Fn(&mut [u8], usize) -> T + Unpin + Send + Sync + 'static, + A: raw::Handler, + T: Send + 'static, + { + self.reads.push(Box::pin( + AsyncReadStream::new(read, map), + )); + } } impl Stream for Context @@ -170,6 +222,50 @@ where Poll::Pending => (), } + // TODO + for (i, fut) in context.futs.iter_mut().enumerate() { + match fut.as_mut().poll(ctx) { + Poll::Ready(msg) => { + context.futs.remove(i); + + return Poll::Ready(Some(raw::Work::Message(msg))) + } + Poll::Pending => (), + } + } + + // TODO + let mut to_remove = vec![]; + for (i, stream) in context.streams.iter_mut().enumerate() { + match stream.as_mut().poll_next(ctx) { + Poll::Ready(Some(msg)) => { + return Poll::Ready(Some(raw::Work::Message(msg))); + } + Poll::Ready(None) => to_remove.push(i), + Poll::Pending => (), + } + } + + for to_remove in to_remove { + context.streams.remove(to_remove); + } + + // TODO + let mut to_remove = vec![]; + for (i, read) in context.reads.iter_mut().enumerate() { + match read.as_mut().poll_read(ctx) { + Poll::Ready(Ok(msg)) => { + return Poll::Ready(Some(raw::Work::Message(msg))); + } + Poll::Ready(Err(_)) => to_remove.push(i), // FIXME: handle error + Poll::Pending => (), + } + } + + for to_remove in to_remove { + context.reads.remove(to_remove); + } + Poll::Pending } } diff --git a/aktoro-context/src/message.rs b/aktoro-context/src/message.rs index c553b81..87a417e 100644 --- a/aktoro-context/src/message.rs +++ b/aktoro-context/src/message.rs @@ -1,4 +1,13 @@ +use std::future::Future; +use std::marker::PhantomData; +use std::pin::Pin; +use std::task::Context as FutContext; +use std::task::Poll; + use aktoro_raw as raw; +use futures_core::Stream; +use futures_io::AsyncRead; +use futures_io::Error as FutIOError; use crate::respond::Respond; @@ -7,16 +16,58 @@ use crate::respond::Respond; pub(crate) struct Message where A: raw::Handler, - M: Send + 'static, + M: Send, { msg: Option, resp: Option>, } +pub(crate) struct AsyncMessage +where + A: raw::Handler, + M: Send, +{ + msg: Option, + _act: PhantomData, +} + +pub(crate) struct AsyncMessageFut +where + A: raw::Handler, + F: Future + Unpin + Send, + M: Send, +{ + fut: F, + _act: PhantomData, +} + +pub(crate) struct AsyncMessageStream +where + A: raw::Handler, + S: Stream + Unpin + Send, + M: Send, +{ + stream: S, + _act: PhantomData, +} + +pub(crate) struct AsyncReadStream +where + A: raw::Handler, + R: AsyncRead + Unpin + Send, + M: Fn(&mut [u8], usize) -> T + Send, + T: Send, +{ + buf: Vec, + read: R, + map: M, + _act: PhantomData, +} + impl Message where A: raw::Handler, - M: Send + 'static, + M: Send, { pub(crate) fn new(msg: M) -> (Self, Respond) { let resp = Respond::new(); @@ -31,6 +82,64 @@ where } } +impl AsyncMessage +where + A: raw::Handler, + M: Send, +{ + pub(crate) fn new(msg: M) -> Self { + AsyncMessage { + msg: Some(msg), + _act: PhantomData, + } + } +} + +impl AsyncMessageFut +where + A: raw::Handler, + F: Future + Unpin + Send, + M: Send, +{ + pub(crate) fn new(fut: F) -> Self { + AsyncMessageFut { + fut, + _act: PhantomData, + } + } +} + +impl AsyncMessageStream +where + A: raw::Handler, + S: Stream + Unpin + Send, + M: Send, +{ + pub(crate) fn new(stream: S) -> Self { + AsyncMessageStream { + stream, + _act: PhantomData, + } + } +} + +impl AsyncReadStream +where + A: raw::Handler, + R: AsyncRead + Unpin + Send, + M: Fn(&mut [u8], usize) -> T + Unpin + Send, + T: Send, +{ + pub(crate) fn new(read: R, map: M) -> Self { + AsyncReadStream { + buf: Vec::new(), + read, + map, + _act: PhantomData, + } + } +} + impl raw::Message for Message where A: raw::Handler, @@ -48,3 +157,91 @@ where Ok(()) } } + +impl raw::Message for AsyncMessage +where + A: raw::Handler, + M: Send, +{ + type Actor = A; + + fn handle(&mut self, actor: &mut A, ctx: &mut A::Context) -> Result<(), A::Error> { + // If the message hasn't already been handled, + // we do so and return the result. + if let Some(msg) = self.msg.take() { + actor.handle(msg, ctx) + } else { + Ok(()) + } + } +} + +impl raw::AsyncMessageFut for AsyncMessageFut +where + A: raw::Handler, + F: Future + Unpin + Send, + M: Send + 'static, +{ + type Actor = A; + + fn poll( + self: Pin<&mut Self>, + ctx: &mut FutContext, + ) -> Poll>> { + match Pin::new(&mut self.get_mut().fut).poll(ctx) { + Poll::Ready(msg) => Poll::Ready(Box::new(AsyncMessage::new(msg))), + Poll::Pending => Poll::Pending, + } + } +} + +impl raw::AsyncMessageStream for AsyncMessageStream +where + A: raw::Handler, + S: Stream + Unpin + Send, + M: Send + 'static, +{ + type Actor = A; + + fn poll_next( + self: Pin<&mut Self>, + ctx: &mut FutContext, + ) -> Poll>>> { + match Pin::new(&mut self.get_mut().stream).poll_next(ctx) { + Poll::Ready(Some(msg)) => Poll::Ready(Some( + Box::new(AsyncMessage::new(msg)) + )), + Poll::Ready(None) => Poll::Ready(None), + Poll::Pending => Poll::Pending, + } + } +} + +impl raw::AsyncReadStream for AsyncReadStream +where + A: raw::Handler, + R: AsyncRead + Unpin + Send, + M: Fn(&mut [u8], usize) -> T + Unpin + Send, + T: Send + 'static, +{ + type Actor = A; + + fn poll_read( + self: Pin<&mut Self>, + ctx: &mut FutContext, + ) -> Poll>, FutIOError>> { + let stream = self.get_mut(); + + match Pin::new(&mut stream.read).poll_read(ctx, &mut stream.buf) { + Poll::Ready(Ok(read)) => { + let msg = (stream.map)(&mut stream.buf, read); + + Poll::Ready(Ok( + Box::new(AsyncMessage::new(msg)) + )) + } + Poll::Ready(Err(err)) => Poll::Ready(Err(err)), + Poll::Pending => Poll::Pending, + } + } +} diff --git a/aktoro-raw/src/action.rs b/aktoro-raw/src/action.rs index 23c69fb..c2ff275 100644 --- a/aktoro-raw/src/action.rs +++ b/aktoro-raw/src/action.rs @@ -10,7 +10,7 @@ pub trait Action: Send { ) -> Result<(), ::Error>; } -pub trait ActionHandler: Actor { +pub trait ActionHandler: Actor { type Output: Send; /// Handles the action, returning a result diff --git a/aktoro-raw/src/channel.rs b/aktoro-raw/src/channel.rs index 5af4365..fd98b03 100644 --- a/aktoro-raw/src/channel.rs +++ b/aktoro-raw/src/channel.rs @@ -26,7 +26,7 @@ pub trait Sender: Clone { fn try_send(&mut self, msg: M) -> SenderRes where A: Handler, - M: Send; + M: Send + 'static; } pub trait Receiver: Stream>> {} diff --git a/aktoro-raw/src/context.rs b/aktoro-raw/src/context.rs index 081d3dd..5f5254d 100644 --- a/aktoro-raw/src/context.rs +++ b/aktoro-raw/src/context.rs @@ -1,4 +1,7 @@ +use std::future::Future; + use futures_core::Stream; +use futures_io::AsyncRead; use crate::action::Action; use crate::actor::Actor; @@ -6,6 +9,7 @@ use crate::channel::Sender; use crate::control::Controller; use crate::event::Event; use crate::event::EventHandler; +use crate::message::Handler; use crate::message::Message; use crate::update::Updater; @@ -61,6 +65,27 @@ pub trait Context: Unpin + Send + 'static + Stream> { /// Gets a mutable reference to the actors's /// update channel receiver. fn updater(&mut self) -> &mut Self::Updater; + + fn wait(&mut self, fut: F, map: M) + where + F: Future + Unpin + Send + 'static, + M: Fn(O) -> T + Send + 'static, + A: Handler, + T: Send + 'static; + + fn subscribe(&mut self, stream: S, map: M) + where + S: Stream + Unpin + Send + 'static, + M: Fn(I) -> T + Send + 'static, + A: Handler, + T: Send + 'static; + + fn read(&mut self, read: R, map: M) + where + R: AsyncRead + Unpin + Send + 'static, + M: Fn(&mut [u8], usize) -> T + Unpin + Send + Sync + 'static, + A: Handler, + T: Send + 'static; } pub enum Work { diff --git a/aktoro-raw/src/event.rs b/aktoro-raw/src/event.rs index f473ff8..cc4aa1b 100644 --- a/aktoro-raw/src/event.rs +++ b/aktoro-raw/src/event.rs @@ -10,7 +10,7 @@ pub trait Event: Send { ) -> Result<(), ::Error>; } -pub trait EventHandler: Actor { +pub trait EventHandler: Actor { /// Handles the event. fn handle(&mut self, event: E, ctx: &mut Self::Context) -> Result<(), Self::Error>; } diff --git a/aktoro-raw/src/lib.rs b/aktoro-raw/src/lib.rs index 4e86814..c8ec5d9 100644 --- a/aktoro-raw/src/lib.rs +++ b/aktoro-raw/src/lib.rs @@ -5,6 +5,7 @@ mod context; mod control; mod event; mod message; +mod net; mod runtime; mod spawned; mod tcp; @@ -18,6 +19,7 @@ pub use crate::context::*; pub use crate::control::*; pub use crate::event::*; pub use crate::message::*; +pub use crate::net::*; pub use crate::runtime::*; pub use crate::spawned::*; pub use crate::tcp::*; diff --git a/aktoro-raw/src/message.rs b/aktoro-raw/src/message.rs index 013ff5c..b2a1a97 100644 --- a/aktoro-raw/src/message.rs +++ b/aktoro-raw/src/message.rs @@ -1,3 +1,9 @@ +use std::pin::Pin; +use std::task::Context as FutContext; +use std::task::Poll; + +use futures_io::Error as FutIOError; + use crate::actor::Actor; pub trait Message: Send { @@ -10,7 +16,34 @@ pub trait Message: Send { ) -> Result<(), ::Error>; } -pub trait Handler: Actor { +pub trait AsyncMessageFut: Send { + type Actor: Actor; + + fn poll( + self: Pin<&mut Self>, + ctx: &mut FutContext, + ) -> Poll>>; +} + +pub trait AsyncMessageStream: Send { + type Actor: Actor; + + fn poll_next( + self: Pin<&mut Self>, + ctx: &mut FutContext, + ) -> Poll>>>; +} + +pub trait AsyncReadStream: Send { + type Actor: Actor; + + fn poll_read( + self: Pin<&mut Self>, + ctx: &mut FutContext, + ) -> Poll>, FutIOError>>; +} + +pub trait Handler: Actor { type Output: Send; /// Handles the message, returning a result diff --git a/aktoro-raw/src/net.rs b/aktoro-raw/src/net.rs new file mode 100644 index 0000000..a7f56d5 --- /dev/null +++ b/aktoro-raw/src/net.rs @@ -0,0 +1,51 @@ +use std::net::ToSocketAddrs; + +use crate::tcp::TcpClient; +use crate::tcp::TcpServer; +use crate::udp::UdpSocket; + +type TcpConnectRes = Result<::Connect, ::Error>; + +type TcpBindRes = Result::Error>; + +type UdpBindRes = Result::Error>; + +pub trait NetworkManager: Unpin + Send + Sync { + /// The type of the TCP socket client + /// that actors can use to be compatible + /// with the runtime (this might not be + /// necessary depending on the runtime + /// implementation). + type TcpClient: TcpClient; + + /// The type of the TCP socket server + /// that actors can use to be compatible + /// with the runtime (this might not be + /// necessary depending on the runtime + /// implementation). + type TcpServer: TcpServer; + + /// The type of UDP socket that actors + /// can use to be compatible with the + /// runtime (this might not be necessary + /// depending on the runtime implementation). + type UdpSocket: UdpSocket; + + /// Tries to connect to a TCP server at the + /// given address. + fn tcp_connect(&self, addr: A) -> TcpConnectRes { + Self::TcpClient::connect(addr) + } + + /// Tries to create a new TCP server that + /// will be bound to the given address. + fn tcp_bind(&self, addr: A) -> TcpBindRes { + Self::TcpServer::bind(addr) + } + + /// Tries to create a new UDP socket that + /// will be bound to the given address. + fn udp_bind(&self, addr: A) -> UdpBindRes { + Self::UdpSocket::bind(addr) + } +} diff --git a/aktoro-raw/src/runtime.rs b/aktoro-raw/src/runtime.rs index 4af1d2a..a219e37 100644 --- a/aktoro-raw/src/runtime.rs +++ b/aktoro-raw/src/runtime.rs @@ -2,31 +2,17 @@ use std::error::Error as StdError; use std::future::Future; use crate::actor::Actor; +use crate::net::NetworkManager; use crate::spawned::Spawned; -use crate::tcp::TcpClient; -use crate::tcp::TcpServer; -use crate::udp::UdpSocket; pub trait Runtime { - /// The type of the TCP socket client - /// that actors can use to be compatible - /// with the runtime (this might not be - /// necessary depending on the runtime - /// implementation). - type TcpClient: TcpClient; - - /// The type of the TCP socket server - /// that actors can use to be compatible - /// with the runtime (this might not be - /// necessary depending on the runtime - /// implementation). - type TcpServer: TcpServer; - - /// The type of UDP socket that actors - /// can use to be compatible with the - /// runtime (this might not be necessary - /// depending on the runtime implementation). - type UdpSocket: UdpSocket; + /// The type that is handling the types of + /// the TCP socket client and server and + /// of the UDP socket that actors can use + /// to be compatible with the runtime (this + /// might not be necessary depending on the + /// runtime implementation). + type NetworkManager: NetworkManager; /// The future returned after calling the /// [`stop`] method. It will resolve after @@ -42,7 +28,7 @@ pub trait Runtime { /// [`wait`]: #method.wait type Wait: Future>; - type Error: StdError; + type Error: StdError + Send; /// Spawns a new actor on the runtime, /// returning [`Some(Spawned)`] if it @@ -54,6 +40,12 @@ pub trait Runtime { /// [`Actor::starting`]: trait.Actor.html#method.starting fn spawn(&mut self, actor: A) -> Option>; + /// Creates a new network manager, that + /// can then be used by an actor to + /// create a new TCP client, server or + /// an UDP socket. + fn net(&mut self) -> Self::NetworkManager; + /// Asks to all the actors managed by the /// runtime to stop, returning a future /// resolving after all of them have been diff --git a/aktoro-raw/src/spawned.rs b/aktoro-raw/src/spawned.rs index 4bd8051..a1e490c 100644 --- a/aktoro-raw/src/spawned.rs +++ b/aktoro-raw/src/spawned.rs @@ -52,7 +52,7 @@ impl Spawned { pub fn try_send_msg(&mut self, msg: M) -> SenderRes> where A: Handler, - M: Send, + M: Send + 'static, { self.sender.try_send(msg) } diff --git a/aktoro-raw/src/tcp.rs b/aktoro-raw/src/tcp.rs index d9fd955..944c58f 100644 --- a/aktoro-raw/src/tcp.rs +++ b/aktoro-raw/src/tcp.rs @@ -7,22 +7,23 @@ use futures_core::Stream; use futures_io::AsyncRead; use futures_io::AsyncWrite; -pub type TcpServerIncoming<'s, S, E> = Box> + 's>; +pub type TcpServerIncoming<'s, S, E> = Box> + Unpin + Send + 's>; +pub type OwnedTcpServerIncoming = Box> + Unpin + Send>; -pub trait TcpClient: TcpStream + Sized { +pub trait TcpClient: TcpStream + Unpin + Send + Sized { type Connect: Future::Error>>; - type Error: StdError; + type Error: StdError + Send; /// Tries to connect to a TCP server at the /// given address. fn connect(addr: A) -> Result::Error>; } -pub trait TcpServer: Sized { +pub trait TcpServer: Unpin + Send + Sized { type Stream: TcpStream; - type Error: StdError; + type Error: StdError + Send; /// Tries to create a new TCP server that /// will be bound to the given address. @@ -34,10 +35,13 @@ pub trait TcpServer: Sized { /// Returns a stream of incoming connections. fn incoming(&mut self) -> Result, Self::Error>; + + // TODO + fn into_incoming(self) -> Result, Self::Error>; } -pub trait TcpStream: AsyncRead + AsyncWrite { - type Error: StdError; +pub trait TcpStream: AsyncRead + AsyncWrite + Unpin + Send { + type Error: StdError + Send; /// Returns the address that the server /// is bound to. diff --git a/aktoro-raw/src/udp.rs b/aktoro-raw/src/udp.rs index 8e14ac3..06a4ba6 100644 --- a/aktoro-raw/src/udp.rs +++ b/aktoro-raw/src/udp.rs @@ -8,8 +8,8 @@ pub type UdpSocketSendTo<'s, E> = Box> + 's pub type UdpSocketRecv<'s, E> = Box> + 's>; -pub trait UdpSocket: Sized { - type Error: StdError; +pub trait UdpSocket: Unpin + Send + Sized + 'static { + type Error: StdError + Send; /// Tries to create a new UDP socket that /// will be bound to the given address. diff --git a/aktoro-runtime/src/lib.rs b/aktoro-runtime/src/lib.rs index 8a38546..ef04cb4 100644 --- a/aktoro-runtime/src/lib.rs +++ b/aktoro-runtime/src/lib.rs @@ -2,12 +2,14 @@ mod actor; mod error; +mod net; mod runtime; mod tcp; mod udp; pub use crate::actor::Status; pub use crate::error::Error; +pub use crate::net::NetworkManager; pub use crate::runtime::Runtime; pub use crate::tcp::TcpClient; pub use crate::tcp::TcpServer; diff --git a/aktoro-runtime/src/net.rs b/aktoro-runtime/src/net.rs new file mode 100644 index 0000000..9d8c35d --- /dev/null +++ b/aktoro-runtime/src/net.rs @@ -0,0 +1,14 @@ +use aktoro_raw as raw; + +use crate::tcp::TcpClient; +use crate::tcp::TcpServer; +use crate::udp::UdpSocket; + +pub struct NetworkManager; + +impl raw::NetworkManager for NetworkManager { + type TcpClient = TcpClient; + type TcpServer = TcpServer; + + type UdpSocket = UdpSocket; +} diff --git a/aktoro-runtime/src/runtime.rs b/aktoro-runtime/src/runtime.rs index 7343734..0bd0a6d 100644 --- a/aktoro-runtime/src/runtime.rs +++ b/aktoro-runtime/src/runtime.rs @@ -18,9 +18,7 @@ use crate::actor::KillSender as Kill; use crate::actor::KilledRecver; use crate::actor::KilledSender; use crate::error::Error; -use crate::tcp::TcpClient; -use crate::tcp::TcpServer; -use crate::udp::UdpSocket; +use crate::net::NetworkManager; /// An actor runtime using the [`runtime`] crate. /// @@ -65,10 +63,7 @@ impl Runtime { } impl raw::Runtime for Runtime { - type TcpClient = TcpClient; - type TcpServer = TcpServer; - - type UdpSocket = UdpSocket; + type NetworkManager = NetworkManager; type Stop = Stop; type Wait = Wait; @@ -103,6 +98,10 @@ impl raw::Runtime for Runtime { Some(spawned) } + fn net(&mut self) -> NetworkManager { + NetworkManager + } + /// Asks to all the actors managed by the /// runtime to stop, returning a future /// resolving after all of them have been diff --git a/aktoro-runtime/src/tcp.rs b/aktoro-runtime/src/tcp.rs index eaf2376..bbfa1cc 100644 --- a/aktoro-runtime/src/tcp.rs +++ b/aktoro-runtime/src/tcp.rs @@ -50,6 +50,12 @@ pub struct TcpIncoming<'i> { incoming: net::tcp::IncomingStream<'i>, } +// TODO +pub struct OwnedTcpIcoming { + // TODO + server: TcpServer, +} + /// A TCP stream, owned by a server, /// and allowing it to communicate with /// a client. @@ -89,13 +95,19 @@ impl raw::TcpServer for TcpServer { } } - fn incoming<'s>( - &'s mut self, - ) -> Result> + 's>, Error> { + fn incoming<'i>( + &'i mut self, + ) -> Result> + Unpin + Send + 'i>, Error> { Ok(Box::new(TcpIncoming { incoming: self.listener.incoming(), })) } + + fn into_incoming(self) -> Result> + Unpin + Send>, Error> { + Ok(Box::new(OwnedTcpIcoming { + server: self, + })) + } } impl raw::TcpStream for TcpClient { @@ -161,6 +173,20 @@ impl<'i> Stream for TcpIncoming<'i> { } } +impl Stream for OwnedTcpIcoming { + type Item = Result; + + fn poll_next(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll> { + match Pin::new(&mut self.get_mut().server.listener.accept()).poll(ctx) { + Poll::Ready(Ok((stream, _))) => { + Poll::Ready(Some(Ok(TcpStream { stream }))) + } + Poll::Ready(Err(err)) => Poll::Ready(Some(Err(Box::new(err).into()))), + Poll::Pending => Poll::Pending, + } + } +} + impl AsyncRead for TcpClient { fn poll_read( self: Pin<&mut Self>, diff --git a/src/lib.rs b/src/lib.rs index 7b0a88f..75900dd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,6 +24,7 @@ pub mod prelude { pub use aktoro_raw::Updated as RawUpdated; pub use aktoro_raw::Updater as RawUpdater; + pub use aktoro_raw::NetworkManager as RawNetworkManager; pub use aktoro_raw::TcpClient as RawTcpClient; pub use aktoro_raw::TcpServer as RawTcpServer; pub use aktoro_raw::TcpStream as RawTcpStream; From 5dc2d18873718800d8a687ce71dc19a2a75745cc Mon Sep 17 00:00:00 2001 From: Matthieu Le Brazidec Date: Mon, 8 Jul 2019 23:12:12 +0200 Subject: [PATCH 02/22] Formatting. --- Cargo.toml | 1 + aktoro-context/src/context.rs | 15 +++---- aktoro-context/src/message.rs | 13 ++---- aktoro-raw/src/message.rs | 12 +++-- aktoro-raw/src/tcp.rs | 4 +- aktoro-runtime/src/tcp.rs | 14 +++--- examples/hello_world/src/main.rs | 2 - examples/net/Cargo.toml | 17 ++++++++ examples/net/LICENSE.md | 1 + examples/net/src/main.rs | 75 ++++++++++++++++++++++++++++++++ 10 files changed, 120 insertions(+), 34 deletions(-) create mode 100644 examples/net/Cargo.toml create mode 120000 examples/net/LICENSE.md create mode 100644 examples/net/src/main.rs diff --git a/Cargo.toml b/Cargo.toml index 9e4cab3..42963ae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,4 +35,5 @@ members = [ "aktoro-runtime", "examples/hello_world", + "examples/net", ] diff --git a/aktoro-context/src/context.rs b/aktoro-context/src/context.rs index f665509..77bbe9d 100644 --- a/aktoro-context/src/context.rs +++ b/aktoro-context/src/context.rs @@ -147,9 +147,7 @@ where A: raw::Handler, T: Send + 'static, { - self.futs.push(Box::pin( - AsyncMessageFut::new(fut.map(map)), - )); + self.futs.push(Box::pin(AsyncMessageFut::new(fut.map(map)))); } fn subscribe(&mut self, stream: S, map: M) @@ -159,9 +157,8 @@ where A: raw::Handler, T: Send + 'static, { - self.streams.push(Box::pin( - AsyncMessageStream::new(stream.map(map)), - )); + self.streams + .push(Box::pin(AsyncMessageStream::new(stream.map(map)))); } fn read(&mut self, read: R, map: M) @@ -171,9 +168,7 @@ where A: raw::Handler, T: Send + 'static, { - self.reads.push(Box::pin( - AsyncReadStream::new(read, map), - )); + self.reads.push(Box::pin(AsyncReadStream::new(read, map))); } } @@ -228,7 +223,7 @@ where Poll::Ready(msg) => { context.futs.remove(i); - return Poll::Ready(Some(raw::Work::Message(msg))) + return Poll::Ready(Some(raw::Work::Message(msg))); } Poll::Pending => (), } diff --git a/aktoro-context/src/message.rs b/aktoro-context/src/message.rs index 87a417e..9c33238 100644 --- a/aktoro-context/src/message.rs +++ b/aktoro-context/src/message.rs @@ -184,10 +184,7 @@ where { type Actor = A; - fn poll( - self: Pin<&mut Self>, - ctx: &mut FutContext, - ) -> Poll>> { + fn poll(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll>> { match Pin::new(&mut self.get_mut().fut).poll(ctx) { Poll::Ready(msg) => Poll::Ready(Box::new(AsyncMessage::new(msg))), Poll::Pending => Poll::Pending, @@ -208,9 +205,7 @@ where ctx: &mut FutContext, ) -> Poll>>> { match Pin::new(&mut self.get_mut().stream).poll_next(ctx) { - Poll::Ready(Some(msg)) => Poll::Ready(Some( - Box::new(AsyncMessage::new(msg)) - )), + Poll::Ready(Some(msg)) => Poll::Ready(Some(Box::new(AsyncMessage::new(msg)))), Poll::Ready(None) => Poll::Ready(None), Poll::Pending => Poll::Pending, } @@ -236,9 +231,7 @@ where Poll::Ready(Ok(read)) => { let msg = (stream.map)(&mut stream.buf, read); - Poll::Ready(Ok( - Box::new(AsyncMessage::new(msg)) - )) + Poll::Ready(Ok(Box::new(AsyncMessage::new(msg)))) } Poll::Ready(Err(err)) => Poll::Ready(Err(err)), Poll::Pending => Poll::Pending, diff --git a/aktoro-raw/src/message.rs b/aktoro-raw/src/message.rs index b2a1a97..067e90f 100644 --- a/aktoro-raw/src/message.rs +++ b/aktoro-raw/src/message.rs @@ -6,6 +6,12 @@ use futures_io::Error as FutIOError; use crate::actor::Actor; +pub type AsyncMessageFutOutput = Box>; + +pub type AsyncMessageStreamItem = Option>>; + +pub type AsyncReadStreamItem = Result>, FutIOError>; + pub trait Message: Send { type Actor: Actor; @@ -22,7 +28,7 @@ pub trait AsyncMessageFut: Send { fn poll( self: Pin<&mut Self>, ctx: &mut FutContext, - ) -> Poll>>; + ) -> Poll; } pub trait AsyncMessageStream: Send { @@ -31,7 +37,7 @@ pub trait AsyncMessageStream: Send { fn poll_next( self: Pin<&mut Self>, ctx: &mut FutContext, - ) -> Poll>>>; + ) -> Poll; } pub trait AsyncReadStream: Send { @@ -40,7 +46,7 @@ pub trait AsyncReadStream: Send { fn poll_read( self: Pin<&mut Self>, ctx: &mut FutContext, - ) -> Poll>, FutIOError>>; + ) -> Poll; } pub trait Handler: Actor { diff --git a/aktoro-raw/src/tcp.rs b/aktoro-raw/src/tcp.rs index 944c58f..0cc4dac 100644 --- a/aktoro-raw/src/tcp.rs +++ b/aktoro-raw/src/tcp.rs @@ -37,7 +37,9 @@ pub trait TcpServer: Unpin + Send + Sized { fn incoming(&mut self) -> Result, Self::Error>; // TODO - fn into_incoming(self) -> Result, Self::Error>; + fn into_incoming( + self, + ) -> Result, Self::Error>; } pub trait TcpStream: AsyncRead + AsyncWrite + Unpin + Send { diff --git a/aktoro-runtime/src/tcp.rs b/aktoro-runtime/src/tcp.rs index bbfa1cc..8c0ce24 100644 --- a/aktoro-runtime/src/tcp.rs +++ b/aktoro-runtime/src/tcp.rs @@ -103,10 +103,10 @@ impl raw::TcpServer for TcpServer { })) } - fn into_incoming(self) -> Result> + Unpin + Send>, Error> { - Ok(Box::new(OwnedTcpIcoming { - server: self, - })) + fn into_incoming( + self, + ) -> Result> + Unpin + Send>, Error> { + Ok(Box::new(OwnedTcpIcoming { server: self })) } } @@ -178,13 +178,11 @@ impl Stream for OwnedTcpIcoming { fn poll_next(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll> { match Pin::new(&mut self.get_mut().server.listener.accept()).poll(ctx) { - Poll::Ready(Ok((stream, _))) => { - Poll::Ready(Some(Ok(TcpStream { stream }))) - } + Poll::Ready(Ok((stream, _))) => Poll::Ready(Some(Ok(TcpStream { stream }))), Poll::Ready(Err(err)) => Poll::Ready(Some(Err(Box::new(err).into()))), Poll::Pending => Poll::Pending, } - } + } } impl AsyncRead for TcpClient { diff --git a/examples/hello_world/src/main.rs b/examples/hello_world/src/main.rs index 4b84a33..9528fd4 100644 --- a/examples/hello_world/src/main.rs +++ b/examples/hello_world/src/main.rs @@ -14,9 +14,7 @@ struct Kill; impl Actor for HelloActor { type Context = Context; - type Status = Status; - type Error = Error; } diff --git a/examples/net/Cargo.toml b/examples/net/Cargo.toml new file mode 100644 index 0000000..13f153c --- /dev/null +++ b/examples/net/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "net" +version = "0.1.0" +license = "MIT" +authors = ["Matthieu Le Brazidec "] +edition = "2018" + +[dependencies] +runtime = "0.3.0-alpha.6" + +[dependencies.aktoro] +path = "../.." +version = "0.1.0-alpha.3" + +[dependencies.futures-util-preview] +version = "0.3.0-alpha.17" +features = ["nightly", "async-await"] diff --git a/examples/net/LICENSE.md b/examples/net/LICENSE.md new file mode 120000 index 0000000..f0608a6 --- /dev/null +++ b/examples/net/LICENSE.md @@ -0,0 +1 @@ +../../LICENSE.md \ No newline at end of file diff --git a/examples/net/src/main.rs b/examples/net/src/main.rs new file mode 100644 index 0000000..73ba6c1 --- /dev/null +++ b/examples/net/src/main.rs @@ -0,0 +1,75 @@ +#![feature(async_await)] + +use std::task::Poll; + +use aktoro::prelude::*; +use aktoro::raw; +use futures_util::poll; + +struct Server { + tcp: Option, +} + +struct Connection { + stream: S::Stream, +} + +impl Actor for Server +where + S: raw::TcpServer + 'static, +{ + type Context = Context; + type Status = Status; + type Error = Error; + + fn started(&mut self, ctx: &mut Self::Context) { + println!("started"); + ctx.subscribe(self.tcp.take().unwrap().into_incoming().unwrap(), |conn| { + Connection { + stream: conn.unwrap(), + } + }); + } +} + +impl Handler> for Server +where + S: raw::TcpServer + 'static, +{ + type Output = (); + + fn handle(&mut self, msg: Connection, ctx: &mut Context) -> Result<(), Self::Error> { + println!("new connection"); + Ok(()) + } +} + +#[runtime::main] +async fn main() { + let mut rt = Runtime::new(); + let net = rt.net(); + + let server = Server { + tcp: Some(net.tcp_bind("127.0.0.1:5555").unwrap()), + }; + + rt.spawn(server).unwrap(); + + let mut run = runtime::spawn(run(net)); + let mut wait = rt.wait(); + + loop { + if let Poll::Ready(_) = poll!(&mut run) { + break; + } + + if let Poll::Ready(res) = poll!(&mut wait) { + res.expect("an error occured while waiting for the runtime to stop"); + break; + } + } +} + +async fn run(net: N) { + loop {} +} From 0b09f44d786e9f523483055532f2e44b8da28a22 Mon Sep 17 00:00:00 2001 From: Matthieu Le Brazidec Date: Wed, 10 Jul 2019 08:10:02 +0200 Subject: [PATCH 03/22] Fixed a bug making the compiler return ICEs. --- aktoro-raw/src/message.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/aktoro-raw/src/message.rs b/aktoro-raw/src/message.rs index 067e90f..ff7e85e 100644 --- a/aktoro-raw/src/message.rs +++ b/aktoro-raw/src/message.rs @@ -6,11 +6,11 @@ use futures_io::Error as FutIOError; use crate::actor::Actor; -pub type AsyncMessageFutOutput = Box>; +pub type AsyncMessageFutOutput = Box>; -pub type AsyncMessageStreamItem = Option>>; +pub type AsyncMessageStreamItem = Option>>; -pub type AsyncReadStreamItem = Result>, FutIOError>; +pub type AsyncReadStreamItem = Result>, FutIOError>; pub trait Message: Send { type Actor: Actor; @@ -28,7 +28,7 @@ pub trait AsyncMessageFut: Send { fn poll( self: Pin<&mut Self>, ctx: &mut FutContext, - ) -> Poll; + ) -> Poll>; } pub trait AsyncMessageStream: Send { @@ -37,7 +37,7 @@ pub trait AsyncMessageStream: Send { fn poll_next( self: Pin<&mut Self>, ctx: &mut FutContext, - ) -> Poll; + ) -> Poll>; } pub trait AsyncReadStream: Send { @@ -46,7 +46,7 @@ pub trait AsyncReadStream: Send { fn poll_read( self: Pin<&mut Self>, ctx: &mut FutContext, - ) -> Poll; + ) -> Poll>; } pub trait Handler: Actor { From 1fe7401f90a3ada61c2ebe67d16a8408b77fbe83 Mon Sep 17 00:00:00 2001 From: Matthieu Le Brazidec Date: Wed, 10 Jul 2019 19:25:11 +0200 Subject: [PATCH 04/22] Modified the handling of wakers. A receiver will have only one spot in the channel's wakers list and will update it when a new waker is available instead of pushing the registering the new one. This way, the channel wont try to wake dead wakers. --- aktoro-channel/src/channel.rs | 14 ++++++++--- aktoro-channel/src/receiver.rs | 46 ++++++++++++++++++++++++++-------- 2 files changed, 46 insertions(+), 14 deletions(-) diff --git a/aktoro-channel/src/channel.rs b/aktoro-channel/src/channel.rs index f8b82b5..be23eaf 100644 --- a/aktoro-channel/src/channel.rs +++ b/aktoro-channel/src/channel.rs @@ -1,8 +1,10 @@ use std::sync::atomic::AtomicBool; use std::sync::atomic::Ordering; +use std::sync::Arc; use std::task::Waker; use crossbeam_queue::SegQueue; +use crossbeam_utils::atomic::AtomicCell; use crate::counters::Counters; use crate::error::*; @@ -16,7 +18,7 @@ pub(crate) struct Channel { pub(crate) queue: Queue>, pub(crate) closed: AtomicBool, pub(crate) counters: Counters, - pub(crate) wakers: SegQueue, + pub(crate) wakers: SegQueue>>>, } impl Channel { @@ -74,7 +76,7 @@ impl Channel { /// Registers a new waker to be /// notified when a new message is /// available. - pub(crate) fn register(&self, waker: Waker) { + pub(crate) fn register(&self, waker: Arc>>) { self.wakers.push(waker); } @@ -82,7 +84,13 @@ impl Channel { /// available. fn notify(&self) { if let Ok(waker) = self.wakers.pop() { - waker.wake(); + if let Some(waker_) = waker.swap(None) { + waker_.wake(); + + self.wakers.push(waker); + } else { + self.notify(); + } } } diff --git a/aktoro-channel/src/receiver.rs b/aktoro-channel/src/receiver.rs index d56cfe8..333980e 100644 --- a/aktoro-channel/src/receiver.rs +++ b/aktoro-channel/src/receiver.rs @@ -2,7 +2,9 @@ use std::pin::Pin; use std::sync::Arc; use std::task::Context; use std::task::Poll; +use std::task::Waker; +use crossbeam_utils::atomic::AtomicCell; use futures_core::FusedStream; use futures_core::Stream; @@ -15,7 +17,10 @@ use crate::error::*; /// implementation. /// /// [`try_recv`]: #method.try_recv -pub struct Receiver(Option>>); +pub struct Receiver { + waker: Arc>>, + channel: Option>>, +} impl Receiver { /// Creates a receiver from a pointer @@ -26,13 +31,20 @@ impl Receiver { // immediately after a channel's // creation. channel.counters.add_recver().expect("receivers limit == 0"); - Receiver(Some(channel)) + + let waker = Arc::new(AtomicCell::new(None)); + channel.register(waker.clone()); + + Receiver { + waker, + channel: Some(channel), + } } /// Tries to receive a message from /// the channel. pub fn try_recv(&self) -> Result, TryRecvError> { - if let Some(channel) = &self.0 { + if let Some(channel) = &self.channel { match channel.try_recv() { Ok(Some(msg)) => Ok(Some(msg.unwrap())), Ok(None) => Ok(None), @@ -46,7 +58,7 @@ impl Receiver { /// Whether the channel the receiver /// is connected to is closed. pub fn is_closed(&self) -> bool { - if let Some(channel) = &self.0 { + if let Some(channel) = &self.channel { channel.check_is_closed() } else { true @@ -56,7 +68,9 @@ impl Receiver { /// Closes the channel the receiver /// is connected to. pub fn close_channel(&self) { - if let Some(channel) = &self.0 { + self.waker.store(None); + + if let Some(channel) = &self.channel { channel.close() } } @@ -64,7 +78,9 @@ impl Receiver { /// Disconnects the receiver from the /// channel. pub fn disconnect(&mut self) { - let channel = if let Some(channel) = self.0.take() { + self.waker.store(None); + + let channel = if let Some(channel) = self.channel.take() { channel } else { return; @@ -79,9 +95,14 @@ impl Receiver { /// returning a new receiver connected to /// the same channel, or an error. pub fn try_clone(&self) -> Result { - if let Some(channel) = &self.0 { + if let Some(channel) = &self.channel { if channel.counters.add_recver().is_ok() { - Ok(Receiver(Some(channel.clone()))) + let waker = Arc::new(AtomicCell::new(None)); + + Ok(Receiver { + waker, + channel: Some(channel.clone()), + }) } else { Err(CloneError::limit()) } @@ -95,7 +116,9 @@ impl Stream for Receiver { type Item = T; fn poll_next(self: Pin<&mut Self>, ctx: &mut Context) -> Poll> { - if let Some(channel) = &self.0 { + self.waker.store(None); + + if let Some(channel) = &self.channel { // We try to receive a message... match channel.try_recv() { // ...and return it if one is @@ -104,7 +127,8 @@ impl Stream for Receiver { // ...or register the stream's // waker if none is available... Ok(None) => { - channel.register(ctx.waker().clone()); + self.waker.store(Some(ctx.waker().clone())); + Poll::Pending } // ...or stop the stream if @@ -119,7 +143,7 @@ impl Stream for Receiver { impl FusedStream for Receiver { fn is_terminated(&self) -> bool { - if let Some(channel) = &self.0 { + if let Some(channel) = &self.channel { channel.is_closed() && channel.is_empty() } else { true From e385fb6790eef4868bd7f94c9d64f50af4202288 Mon Sep 17 00:00:00 2001 From: Matthieu Le Brazidec Date: Wed, 10 Jul 2019 19:30:00 +0200 Subject: [PATCH 05/22] Added support for writing to `AsyncWrite`s. Also made the `AsyncRead` forwarding support better by, for example, adding a `map_err` closure to handle the case where an error is returned by `AsyncRead::poll_read` so that a different actor message can be returned. --- aktoro-context/src/context.rs | 52 +++++++++----- aktoro-context/src/message.rs | 131 +++++++++++++++++++++++++++++----- aktoro-raw/src/context.rs | 33 +++++++-- aktoro-raw/src/message.rs | 22 +++--- aktoro-raw/src/tcp.rs | 2 +- 5 files changed, 190 insertions(+), 50 deletions(-) diff --git a/aktoro-context/src/context.rs b/aktoro-context/src/context.rs index 77bbe9d..f06d5c2 100644 --- a/aktoro-context/src/context.rs +++ b/aktoro-context/src/context.rs @@ -8,7 +8,9 @@ use aktoro_channel::error::TrySendError; use aktoro_raw as raw; use aktoro_raw::Updater as RawUpdater; use futures_core::Stream; +use futures_io as io; use futures_io::AsyncRead; +use futures_io::AsyncWrite; use futures_util::FutureExt; use futures_util::StreamExt; @@ -22,6 +24,7 @@ use crate::event::Event; use crate::message::AsyncMessageFut; use crate::message::AsyncMessageStream; use crate::message::AsyncReadStream; +use crate::message::AsyncWriteFut; use crate::update; use crate::update::Updated; use crate::update::Updater; @@ -161,14 +164,38 @@ where .push(Box::pin(AsyncMessageStream::new(stream.map(map)))); } - fn read(&mut self, read: R, map: M) - where + fn read( + &mut self, + read: R, + cap: usize, + map: M, + map_err: N, + ) where R: AsyncRead + Unpin + Send + 'static, - M: Fn(&mut [u8], usize) -> T + Unpin + Send + Sync + 'static, - A: raw::Handler, + M: Fn(Vec) -> T + Unpin + Send + Sync + 'static, + N: Fn(io::Error) -> E + Unpin + Send + Sync + 'static, + A: raw::Handler + raw::Handler, + T: Send + 'static, + E: Send + 'static, + { + self.reads.push(Box::pin(AsyncReadStream::new(read, cap, map, map_err))); + } + + fn write( + &mut self, + write: W, + data: Vec, + map: M, + map_err: N, + ) where + W: AsyncWrite + Unpin + Send + 'static, + M: Fn((Vec, usize), W) -> T + Unpin + Send + Sync + 'static, + N: Fn(io::Error) -> E + Unpin + Send + Sync + 'static, + A: raw::Handler + raw::Handler, T: Send + 'static, + E: Send + 'static, { - self.reads.push(Box::pin(AsyncReadStream::new(read, map))); + self.futs.push(Box::pin(AsyncWriteFut::new(write, data, map, map_err))); } } @@ -246,21 +273,12 @@ where } // TODO - let mut to_remove = vec![]; - for (i, read) in context.reads.iter_mut().enumerate() { - match read.as_mut().poll_read(ctx) { - Poll::Ready(Ok(msg)) => { - return Poll::Ready(Some(raw::Work::Message(msg))); - } - Poll::Ready(Err(_)) => to_remove.push(i), // FIXME: handle error - Poll::Pending => (), + for read in context.reads.iter_mut() { + if let Poll::Ready(msg) = read.as_mut().poll_read(ctx) { + return Poll::Ready(Some(raw::Work::Message(msg))); } } - for to_remove in to_remove { - context.reads.remove(to_remove); - } - Poll::Pending } } diff --git a/aktoro-context/src/message.rs b/aktoro-context/src/message.rs index 9c33238..b8d7ddc 100644 --- a/aktoro-context/src/message.rs +++ b/aktoro-context/src/message.rs @@ -6,8 +6,9 @@ use std::task::Poll; use aktoro_raw as raw; use futures_core::Stream; +use futures_io as io; use futures_io::AsyncRead; -use futures_io::Error as FutIOError; +use futures_io::AsyncWrite; use crate::respond::Respond; @@ -51,16 +52,36 @@ where _act: PhantomData, } -pub(crate) struct AsyncReadStream +pub(crate) struct AsyncReadStream where - A: raw::Handler, + A: raw::Handler + raw::Handler, R: AsyncRead + Unpin + Send, - M: Fn(&mut [u8], usize) -> T + Send, + M: Fn(Vec) -> T + Send, + N: Fn(io::Error) -> E + Send, T: Send, + E: Send, { + cap: usize, buf: Vec, read: R, map: M, + map_err: N, + _act: PhantomData, +} + +pub(crate) struct AsyncWriteFut +where + A: raw::Handler + raw::Handler, + W: AsyncWrite + Unpin + Send, + M: Fn((Vec, usize), W) -> T + Unpin + Send + Sync + 'static, + N: Fn(io::Error) -> E + Unpin + Send + Sync + 'static, + T: Send, + E: Send, +{ + data: Option>, + map: M, + map_err: N, + write: Option, _act: PhantomData, } @@ -123,18 +144,45 @@ where } } -impl AsyncReadStream +impl AsyncReadStream where - A: raw::Handler, + A: raw::Handler + raw::Handler, R: AsyncRead + Unpin + Send, - M: Fn(&mut [u8], usize) -> T + Unpin + Send, + M: Fn(Vec) -> T + Unpin + Send, + N: Fn(io::Error) -> E + Unpin + Send, T: Send, + E: Send, { - pub(crate) fn new(read: R, map: M) -> Self { + pub(crate) fn new(read: R, cap: usize, map: M, map_err: N) -> Self { + let mut buf = Vec::with_capacity(cap); + buf.resize(cap, 0); + AsyncReadStream { - buf: Vec::new(), + cap, + buf, read, map, + map_err, + _act: PhantomData, + } + } +} + +impl AsyncWriteFut +where + A: raw::Handler + raw::Handler, + W: AsyncWrite + Unpin + Send, + M: Fn((Vec, usize), W) -> T + Unpin + Send + Sync, + N: Fn(io::Error) -> E + Unpin + Send + Sync, + T: Send, + E: Send, +{ + pub(crate) fn new(write: W, data: Vec, map: M, map_err: N) -> Self { + AsyncWriteFut { + data: Some(data), + map, + map_err, + write: Some(write), _act: PhantomData, } } @@ -184,7 +232,7 @@ where { type Actor = A; - fn poll(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll>> { + fn poll(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll> { match Pin::new(&mut self.get_mut().fut).poll(ctx) { Poll::Ready(msg) => Poll::Ready(Box::new(AsyncMessage::new(msg))), Poll::Pending => Poll::Pending, @@ -203,7 +251,7 @@ where fn poll_next( self: Pin<&mut Self>, ctx: &mut FutContext, - ) -> Poll>>> { + ) -> Poll> { match Pin::new(&mut self.get_mut().stream).poll_next(ctx) { Poll::Ready(Some(msg)) => Poll::Ready(Some(Box::new(AsyncMessage::new(msg)))), Poll::Ready(None) => Poll::Ready(None), @@ -212,28 +260,75 @@ where } } -impl raw::AsyncReadStream for AsyncReadStream +impl raw::AsyncReadStream for AsyncReadStream where - A: raw::Handler, + A: raw::Handler + raw::Handler, R: AsyncRead + Unpin + Send, - M: Fn(&mut [u8], usize) -> T + Unpin + Send, + M: Fn(Vec) -> T + Unpin + Send, + N: Fn(io::Error) -> E + Unpin + Send, T: Send + 'static, + E: Send + 'static, { type Actor = A; fn poll_read( self: Pin<&mut Self>, ctx: &mut FutContext, - ) -> Poll>, FutIOError>> { + ) -> Poll> { let stream = self.get_mut(); match Pin::new(&mut stream.read).poll_read(ctx, &mut stream.buf) { Poll::Ready(Ok(read)) => { - let msg = (stream.map)(&mut stream.buf, read); + let data = stream.buf.drain(0..read).collect(); + stream.buf.resize(stream.cap, 0); + + let msg = (stream.map)(data); + + Poll::Ready(Box::new(AsyncMessage::new(msg))) + } + Poll::Ready(Err(err)) => { + let msg = (stream.map_err)(err); + + Poll::Ready(Box::new(AsyncMessage::new(msg))) + } + Poll::Pending => Poll::Pending, + } + } +} + +impl raw::AsyncMessageFut for AsyncWriteFut +where + A: raw::Handler + raw::Handler, + W: AsyncWrite + Unpin + Send, + M: Fn((Vec, usize), W) -> T + Unpin + Send + Sync, + N: Fn(io::Error) -> E + Unpin + Send + Sync, + T: Send + 'static, + E: Send + 'static, +{ + type Actor = A; + + fn poll( + self: Pin<&mut Self>, + ctx: &mut FutContext, + ) -> Poll> { + let fut = self.get_mut(); + + match Pin::new(&mut fut.write.as_mut().unwrap()) + .poll_write(ctx, fut.data.as_ref().unwrap()) + { + Poll::Ready(Ok(wrote)) => { + let msg = (fut.map)( + (fut.data.take().unwrap(), wrote), + fut.write.take().unwrap(), + ); + + Poll::Ready(Box::new(AsyncMessage::new(msg))) + } + Poll::Ready(Err(err)) => { + let msg = (fut.map_err)(err); - Poll::Ready(Ok(Box::new(AsyncMessage::new(msg)))) + Poll::Ready(Box::new(AsyncMessage::new(msg))) } - Poll::Ready(Err(err)) => Poll::Ready(Err(err)), Poll::Pending => Poll::Pending, } } diff --git a/aktoro-raw/src/context.rs b/aktoro-raw/src/context.rs index 5f5254d..e07071b 100644 --- a/aktoro-raw/src/context.rs +++ b/aktoro-raw/src/context.rs @@ -1,7 +1,9 @@ use std::future::Future; use futures_core::Stream; +use futures_io as io; use futures_io::AsyncRead; +use futures_io::AsyncWrite; use crate::action::Action; use crate::actor::Actor; @@ -80,12 +82,33 @@ pub trait Context: Unpin + Send + 'static + Stream> { A: Handler, T: Send + 'static; - fn read(&mut self, read: R, map: M) - where + fn read( + &mut self, + read: R, + cap: usize, + map: M, + map_err: N, + ) where R: AsyncRead + Unpin + Send + 'static, - M: Fn(&mut [u8], usize) -> T + Unpin + Send + Sync + 'static, - A: Handler, - T: Send + 'static; + M: Fn(Vec) -> T + Unpin + Send + Sync + 'static, + N: Fn(io::Error) -> E + Unpin + Send + Sync + 'static, + A: Handler + Handler, + T: Send + 'static, + E: Send + 'static; + + fn write( + &mut self, + write: W, + data: Vec, + map: M, + map_err: N, + ) where + W: AsyncWrite + Unpin + Send + 'static, + M: Fn((Vec, usize), W) -> T + Unpin + Send + Sync + 'static, + N: Fn(io::Error) -> E + Unpin + Send + Sync + 'static, + A: Handler + Handler, + T: Send + 'static, + E: Send + 'static; } pub enum Work { diff --git a/aktoro-raw/src/message.rs b/aktoro-raw/src/message.rs index ff7e85e..f32b770 100644 --- a/aktoro-raw/src/message.rs +++ b/aktoro-raw/src/message.rs @@ -2,15 +2,11 @@ use std::pin::Pin; use std::task::Context as FutContext; use std::task::Poll; -use futures_io::Error as FutIOError; - use crate::actor::Actor; -pub type AsyncMessageFutOutput = Box>; - -pub type AsyncMessageStreamItem = Option>>; +pub type AsyncMessageOutput = Box>; -pub type AsyncReadStreamItem = Result>, FutIOError>; +pub type AsyncMessageItem = Option>>; pub trait Message: Send { type Actor: Actor; @@ -28,7 +24,7 @@ pub trait AsyncMessageFut: Send { fn poll( self: Pin<&mut Self>, ctx: &mut FutContext, - ) -> Poll>; + ) -> Poll>; } pub trait AsyncMessageStream: Send { @@ -37,7 +33,7 @@ pub trait AsyncMessageStream: Send { fn poll_next( self: Pin<&mut Self>, ctx: &mut FutContext, - ) -> Poll>; + ) -> Poll>; } pub trait AsyncReadStream: Send { @@ -46,7 +42,7 @@ pub trait AsyncReadStream: Send { fn poll_read( self: Pin<&mut Self>, ctx: &mut FutContext, - ) -> Poll>; + ) -> Poll>; } pub trait Handler: Actor { @@ -56,3 +52,11 @@ pub trait Handler: Actor { /// eventually containing the message's output. fn handle(&mut self, msg: M, ctx: &mut Self::Context) -> Result; } + +impl Handler<()> for A { + type Output = (); + + fn handle(&mut self, _: (), _: &mut Self::Context) -> Result<(), Self::Error> { + Ok(()) + } +} diff --git a/aktoro-raw/src/tcp.rs b/aktoro-raw/src/tcp.rs index 0cc4dac..b4c56c9 100644 --- a/aktoro-raw/src/tcp.rs +++ b/aktoro-raw/src/tcp.rs @@ -11,7 +11,7 @@ pub type TcpServerIncoming<'s, S, E> = Box> + Unp pub type OwnedTcpServerIncoming = Box> + Unpin + Send>; pub trait TcpClient: TcpStream + Unpin + Send + Sized { - type Connect: Future::Error>>; + type Connect: Future::Error>> + Unpin + Send; type Error: StdError + Send; From 37e91070801a233f05e6590bcc5690ecdf59264c Mon Sep 17 00:00:00 2001 From: Matthieu Le Brazidec Date: Wed, 10 Jul 2019 19:31:44 +0200 Subject: [PATCH 06/22] Fixed polling bugs. - If the `Spawned` linked to an actor was dropped, the actor coudln't notify the runtime that it stopped. --- aktoro-runtime/src/actor.rs | 17 +++++++++++------ aktoro-runtime/src/runtime.rs | 14 +++++++++++--- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/aktoro-runtime/src/actor.rs b/aktoro-runtime/src/actor.rs index 1e199a8..d1202b3 100644 --- a/aktoro-runtime/src/actor.rs +++ b/aktoro-runtime/src/actor.rs @@ -139,19 +139,24 @@ impl Actor { // dead. self.ctx.set_status(A::Status::dead()); + // We try to notify the actor's + // death over the killed channel. + if let Err(err) = self.killed.killed(self.id) { + return Err(Box::new(err).into()); + } + // We try to push the actor's // new status over its update // channel. + // NOTE: this is done after sending + // the death notification because + // if the `Spanwed` linked to + // this actor has been dropped, + // it will return an error. if let Err(err) = self.ctx.update() { return Err(Box::new(err).into()); } - // We try to notify the actor's - // death over the killed channel. - if let Err(err) = self.killed.killed(self.id) { - return Err(Box::new(err).into()); - } - Ok(()) } } diff --git a/aktoro-runtime/src/runtime.rs b/aktoro-runtime/src/runtime.rs index 0bd0a6d..908b902 100644 --- a/aktoro-runtime/src/runtime.rs +++ b/aktoro-runtime/src/runtime.rs @@ -177,12 +177,20 @@ impl Future for Wait { } // We remove the dead actors. - for actor in remove { - if rt.actors.remove(&actor).is_none() { - wait.errors.push(Error::already_removed(actor)); + for actor in &remove { + if rt.actors.remove(actor).is_none() { + wait.errors.push(Error::already_removed(*actor)); } } + // We restart the loop if actors + // were removed in case other + // actors stopped in the mean + // time. + if remove.len() > 0 { + continue; + } + // We try to poll from the actors' // kill channel's receiver. match Pin::new(&mut rt.recver).poll_next(ctx) { From 5d193fa198af9ed86121f9a2eb889987389079a0 Mon Sep 17 00:00:00 2001 From: Matthieu Le Brazidec Date: Wed, 10 Jul 2019 19:36:04 +0200 Subject: [PATCH 07/22] Updated the network example. --- examples/net/Cargo.toml | 3 +- examples/net/src/main.rs | 123 ++++++++++++++++++++++++++++++--------- 2 files changed, 98 insertions(+), 28 deletions(-) diff --git a/examples/net/Cargo.toml b/examples/net/Cargo.toml index 13f153c..6c57892 100644 --- a/examples/net/Cargo.toml +++ b/examples/net/Cargo.toml @@ -6,7 +6,8 @@ authors = ["Matthieu Le Brazidec "] edition = "2018" [dependencies] -runtime = "0.3.0-alpha.6" +futures-io-preview = "0.3.0-alpha.17" +runtime = "0.3.0-alpha.6" [dependencies.aktoro] path = "../.." diff --git a/examples/net/src/main.rs b/examples/net/src/main.rs index 73ba6c1..adc793d 100644 --- a/examples/net/src/main.rs +++ b/examples/net/src/main.rs @@ -1,17 +1,40 @@ #![feature(async_await)] -use std::task::Poll; - use aktoro::prelude::*; use aktoro::raw; -use futures_util::poll; +use futures_util::io::AsyncReadExt; +use futures_util::io::WriteHalf; + +struct Client { + connect: Option, + write: Option>, +} struct Server { tcp: Option, } -struct Connection { - stream: S::Stream, +struct Connected(C); + +struct Connection(S::Stream); + +struct Sent(WriteHalf); + +struct Received(Vec); + +impl Actor for Client +where + C: raw::TcpClient + 'static, +{ + type Context = Context; + type Status = Status; + type Error = Error; + + fn started(&mut self, ctx: &mut Self::Context) { + let connect = self.connect.take().unwrap(); + + ctx.wait(connect, |client| Connected(client.unwrap())); + } } impl Actor for Server @@ -23,23 +46,76 @@ where type Error = Error; fn started(&mut self, ctx: &mut Self::Context) { - println!("started"); - ctx.subscribe(self.tcp.take().unwrap().into_incoming().unwrap(), |conn| { - Connection { - stream: conn.unwrap(), - } + let tcp = self.tcp.take().unwrap(); + println!("listening on {}", tcp.local_addr().unwrap()); + + ctx.subscribe(tcp.into_incoming().unwrap(), |conn| { + Connection(conn.unwrap()) }); } } +impl Handler> for Client +where + C: raw::TcpClient + 'static, +{ + type Output = (); + + fn handle(&mut self, msg: Connected, ctx: &mut Self::Context) -> Result<(), Self::Error> { + let client = msg.0; + println!("connected to {}", client.peer_addr().unwrap()); + + let (_, write) = client.split(); + ctx.write(write, vec![0], |_, write| Sent(write), |_| ()); + + Ok(()) + } +} + impl Handler> for Server where S: raw::TcpServer + 'static, { type Output = (); - fn handle(&mut self, msg: Connection, ctx: &mut Context) -> Result<(), Self::Error> { - println!("new connection"); + fn handle(&mut self, msg: Connection, ctx: &mut Self::Context) -> Result<(), Self::Error> { + let conn = msg.0; + println!("new connection from {}", conn.peer_addr().unwrap()); + + let (read, _) = conn.split(); + ctx.read(read, 64, |data| Received(data), |_| ()); + + Ok(()) + } +} + +impl Handler> for Client +where + C: raw::TcpClient + 'static, +{ + type Output = (); + + fn handle(&mut self, sent: Sent, ctx: &mut Self::Context) -> Result<(), Self::Error> { + println!("sent data"); + self.write = Some(sent.0); + + ctx.set_status(Status::Stopped); + + Ok(()) + } +} + +impl Handler for Server +where + S: raw::TcpServer + 'static, +{ + type Output = (); + + fn handle(&mut self, msg: Received, ctx: &mut Self::Context) -> Result<(), Self::Error> { + println!("received {:?}", msg.0); + + ctx.set_status(Status::Stopped); + Ok(()) } } @@ -55,21 +131,14 @@ async fn main() { rt.spawn(server).unwrap(); - let mut run = runtime::spawn(run(net)); - let mut wait = rt.wait(); - - loop { - if let Poll::Ready(_) = poll!(&mut run) { - break; - } + let client = Client:: { + connect: Some(net.tcp_connect("127.0.0.1:5555").unwrap()), + write: None, + }; - if let Poll::Ready(res) = poll!(&mut wait) { - res.expect("an error occured while waiting for the runtime to stop"); - break; - } - } -} + rt.spawn(client).unwrap(); -async fn run(net: N) { - loop {} + rt.wait() + .await + .expect("an error occured while waiting for the runtime to stop"); } From b2ceef3bc442b111e6852cc557dfd902a67f4d55 Mon Sep 17 00:00:00 2001 From: Matthieu Le Brazidec Date: Wed, 10 Jul 2019 19:38:47 +0200 Subject: [PATCH 08/22] Formatting. --- aktoro-context/src/context.rs | 26 +++++++++----------------- aktoro-context/src/message.rs | 20 ++++++++------------ aktoro-raw/src/context.rs | 20 +++++--------------- aktoro-raw/src/message.rs | 11 +++-------- aktoro-runtime/src/runtime.rs | 2 +- examples/net/src/main.rs | 2 +- 6 files changed, 27 insertions(+), 54 deletions(-) diff --git a/aktoro-context/src/context.rs b/aktoro-context/src/context.rs index f06d5c2..13a181e 100644 --- a/aktoro-context/src/context.rs +++ b/aktoro-context/src/context.rs @@ -164,13 +164,8 @@ where .push(Box::pin(AsyncMessageStream::new(stream.map(map)))); } - fn read( - &mut self, - read: R, - cap: usize, - map: M, - map_err: N, - ) where + fn read(&mut self, read: R, cap: usize, map: M, map_err: N) + where R: AsyncRead + Unpin + Send + 'static, M: Fn(Vec) -> T + Unpin + Send + Sync + 'static, N: Fn(io::Error) -> E + Unpin + Send + Sync + 'static, @@ -178,24 +173,21 @@ where T: Send + 'static, E: Send + 'static, { - self.reads.push(Box::pin(AsyncReadStream::new(read, cap, map, map_err))); + self.reads + .push(Box::pin(AsyncReadStream::new(read, cap, map, map_err))); } - fn write( - &mut self, - write: W, - data: Vec, - map: M, - map_err: N, - ) where + fn write(&mut self, write: W, data: Vec, map: M, map_err: N) + where W: AsyncWrite + Unpin + Send + 'static, - M: Fn((Vec, usize), W) -> T + Unpin + Send + Sync + 'static, + M: Fn((Vec, usize), W) -> T + Unpin + Send + Sync + 'static, N: Fn(io::Error) -> E + Unpin + Send + Sync + 'static, A: raw::Handler + raw::Handler, T: Send + 'static, E: Send + 'static, { - self.futs.push(Box::pin(AsyncWriteFut::new(write, data, map, map_err))); + self.futs + .push(Box::pin(AsyncWriteFut::new(write, data, map, map_err))); } } diff --git a/aktoro-context/src/message.rs b/aktoro-context/src/message.rs index b8d7ddc..4c5b412 100644 --- a/aktoro-context/src/message.rs +++ b/aktoro-context/src/message.rs @@ -154,12 +154,9 @@ where E: Send, { pub(crate) fn new(read: R, cap: usize, map: M, map_err: N) -> Self { - let mut buf = Vec::with_capacity(cap); - buf.resize(cap, 0); - AsyncReadStream { cap, - buf, + buf: vec![0; cap], read, map, map_err, @@ -172,7 +169,7 @@ impl AsyncWriteFut where A: raw::Handler + raw::Handler, W: AsyncWrite + Unpin + Send, - M: Fn((Vec, usize), W) -> T + Unpin + Send + Sync, + M: Fn((Vec, usize), W) -> T + Unpin + Send + Sync, N: Fn(io::Error) -> E + Unpin + Send + Sync, T: Send, E: Send, @@ -232,7 +229,10 @@ where { type Actor = A; - fn poll(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll> { + fn poll( + self: Pin<&mut Self>, + ctx: &mut FutContext, + ) -> Poll> { match Pin::new(&mut self.get_mut().fut).poll(ctx) { Poll::Ready(msg) => Poll::Ready(Box::new(AsyncMessage::new(msg))), Poll::Pending => Poll::Pending, @@ -313,14 +313,10 @@ where ) -> Poll> { let fut = self.get_mut(); - match Pin::new(&mut fut.write.as_mut().unwrap()) - .poll_write(ctx, fut.data.as_ref().unwrap()) + match Pin::new(&mut fut.write.as_mut().unwrap()).poll_write(ctx, fut.data.as_ref().unwrap()) { Poll::Ready(Ok(wrote)) => { - let msg = (fut.map)( - (fut.data.take().unwrap(), wrote), - fut.write.take().unwrap(), - ); + let msg = (fut.map)((fut.data.take().unwrap(), wrote), fut.write.take().unwrap()); Poll::Ready(Box::new(AsyncMessage::new(msg))) } diff --git a/aktoro-raw/src/context.rs b/aktoro-raw/src/context.rs index e07071b..3034efe 100644 --- a/aktoro-raw/src/context.rs +++ b/aktoro-raw/src/context.rs @@ -82,13 +82,8 @@ pub trait Context: Unpin + Send + 'static + Stream> { A: Handler, T: Send + 'static; - fn read( - &mut self, - read: R, - cap: usize, - map: M, - map_err: N, - ) where + fn read(&mut self, read: R, cap: usize, map: M, map_err: N) + where R: AsyncRead + Unpin + Send + 'static, M: Fn(Vec) -> T + Unpin + Send + Sync + 'static, N: Fn(io::Error) -> E + Unpin + Send + Sync + 'static, @@ -96,15 +91,10 @@ pub trait Context: Unpin + Send + 'static + Stream> { T: Send + 'static, E: Send + 'static; - fn write( - &mut self, - write: W, - data: Vec, - map: M, - map_err: N, - ) where + fn write(&mut self, write: W, data: Vec, map: M, map_err: N) + where W: AsyncWrite + Unpin + Send + 'static, - M: Fn((Vec, usize), W) -> T + Unpin + Send + Sync + 'static, + M: Fn((Vec, usize), W) -> T + Unpin + Send + Sync + 'static, N: Fn(io::Error) -> E + Unpin + Send + Sync + 'static, A: Handler + Handler, T: Send + 'static, diff --git a/aktoro-raw/src/message.rs b/aktoro-raw/src/message.rs index f32b770..597474b 100644 --- a/aktoro-raw/src/message.rs +++ b/aktoro-raw/src/message.rs @@ -21,19 +21,14 @@ pub trait Message: Send { pub trait AsyncMessageFut: Send { type Actor: Actor; - fn poll( - self: Pin<&mut Self>, - ctx: &mut FutContext, - ) -> Poll>; + fn poll(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll>; } pub trait AsyncMessageStream: Send { type Actor: Actor; - fn poll_next( - self: Pin<&mut Self>, - ctx: &mut FutContext, - ) -> Poll>; + fn poll_next(self: Pin<&mut Self>, ctx: &mut FutContext) + -> Poll>; } pub trait AsyncReadStream: Send { diff --git a/aktoro-runtime/src/runtime.rs b/aktoro-runtime/src/runtime.rs index 908b902..b6d131b 100644 --- a/aktoro-runtime/src/runtime.rs +++ b/aktoro-runtime/src/runtime.rs @@ -187,7 +187,7 @@ impl Future for Wait { // were removed in case other // actors stopped in the mean // time. - if remove.len() > 0 { + if !remove.is_empty() { continue; } diff --git a/examples/net/src/main.rs b/examples/net/src/main.rs index adc793d..000376f 100644 --- a/examples/net/src/main.rs +++ b/examples/net/src/main.rs @@ -83,7 +83,7 @@ where println!("new connection from {}", conn.peer_addr().unwrap()); let (read, _) = conn.split(); - ctx.read(read, 64, |data| Received(data), |_| ()); + ctx.read(read, 64, Received, |_| ()); Ok(()) } From 42f02457ae93adb291665c28215214f70b9c3834 Mon Sep 17 00:00:00 2001 From: Matthieu Le Brazidec Date: Thu, 11 Jul 2019 11:32:03 +0200 Subject: [PATCH 09/22] Added a way for actors to spawn other actors. --- aktoro-context/src/channel.rs | 2 +- aktoro-context/src/context.rs | 65 +++++++++++-- aktoro-context/src/control.rs | 2 +- aktoro-context/src/message.rs | 8 +- aktoro-context/src/update.rs | 148 ++++++++++++++++++++++++++-- aktoro-raw/src/actor.rs | 6 +- aktoro-raw/src/channel.rs | 6 +- aktoro-raw/src/context.rs | 19 +++- aktoro-raw/src/control.rs | 6 +- aktoro-raw/src/net.rs | 2 +- aktoro-raw/src/runtime.rs | 45 ++++----- aktoro-raw/src/spawned.rs | 21 ++-- aktoro-raw/src/tcp.rs | 6 +- aktoro-raw/src/udp.rs | 4 +- aktoro-raw/src/update.rs | 22 +++-- aktoro-runtime/src/actor.rs | 7 +- aktoro-runtime/src/runtime.rs | 177 +++++++++++++--------------------- 17 files changed, 351 insertions(+), 195 deletions(-) diff --git a/aktoro-context/src/channel.rs b/aktoro-context/src/channel.rs index 7ac822c..f1faf0a 100644 --- a/aktoro-context/src/channel.rs +++ b/aktoro-context/src/channel.rs @@ -40,7 +40,7 @@ pub(crate) fn new() -> (Sender, Receiver) { impl raw::Sender for Sender where - A: raw::Actor, + A: raw::Actor + 'static, { type Receiver = Receiver; diff --git a/aktoro-context/src/context.rs b/aktoro-context/src/context.rs index 13a181e..fe9ead2 100644 --- a/aktoro-context/src/context.rs +++ b/aktoro-context/src/context.rs @@ -7,6 +7,7 @@ use std::task::Poll; use aktoro_channel::error::TrySendError; use aktoro_raw as raw; use aktoro_raw::Updater as RawUpdater; +use aktoro_raw::Wait as RawWait; use futures_core::Stream; use futures_io as io; use futures_io::AsyncRead; @@ -26,13 +27,16 @@ use crate::message::AsyncMessageStream; use crate::message::AsyncReadStream; use crate::message::AsyncWriteFut; use crate::update; +use crate::update::Update; use crate::update::Updated; use crate::update::Updater; /// An actor context using the [`aktoro-channel`] crate. /// /// [`aktoro-channel`]: https://docs.rs/aktoro-channel -pub struct Context { +pub struct Context { + // TODO + pub actor_id: u64, /// The actor's current status. status: A::Status, /// An actor's control channel sender. @@ -48,6 +52,8 @@ pub struct Context { streams: Vec>>>, // TODO reads: Vec>>>, + // TODO + rt: Option, /// A list of the actor's unhandled events. events: VecDeque>>, /// An actor's message channel sender. @@ -60,15 +66,16 @@ pub struct Context { updted: Option>, } -impl raw::Context for Context +impl raw::Context for Context where - A: raw::Actor, + A: raw::Actor + 'static, + RT: raw::Runtime, { type Controller = Controller; type Sender = Sender; type Updater = Updater; - fn new() -> Context { + fn new(actor_id: u64) -> Context { // We create the actor's control, message and // update channels. let (ctrler, ctrled) = control::new(); @@ -76,6 +83,7 @@ where let (updter, updted) = update::new(); Context { + actor_id, status: A::Status::default(), ctrler, ctrled, @@ -83,6 +91,7 @@ where futs: Vec::new(), streams: Vec::new(), reads: Vec::new(), + rt: None, events: VecDeque::new(), sender, recver, @@ -110,9 +119,11 @@ where } } - fn update(&mut self) -> Result<(), TrySendError> { + fn update(&mut self) -> Result<(), TrySendError>> { self.update = false; - self.updter.try_send(self.status.clone()) + self.updter.try_send( + Update::new(self.actor_id, self.status.clone()), + ) } fn controller(&self) -> &Controller { @@ -143,6 +154,28 @@ where &mut self.updter } + fn actors(&self) -> Vec { + if let Some(rt) = &self.rt { + rt.actors() + } else { + vec![] + } + } + + fn spawn(&mut self, actor: S) -> Option> + where + S: raw::Actor + 'static, + { + let rt = if let Some(rt) = &mut self.rt { + rt + } else { + self.rt = Some(RT::default()); + self.rt.as_mut().unwrap() + }; + + rt.spawn(actor) + } + fn wait(&mut self, fut: F, map: M) where F: Future + Unpin + Send + 'static, @@ -191,9 +224,10 @@ where } } -impl Stream for Context +impl Stream for Context where A: raw::Actor, + R: raw::Runtime, { type Item = raw::Work; @@ -236,6 +270,23 @@ where Poll::Pending => (), } + // TODO + if let Some(rt) = context.rt.take() { + let mut wait = rt.wait(); + + loop { + if wait.runtime().actors().is_empty() { + break; + } + + if let Poll::Pending = Pin::new(&mut wait).poll_next(ctx) { + break; + } + } + + context.rt = Some(wait.into_runtime()); + } + // TODO for (i, fut) in context.futs.iter_mut().enumerate() { match fut.as_mut().poll(ctx) { diff --git a/aktoro-context/src/control.rs b/aktoro-context/src/control.rs index e1eddf7..205211d 100644 --- a/aktoro-context/src/control.rs +++ b/aktoro-context/src/control.rs @@ -40,7 +40,7 @@ pub(crate) fn new() -> (Controller, Controlled) { impl raw::Controller for Controller where - A: raw::Actor, + A: raw::Actor + 'static, { type Controlled = Controlled; diff --git a/aktoro-context/src/message.rs b/aktoro-context/src/message.rs index 4c5b412..d4095e8 100644 --- a/aktoro-context/src/message.rs +++ b/aktoro-context/src/message.rs @@ -223,7 +223,7 @@ where impl raw::AsyncMessageFut for AsyncMessageFut where - A: raw::Handler, + A: raw::Handler + 'static, F: Future + Unpin + Send, M: Send + 'static, { @@ -242,7 +242,7 @@ where impl raw::AsyncMessageStream for AsyncMessageStream where - A: raw::Handler, + A: raw::Handler + 'static, S: Stream + Unpin + Send, M: Send + 'static, { @@ -262,7 +262,7 @@ where impl raw::AsyncReadStream for AsyncReadStream where - A: raw::Handler + raw::Handler, + A: raw::Handler + raw::Handler + 'static, R: AsyncRead + Unpin + Send, M: Fn(Vec) -> T + Unpin + Send, N: Fn(io::Error) -> E + Unpin + Send, @@ -298,7 +298,7 @@ where impl raw::AsyncMessageFut for AsyncWriteFut where - A: raw::Handler + raw::Handler, + A: raw::Handler + raw::Handler + 'static, W: AsyncWrite + Unpin + Send, M: Fn((Vec, usize), W) -> T + Unpin + Send + Sync, N: Fn(io::Error) -> E + Unpin + Send + Sync, diff --git a/aktoro-context/src/update.rs b/aktoro-context/src/update.rs index 284bed3..8889749 100644 --- a/aktoro-context/src/update.rs +++ b/aktoro-context/src/update.rs @@ -7,17 +7,26 @@ use aktoro_channel::error::TrySendError; use aktoro_raw as raw; use futures_core::Stream; +// TODO +pub struct Update +where + A: raw::Actor, +{ + actor_id: u64, + status: A::Status, +} + /// An actor's update channel sender, used by /// [`Context`]. /// /// [`Context`]: struct.Context.html -pub struct Updater(channel::Sender); +pub struct Updater(channel::Sender>); /// An actor's update channel receiver, used /// by [`Context`]. /// /// [`Context`]: struct.Context.html -pub struct Updated(channel::Receiver); +pub struct Updated(channel::Receiver>); /// Creates a new control channel for the /// specified actor type, returning a sender @@ -35,28 +44,149 @@ pub(crate) fn new() -> (Updater, Updated) { (Updater(sender), Updated(recver)) } -impl raw::Updater for Updater +impl Update +where + A: raw::Actor, +{ + pub(crate) fn new(actor_id: u64, status: A::Status) -> Self { + Update { + actor_id, + status, + } + } +} + +impl raw::Status for Update where A: raw::Actor, { + fn starting() -> Self { + Update { + actor_id: !0, + status: A::Status::starting(), + } + } + + fn started() -> Self { + Update { + actor_id: !0, + status: A::Status::started(), + } + } + + fn stopping() -> Self { + Update { + actor_id: !0, + status: A::Status::stopping(), + } + } + + fn stopped() -> Self { + Update { + actor_id: !0, + status: A::Status::stopped(), + } + } + + fn dead() -> Self { + Update { + actor_id: !0, + status: A::Status::dead(), + } + } + + fn is_starting(&self) -> bool { + self.status.is_starting() + } + + fn is_started(&self) -> bool { + self.status.is_started() + } + + fn is_stopping(&self) -> bool { + self.status.is_stopping() + } + + fn is_stopped(&self) -> bool { + self.status.is_stopped() + } + + fn is_dead(&self) -> bool { + self.status.is_dead() + } +} + +impl raw::Update for Update +where + A: raw::Actor, +{ + fn actor_id(&self) -> u64 { + self.actor_id + } + + fn set_actor_id(&mut self, id: u64) { + self.actor_id = id; + } +} + +impl raw::Updater for Updater +where + A: raw::Actor + 'static, +{ + type Update = Update; + type Updated = Updated; - type Error = TrySendError; + type Error = TrySendError>; - fn try_send(&mut self, status: A::Status) -> Result<(), Self::Error> { - self.0.try_send(status) + fn try_send(&mut self, update: Update) -> Result<(), Self::Error> { + self.0.try_send(update) } } -impl raw::Updated for Updated {} +impl raw::Updated> for Updated {} impl Stream for Updated where A: raw::Actor, { - type Item = A::Status; + type Item = Update; - fn poll_next(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll> { + fn poll_next(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll>> { Pin::new(&mut self.get_mut().0).poll_next(ctx) } } + +impl PartialEq for Update +where + A: raw::Actor, +{ + fn eq(&self, other: &Self) -> bool { + self.actor_id == other.actor_id && + self.status == other.status + } +} + +impl Default for Update +where + A: raw::Actor, +{ + fn default() -> Self { + Update { + actor_id: !0, + status: A::Status::default(), + } + } +} + +impl Clone for Update +where + A: raw::Actor, +{ + fn clone(&self) -> Self { + Update { + actor_id: self.actor_id, + status: self.status.clone(), + } + } +} diff --git a/aktoro-raw/src/actor.rs b/aktoro-raw/src/actor.rs index 6f6a341..67e4e9a 100644 --- a/aktoro-raw/src/actor.rs +++ b/aktoro-raw/src/actor.rs @@ -2,12 +2,12 @@ use std::error::Error as StdError; use crate::context::Context; -pub trait Actor: Unpin + Send + Sized + 'static { +pub trait Actor: Unpin + Send + Sized { type Context: Context; type Status: Status + Unpin; - type Error: StdError + Send; + type Error: StdError + Send + 'static; #[allow(unused)] /// Called when the actor's context has been created @@ -30,7 +30,7 @@ pub trait Actor: Unpin + Send + Sized + 'static { fn stopped(&mut self, ctx: &mut Self::Context) {} } -pub trait Status: PartialEq + Default + Clone + Send { +pub trait Status: PartialEq + Default + Clone + Unpin + Send { /// Returns the status that an actor should have /// before [`Actor::starting`] is called. /// diff --git a/aktoro-raw/src/channel.rs b/aktoro-raw/src/channel.rs index fd98b03..f8feab3 100644 --- a/aktoro-raw/src/channel.rs +++ b/aktoro-raw/src/channel.rs @@ -16,10 +16,10 @@ use crate::message::Message; /// [`Sender::try_send`]: trait.Sender.html#method.try_send pub type SenderRes<'s, O, E> = Result>, E>; -pub trait Sender: Clone { +pub trait Sender: Unpin + Clone + Send { type Receiver: Receiver; - type Error: StdError + Send; + type Error: StdError + Send + 'static; /// Tries to send a message to be handled by the /// actor. @@ -29,4 +29,4 @@ pub trait Sender: Clone { M: Send + 'static; } -pub trait Receiver: Stream>> {} +pub trait Receiver: Stream>> + Unpin + Send {} diff --git a/aktoro-raw/src/context.rs b/aktoro-raw/src/context.rs index 3034efe..7e505a1 100644 --- a/aktoro-raw/src/context.rs +++ b/aktoro-raw/src/context.rs @@ -13,15 +13,16 @@ use crate::event::Event; use crate::event::EventHandler; use crate::message::Handler; use crate::message::Message; +use crate::spawned::Spawned; use crate::update::Updater; -pub trait Context: Unpin + Send + 'static + Stream> { +pub trait Context: Stream> + Unpin + Send { type Controller: Controller; type Sender: Sender; type Updater: Updater; - /// Creates a new context for an actor. - fn new() -> Self; + // TODO + fn new(actor_id: u64) -> Self; /// Emits an event that will be handled by the /// actor. @@ -68,6 +69,15 @@ pub trait Context: Unpin + Send + 'static + Stream> { /// update channel receiver. fn updater(&mut self) -> &mut Self::Updater; + // TODO + fn actors(&self) -> Vec; + + // TODO + fn spawn(&mut self, actor: S) -> Option> + where + S: Actor + 'static; + + // TODO fn wait(&mut self, fut: F, map: M) where F: Future + Unpin + Send + 'static, @@ -75,6 +85,7 @@ pub trait Context: Unpin + Send + 'static + Stream> { A: Handler, T: Send + 'static; + // TODO fn subscribe(&mut self, stream: S, map: M) where S: Stream + Unpin + Send + 'static, @@ -82,6 +93,7 @@ pub trait Context: Unpin + Send + 'static + Stream> { A: Handler, T: Send + 'static; + // TODO fn read(&mut self, read: R, cap: usize, map: M, map_err: N) where R: AsyncRead + Unpin + Send + 'static, @@ -91,6 +103,7 @@ pub trait Context: Unpin + Send + 'static + Stream> { T: Send + 'static, E: Send + 'static; + // TODO fn write(&mut self, write: W, data: Vec, map: M, map_err: N) where W: AsyncWrite + Unpin + Send + 'static, diff --git a/aktoro-raw/src/control.rs b/aktoro-raw/src/control.rs index f8f6d23..39e0338 100644 --- a/aktoro-raw/src/control.rs +++ b/aktoro-raw/src/control.rs @@ -16,10 +16,10 @@ use crate::actor::Actor; /// [`Controller::try_send`]: trait.Controller.html#method.try_send pub type ControllerRes<'c, O, E> = Result>, E>; -pub trait Controller: Clone { +pub trait Controller: Unpin + Clone + Send { type Controlled: Controlled; - type Error: StdError + Send; + type Error: StdError + Send + 'static; /// Tries to send an action to be handled by the /// actor. @@ -29,4 +29,4 @@ pub trait Controller: Clone { D: Send + 'static; } -pub trait Controlled: Stream>> {} +pub trait Controlled: Stream>> + Unpin + Send {} diff --git a/aktoro-raw/src/net.rs b/aktoro-raw/src/net.rs index a7f56d5..89eed4a 100644 --- a/aktoro-raw/src/net.rs +++ b/aktoro-raw/src/net.rs @@ -10,7 +10,7 @@ type TcpBindRes = Result::Error>; type UdpBindRes = Result::Error>; -pub trait NetworkManager: Unpin + Send + Sync { +pub trait NetworkManager: Unpin + Send { /// The type of the TCP socket client /// that actors can use to be compatible /// with the runtime (this might not be diff --git a/aktoro-raw/src/runtime.rs b/aktoro-raw/src/runtime.rs index a219e37..29eaffa 100644 --- a/aktoro-raw/src/runtime.rs +++ b/aktoro-raw/src/runtime.rs @@ -1,11 +1,18 @@ use std::error::Error as StdError; -use std::future::Future; + +use futures_core::Stream; use crate::actor::Actor; use crate::net::NetworkManager; use crate::spawned::Spawned; -pub trait Runtime { +pub trait Wait: Stream> + Unpin + Send { + fn runtime(&self) -> &R; + + fn into_runtime(self) -> R; +} + +pub trait Runtime: Default + Unpin + Send { /// The type that is handling the types of /// the TCP socket client and server and /// of the UDP socket that actors can use @@ -14,21 +21,13 @@ pub trait Runtime { /// runtime implementation). type NetworkManager: NetworkManager; - /// The future returned after calling the - /// [`stop`] method. It will resolve after - /// all the actors have been stopped. - /// - /// [`stop`]: #method.stop - type Stop: Future>; + // TODO + type Wait: Wait; - /// The future returned after calling the - /// [`wait`] method. It will resolve after - /// all the actors have been stopped. - /// - /// [`wait`]: #method.wait - type Wait: Future>; + type Error: StdError + Send + 'static; - type Error: StdError + Send; + // TODO + fn actors(&self) -> Vec; /// Spawns a new actor on the runtime, /// returning [`Some(Spawned)`] if it @@ -38,7 +37,9 @@ pub trait Runtime { /// /// [`Some(Spawned)`]: sturct.Spawned.html /// [`Actor::starting`]: trait.Actor.html#method.starting - fn spawn(&mut self, actor: A) -> Option>; + fn spawn(&mut self, actor: A) -> Option> + where + A: Actor + 'static; /// Creates a new network manager, that /// can then be used by an actor to @@ -46,13 +47,9 @@ pub trait Runtime { /// an UDP socket. fn net(&mut self) -> Self::NetworkManager; - /// Asks to all the actors managed by the - /// runtime to stop, returning a future - /// resolving after all of them have been - /// stopped. - fn stop(self) -> Self::Stop; - - /// Waits for all the actors to be stopped, - /// returning a future waiting for it. + // TODO fn wait(self) -> Self::Wait; + + // TODO + fn stop(&mut self); } diff --git a/aktoro-raw/src/spawned.rs b/aktoro-raw/src/spawned.rs index a1e490c..3bf8a96 100644 --- a/aktoro-raw/src/spawned.rs +++ b/aktoro-raw/src/spawned.rs @@ -20,21 +20,25 @@ type SenderError = as RawSender>::Error; type Controller = <::Context as Context>::Controller; type ControllerError = as RawController>::Error; +type Update = <<::Context as Context>::Updater as Updater>::Update; type Updated = <<::Context as Context>::Updater as Updater>::Updated; /// A wrapper around an actor's /// message, control and update /// channels. pub struct Spawned { + // TODO sender: Sender, + // TODO ctrler: Controller, + // TODO updted: Option>, } impl Spawned { /// Creates a new `Spawned` struct from an actor's /// context. - pub fn new(ctx: &mut A::Context) -> Spawned { + pub fn new(ctx: &mut A::Context) -> Self { Spawned { sender: ctx.sender().clone(), ctrler: ctx.controller().clone(), @@ -96,14 +100,10 @@ impl Spawned { impl Unpin for Spawned {} -impl Stream for Spawned -where - A: Actor, - Updated: Unpin, -{ - type Item = A::Status; +impl Stream for Spawned { + type Item = Update; - fn poll_next(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll> { + fn poll_next(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll>> { if let Some(updted) = &mut self.get_mut().updted { Pin::new(updted).poll_next(ctx) } else { @@ -112,10 +112,7 @@ where } } -impl Clone for Spawned -where - A: Actor, -{ +impl Clone for Spawned { fn clone(&self) -> Self { Spawned { sender: self.sender.clone(), diff --git a/aktoro-raw/src/tcp.rs b/aktoro-raw/src/tcp.rs index b4c56c9..9e10950 100644 --- a/aktoro-raw/src/tcp.rs +++ b/aktoro-raw/src/tcp.rs @@ -13,7 +13,7 @@ pub type OwnedTcpServerIncoming = Box> + Un pub trait TcpClient: TcpStream + Unpin + Send + Sized { type Connect: Future::Error>> + Unpin + Send; - type Error: StdError + Send; + type Error: StdError + Send + 'static; /// Tries to connect to a TCP server at the /// given address. @@ -23,7 +23,7 @@ pub trait TcpClient: TcpStream + Unpin + Send + Sized { pub trait TcpServer: Unpin + Send + Sized { type Stream: TcpStream; - type Error: StdError + Send; + type Error: StdError + Send + 'static; /// Tries to create a new TCP server that /// will be bound to the given address. @@ -43,7 +43,7 @@ pub trait TcpServer: Unpin + Send + Sized { } pub trait TcpStream: AsyncRead + AsyncWrite + Unpin + Send { - type Error: StdError + Send; + type Error: StdError + Send + 'static; /// Returns the address that the server /// is bound to. diff --git a/aktoro-raw/src/udp.rs b/aktoro-raw/src/udp.rs index 06a4ba6..e39c362 100644 --- a/aktoro-raw/src/udp.rs +++ b/aktoro-raw/src/udp.rs @@ -8,8 +8,8 @@ pub type UdpSocketSendTo<'s, E> = Box> + 's pub type UdpSocketRecv<'s, E> = Box> + 's>; -pub trait UdpSocket: Unpin + Send + Sized + 'static { - type Error: StdError + Send; +pub trait UdpSocket: Unpin + Send + Sized { + type Error: StdError + Send + 'static; /// Tries to create a new UDP socket that /// will be bound to the given address. diff --git a/aktoro-raw/src/update.rs b/aktoro-raw/src/update.rs index 66d0ccc..bba7589 100644 --- a/aktoro-raw/src/update.rs +++ b/aktoro-raw/src/update.rs @@ -3,15 +3,23 @@ use std::error::Error as StdError; use futures_core::Stream; use crate::actor::Actor; +use crate::actor::Status; -pub trait Updater { - type Updated: Updated; +pub trait Update: Status + Unpin + Send { + fn actor_id(&self) -> u64; - type Error: StdError + Send; + fn set_actor_id(&mut self, id: u64); +} + +pub trait Updater: Unpin + Send { + type Update: Update; + + type Updated: Updated; + + type Error: StdError + Send + 'static; - /// Tries to send a status update over - /// the actor's update channel. - fn try_send(&mut self, status: A::Status) -> Result<(), Self::Error>; + // TODO + fn try_send(&mut self, update: Self::Update) -> Result<(), Self::Error>; } -pub trait Updated: Stream {} +pub trait Updated: Stream + Unpin + Send {} diff --git a/aktoro-runtime/src/actor.rs b/aktoro-runtime/src/actor.rs index d1202b3..a10f705 100644 --- a/aktoro-runtime/src/actor.rs +++ b/aktoro-runtime/src/actor.rs @@ -26,7 +26,7 @@ pub(crate) struct Actor { killed: KilledSender, } -#[derive(Eq, PartialEq, Debug, Clone)] +#[derive(PartialEq, Debug, Clone)] /// A default implementation for the /// [`aktoro-raw::Status`] trait. /// @@ -221,7 +221,10 @@ impl KilledSender { } } -impl Future for Actor { +impl Future for Actor +where + A: raw::Actor + 'static, +{ type Output = Result<(), Error>; fn poll(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll { diff --git a/aktoro-runtime/src/runtime.rs b/aktoro-runtime/src/runtime.rs index b6d131b..ce7eadf 100644 --- a/aktoro-runtime/src/runtime.rs +++ b/aktoro-runtime/src/runtime.rs @@ -41,19 +41,8 @@ pub struct Runtime { rng: Xoshiro512StarStar, } -/// A future that resolves when all the -/// runtime's actors have been stopped. -pub struct Stop(Wait); - -/// A future that resolves when all the -/// runtime's actors have been stopped. -pub struct Wait { - rt: Runtime, - /// Contains a list of all the errors - /// that happened while waiting for - /// the actors to stop. - errors: Vec, -} +// TODO +pub struct Wait(Runtime); impl Runtime { /// Creates a new `Runtime`. @@ -65,22 +54,28 @@ impl Runtime { impl raw::Runtime for Runtime { type NetworkManager = NetworkManager; - type Stop = Stop; type Wait = Wait; type Error = Error; - fn spawn(&mut self, actor: A) -> Option> { + fn actors(&self) -> Vec { + self.actors.keys().copied().collect() + } + + fn spawn(&mut self, actor: A) -> Option> + where + A: raw::Actor + 'static, + { + // Generate the actor's ID. + let id = self.rng.next_u64(); + // Create a new context for the actor. - let mut ctx = A::Context::new(); + let mut ctx = A::Context::new(id); // Create a new `Spawned` struct from // the actor's context. let spawned = raw::Spawned::new(&mut ctx); - // Generate the actor's ID. - let id = self.rng.next_u64(); - // Create the actor's kill channel. let (sender, recver) = actor::new_kill(); @@ -102,117 +97,79 @@ impl raw::Runtime for Runtime { NetworkManager } - /// Asks to all the actors managed by the - /// runtime to stop, returning a future - /// resolving after all of them have been - /// stopped. - /// - /// ## Note - /// - /// Calling this method and polling the - /// returned future might be required to - /// poll the actors a first time, making - /// this method kind of useless if that's - /// the case. - fn stop(mut self) -> Stop { - // Ask for each actor to stop. - for (_, actor) in self.actors.iter_mut() { - actor.0.kill(); - } - - Stop(self.wait()) + // TODO + fn wait(self) -> Wait { + Wait(self) } - /// Waits for all the actors to be stopped, - /// returning a future waiting for it. - /// - /// ## Note - /// - /// Calling this method and polling the - /// returned future might be required to - /// poll the actors a first time. - fn wait(self) -> Wait { - Wait { - rt: self, - errors: vec![], + // TODO + fn stop(&mut self) { + // Ask to every actor to stop. + for (_, actor) in self.actors.iter_mut() { + actor.0.kill(); } } } -impl Future for Stop { - type Output = Result<(), Error>; +impl raw::Wait for Wait { + fn runtime(&self) -> &Runtime { + &self.0 + } - fn poll(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll> { - // `Stop` is just a wrapper - // arround `Wait` (what differs - // is what happens before it - // is returned by the `stop` - // method). - Pin::new(&mut self.get_mut().0).poll(ctx) + fn into_runtime(self) -> Runtime { + self.0 } } -impl Future for Wait { - type Output = Result<(), Error>; +impl Stream for Wait { + type Item = Result; - fn poll(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll> { - let wait = self.get_mut(); - let rt = &mut wait.rt; + fn poll_next(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll>> { + let rt = &mut self.get_mut().0; - loop { - if rt.actors.is_empty() { - return Poll::Ready(Ok(())); - } - - // We poll all the actors' handle. - let mut remove = vec![]; - for (id, act) in rt.actors.iter_mut() { - if let Poll::Ready(res) = Pin::new(&mut act.1).poll(ctx) { - remove.push(*id); - - if let Err(err) = res { - wait.errors.push(err); - } - } - } + if rt.actors.is_empty() { + return Poll::Ready(None); + } - // We remove the dead actors. - for actor in &remove { - if rt.actors.remove(actor).is_none() { - wait.errors.push(Error::already_removed(*actor)); - } + // TODO + let mut remove = None; + for (id, act) in rt.actors.iter_mut() { + if let Poll::Ready(res) = Pin::new(&mut act.1).poll(ctx) { + remove = Some((*id, res)); } + } - // We restart the loop if actors - // were removed in case other - // actors stopped in the mean - // time. - if !remove.is_empty() { - continue; + // TODO + if let Some((id, res)) = remove { + let removed = rt.actors.remove(&id); + + match (removed, res) { + (Some(_), Err(err)) => return Poll::Ready(Some(Err((id, err)))), + (None, Err(err)) => return Poll::Ready(Some(Err(( + id, + Error::multiple(vec![ + Error::already_removed(id), + Error::std(err), + ]), + )))), + _ => return Poll::Ready(Some(Ok(id))), } + } - // We try to poll from the actors' - // kill channel's receiver. - match Pin::new(&mut rt.recver).poll_next(ctx) { - Poll::Ready(Some(actor)) => { - if rt.actors.remove(&actor).is_none() { - wait.errors.push(Error::already_removed(actor)); - } - } - // If the channel has been closed, - // we stop the future. - Poll::Ready(None) => { - if wait.errors.len() > 1 { - return Poll::Ready(Err(Error::multiple(wait.errors.split_off(0)))); - } else if wait.errors.len() == 1 { - return Poll::Ready(Err(wait.errors.pop().unwrap())); - } else { - return Poll::Ready(Ok(())); - } + // TODO + match Pin::new(&mut rt.recver).poll_next(ctx) { + Poll::Ready(Some(actor)) => { + if rt.actors.remove(&actor).is_none() { + return Poll::Ready(Some(Err((actor, Error::already_removed(actor))))); + } else { + return Poll::Ready(Some(Ok(actor))); } - Poll::Pending => return Poll::Pending, } + Poll::Ready(None) => return Poll::Ready(None), + Poll::Pending => (), } + + Poll::Pending } } From 6a46d955877fb24ebf251a1be202709225d3ccd8 Mon Sep 17 00:00:00 2001 From: Matthieu Le Brazidec Date: Thu, 11 Jul 2019 11:32:50 +0200 Subject: [PATCH 10/22] Updated the examples. --- examples/hello_world/Cargo.toml | 2 +- examples/hello_world/src/main.rs | 34 +++++++++--------- examples/net/src/main.rs | 62 ++++++++++++++++++++++++++------ 3 files changed, 70 insertions(+), 28 deletions(-) diff --git a/examples/hello_world/Cargo.toml b/examples/hello_world/Cargo.toml index c26c4d1..3f0c29f 100644 --- a/examples/hello_world/Cargo.toml +++ b/examples/hello_world/Cargo.toml @@ -14,4 +14,4 @@ version = "0.1.0-alpha.3" [dependencies.futures-util-preview] version = "0.3.0-alpha.17" -features = ["nightly", "async-await"] +features = ["nightly", "async-await", "select-macro"] diff --git a/examples/hello_world/src/main.rs b/examples/hello_world/src/main.rs index 9528fd4..24509c7 100644 --- a/examples/hello_world/src/main.rs +++ b/examples/hello_world/src/main.rs @@ -1,9 +1,9 @@ #![feature(async_await)] -use std::task::Poll; - use aktoro::prelude::*; -use futures_util::poll; +use futures_util::select; +use futures_util::FutureExt; +use futures_util::StreamExt; struct HelloActor; @@ -13,7 +13,7 @@ struct Bye(&'static str); struct Kill; impl Actor for HelloActor { - type Context = Context; + type Context = Context; type Status = Status; type Error = Error; } @@ -21,7 +21,7 @@ impl Actor for HelloActor { impl Handler for HelloActor { type Output = String; - fn handle(&mut self, msg: Hello, _: &mut Context) -> Result { + fn handle(&mut self, msg: Hello, _: &mut Self::Context) -> Result { Ok(format!("Hello, {}!", msg.0)) } } @@ -29,7 +29,7 @@ impl Handler for HelloActor { impl Handler for HelloActor { type Output = String; - fn handle(&mut self, msg: Bye, _: &mut Context) -> Result { + fn handle(&mut self, msg: Bye, _: &mut Self::Context) -> Result { Ok(format!("Bye, {}!", msg.0)) } } @@ -37,8 +37,8 @@ impl Handler for HelloActor { impl ActionHandler for HelloActor { type Output = (); - fn handle(&mut self, _: Kill, ctx: &mut Context) -> Result<(), Error> { - ctx.set_status(Status::Stopped); + fn handle(&mut self, _: Kill, ctx: &mut Self::Context) -> Result<(), Error> { + ctx.set_status(Status::Dead); Ok(()) } } @@ -49,17 +49,17 @@ async fn main() { let spawned = rt.spawn(HelloActor).unwrap(); - let mut run = runtime::spawn(run("World", spawned)); - let mut wait = rt.wait(); + let mut run = runtime::spawn(run("World", spawned)).fuse(); + let mut wait = rt.wait().fuse(); loop { - if let Poll::Ready(_) = poll!(&mut run) { - break; - } - - if let Poll::Ready(res) = poll!(&mut wait) { - res.expect("an error occured while waiting for the runtime to stop"); - break; + select! { + _ = run => break, + res = wait.next() => { + res.unwrap() + .expect("an error occured while waiting for the runtime to stop"); + break; + }, } } } diff --git a/examples/net/src/main.rs b/examples/net/src/main.rs index 000376f..d4d4970 100644 --- a/examples/net/src/main.rs +++ b/examples/net/src/main.rs @@ -3,7 +3,9 @@ use aktoro::prelude::*; use aktoro::raw; use futures_util::io::AsyncReadExt; +use futures_util::io::ReadHalf; use futures_util::io::WriteHalf; +use futures_util::StreamExt; struct Client { connect: Option, @@ -14,6 +16,10 @@ struct Server { tcp: Option, } +struct Agent { + read: Option>, +} + struct Connected(C); struct Connection(S::Stream); @@ -22,11 +28,13 @@ struct Sent(WriteHalf); struct Received(Vec); +struct Died; + impl Actor for Client where C: raw::TcpClient + 'static, { - type Context = Context; + type Context = Context; type Status = Status; type Error = Error; @@ -41,7 +49,7 @@ impl Actor for Server where S: raw::TcpServer + 'static, { - type Context = Context; + type Context = Context; type Status = Status; type Error = Error; @@ -55,6 +63,19 @@ where } } +impl Actor for Agent +where + S: raw::TcpStream + 'static, +{ + type Context = Context; + type Status = Status; + type Error = Error; + + fn started(&mut self, ctx: &mut Self::Context) { + ctx.read(self.read.take().unwrap(), 64, Received, |_| ()); + } +} + impl Handler> for Client where C: raw::TcpClient + 'static, @@ -83,7 +104,11 @@ where println!("new connection from {}", conn.peer_addr().unwrap()); let (read, _) = conn.split(); - ctx.read(read, 64, Received, |_| ()); + let spawned = ctx.spawn(Agent { + read: Some(read), + }).unwrap(); + + ctx.subscribe(spawned, |_| Died); Ok(()) } @@ -99,22 +124,37 @@ where println!("sent data"); self.write = Some(sent.0); - ctx.set_status(Status::Stopped); + ctx.set_status(Status::Dead); Ok(()) } } -impl Handler for Server +impl Handler for Agent where - S: raw::TcpServer + 'static, + S: raw::TcpStream + 'static, { type Output = (); fn handle(&mut self, msg: Received, ctx: &mut Self::Context) -> Result<(), Self::Error> { println!("received {:?}", msg.0); - ctx.set_status(Status::Stopped); + ctx.set_status(Status::Dead); + + Ok(()) + } +} + +impl Handler for Server +where + S: raw::TcpServer + 'static, +{ + type Output = (); + + fn handle(&mut self, _: Died, ctx: &mut Self::Context) -> Result<(), Self::Error> { + println!("agent died; remaining agents: {:?}", ctx.actors()); + + ctx.set_status(Status::Dead); Ok(()) } @@ -138,7 +178,9 @@ async fn main() { rt.spawn(client).unwrap(); - rt.wait() - .await - .expect("an error occured while waiting for the runtime to stop"); + let mut wait = rt.wait(); + + while let Some(res) = wait.next().await { + res.expect("an error occured while waiting for the runtime to stop"); + } } From 65ffaed74db14938670cc9757a3bcd1d3769dcc8 Mon Sep 17 00:00:00 2001 From: Matthieu Le Brazidec Date: Thu, 11 Jul 2019 11:33:10 +0200 Subject: [PATCH 11/22] Formatting. --- aktoro-context/src/context.rs | 5 ++--- aktoro-context/src/update.rs | 8 ++------ aktoro-runtime/src/runtime.rs | 18 ++++++++++-------- examples/net/src/main.rs | 4 +--- 4 files changed, 15 insertions(+), 20 deletions(-) diff --git a/aktoro-context/src/context.rs b/aktoro-context/src/context.rs index fe9ead2..67d8401 100644 --- a/aktoro-context/src/context.rs +++ b/aktoro-context/src/context.rs @@ -121,9 +121,8 @@ where fn update(&mut self) -> Result<(), TrySendError>> { self.update = false; - self.updter.try_send( - Update::new(self.actor_id, self.status.clone()), - ) + self.updter + .try_send(Update::new(self.actor_id, self.status.clone())) } fn controller(&self) -> &Controller { diff --git a/aktoro-context/src/update.rs b/aktoro-context/src/update.rs index 8889749..a7020d5 100644 --- a/aktoro-context/src/update.rs +++ b/aktoro-context/src/update.rs @@ -49,10 +49,7 @@ where A: raw::Actor, { pub(crate) fn new(actor_id: u64, status: A::Status) -> Self { - Update { - actor_id, - status, - } + Update { actor_id, status } } } @@ -162,8 +159,7 @@ where A: raw::Actor, { fn eq(&self, other: &Self) -> bool { - self.actor_id == other.actor_id && - self.status == other.status + self.actor_id == other.actor_id && self.status == other.status } } diff --git a/aktoro-runtime/src/runtime.rs b/aktoro-runtime/src/runtime.rs index ce7eadf..d6465c9 100644 --- a/aktoro-runtime/src/runtime.rs +++ b/aktoro-runtime/src/runtime.rs @@ -124,7 +124,10 @@ impl raw::Wait for Wait { impl Stream for Wait { type Item = Result; - fn poll_next(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll>> { + fn poll_next( + self: Pin<&mut Self>, + ctx: &mut FutContext, + ) -> Poll>> { let rt = &mut self.get_mut().0; if rt.actors.is_empty() { @@ -145,13 +148,12 @@ impl Stream for Wait { match (removed, res) { (Some(_), Err(err)) => return Poll::Ready(Some(Err((id, err)))), - (None, Err(err)) => return Poll::Ready(Some(Err(( - id, - Error::multiple(vec![ - Error::already_removed(id), - Error::std(err), - ]), - )))), + (None, Err(err)) => { + return Poll::Ready(Some(Err(( + id, + Error::multiple(vec![Error::already_removed(id), Error::std(err)]), + )))) + } _ => return Poll::Ready(Some(Ok(id))), } } diff --git a/examples/net/src/main.rs b/examples/net/src/main.rs index d4d4970..9191f1f 100644 --- a/examples/net/src/main.rs +++ b/examples/net/src/main.rs @@ -104,9 +104,7 @@ where println!("new connection from {}", conn.peer_addr().unwrap()); let (read, _) = conn.split(); - let spawned = ctx.spawn(Agent { - read: Some(read), - }).unwrap(); + let spawned = ctx.spawn(Agent { read: Some(read) }).unwrap(); ctx.subscribe(spawned, |_| Died); From ce66b201511744eaebed348bd20eeacbb2bbce6a Mon Sep 17 00:00:00 2001 From: Matthieu Le Brazidec Date: Fri, 12 Jul 2019 19:58:04 +0200 Subject: [PATCH 12/22] Fixed a bug where wakers would be removed while valid. --- aktoro-channel/src/channel.rs | 28 +++++++++++++++++----------- aktoro-channel/src/receiver.rs | 14 +++++++------- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/aktoro-channel/src/channel.rs b/aktoro-channel/src/channel.rs index be23eaf..3e104eb 100644 --- a/aktoro-channel/src/channel.rs +++ b/aktoro-channel/src/channel.rs @@ -15,10 +15,14 @@ use crate::queue::Queue; /// messages over it, and receivers to /// retrieve them. pub(crate) struct Channel { + // TODO pub(crate) queue: Queue>, + // TODO pub(crate) closed: AtomicBool, + // TODO pub(crate) counters: Counters, - pub(crate) wakers: SegQueue>>>, + // TODO + pub(crate) wakers: SegQueue)>>>, } impl Channel { @@ -73,10 +77,8 @@ impl Channel { } } - /// Registers a new waker to be - /// notified when a new message is - /// available. - pub(crate) fn register(&self, waker: Arc>>) { + // TODO + pub(crate) fn register(&self, waker: Arc)>>) { self.wakers.push(waker); } @@ -84,12 +86,16 @@ impl Channel { /// available. fn notify(&self) { if let Ok(waker) = self.wakers.pop() { - if let Some(waker_) = waker.swap(None) { - waker_.wake(); - - self.wakers.push(waker); - } else { - self.notify(); + match waker.swap((true, None)) { + (true, Some(waker_)) => { + self.wakers.push(waker); + waker_.wake(); + } + (true, None) => { + self.wakers.push(waker); + self.notify(); + } + _ => self.notify(), } } } diff --git a/aktoro-channel/src/receiver.rs b/aktoro-channel/src/receiver.rs index 333980e..bae11bd 100644 --- a/aktoro-channel/src/receiver.rs +++ b/aktoro-channel/src/receiver.rs @@ -18,7 +18,7 @@ use crate::error::*; /// /// [`try_recv`]: #method.try_recv pub struct Receiver { - waker: Arc>>, + waker: Arc)>>, channel: Option>>, } @@ -32,7 +32,7 @@ impl Receiver { // creation. channel.counters.add_recver().expect("receivers limit == 0"); - let waker = Arc::new(AtomicCell::new(None)); + let waker = Arc::new(AtomicCell::new((true, None))); channel.register(waker.clone()); Receiver { @@ -68,7 +68,7 @@ impl Receiver { /// Closes the channel the receiver /// is connected to. pub fn close_channel(&self) { - self.waker.store(None); + self.waker.store((false, None)); if let Some(channel) = &self.channel { channel.close() @@ -78,7 +78,7 @@ impl Receiver { /// Disconnects the receiver from the /// channel. pub fn disconnect(&mut self) { - self.waker.store(None); + self.waker.store((false, None)); let channel = if let Some(channel) = self.channel.take() { channel @@ -97,7 +97,7 @@ impl Receiver { pub fn try_clone(&self) -> Result { if let Some(channel) = &self.channel { if channel.counters.add_recver().is_ok() { - let waker = Arc::new(AtomicCell::new(None)); + let waker = Arc::new(AtomicCell::new((true, None))); Ok(Receiver { waker, @@ -116,7 +116,7 @@ impl Stream for Receiver { type Item = T; fn poll_next(self: Pin<&mut Self>, ctx: &mut Context) -> Poll> { - self.waker.store(None); + self.waker.store((true, None)); if let Some(channel) = &self.channel { // We try to receive a message... @@ -127,7 +127,7 @@ impl Stream for Receiver { // ...or register the stream's // waker if none is available... Ok(None) => { - self.waker.store(Some(ctx.waker().clone())); + self.waker.store((true, Some(ctx.waker().clone()))); Poll::Pending } From be1fd2b54ed1f568601653e2f164fc935d50440d Mon Sep 17 00:00:00 2001 From: Matthieu Le Brazidec Date: Fri, 12 Jul 2019 19:59:48 +0200 Subject: [PATCH 13/22] Added a way to cancel actors subscriptions and to block on them. --- aktoro-raw/Cargo.toml | 1 + aktoro-raw/src/context.rs | 161 +++++++++++++++++++++++++++++++++++--- aktoro-raw/src/message.rs | 10 +-- aktoro-raw/src/runtime.rs | 7 ++ aktoro-raw/src/tcp.rs | 8 +- 5 files changed, 166 insertions(+), 21 deletions(-) diff --git a/aktoro-raw/Cargo.toml b/aktoro-raw/Cargo.toml index 41a6854..8c4fbb8 100644 --- a/aktoro-raw/Cargo.toml +++ b/aktoro-raw/Cargo.toml @@ -7,5 +7,6 @@ authors = ["Matthieu Le Brazidec "] edition = "2018" [dependencies] +crossbeam-utils = "0.6" futures-core-preview = "0.3.0-alpha.17" futures-io-preview = "0.3.0-alpha.17" diff --git a/aktoro-raw/src/context.rs b/aktoro-raw/src/context.rs index 7e505a1..bfeb32f 100644 --- a/aktoro-raw/src/context.rs +++ b/aktoro-raw/src/context.rs @@ -1,5 +1,13 @@ use std::future::Future; +use std::pin::Pin; +use std::sync::atomic::AtomicBool; +use std::sync::atomic::Ordering; +use std::sync::Arc; +use std::task::Context as FutContext; +use std::task::Poll; +use std::task::Waker; +use crossbeam_utils::atomic::AtomicCell; use futures_core::Stream; use futures_io as io; use futures_io::AsyncRead; @@ -16,13 +24,44 @@ use crate::message::Message; use crate::spawned::Spawned; use crate::update::Updater; -pub trait Context: Stream> + Unpin + Send { +// TODO +pub struct Cancellable { + // TODO + inner: CancellableInner, +} + +// TODO +pub struct CancellableInner { + // TODO + inner: Arc>>>>, + // TODO + done: Arc, + // TODO + waker: Arc>>, +} + +// TODO +pub struct Cancelling { + // TODO + inner: Arc>>>>, + // TODO + done: Arc, + // TODO + waker: Arc>>, +} + +pub trait Context: Stream> + Unpin + Send + Sized { + type Config: Default; + type Controller: Controller; type Sender: Sender; type Updater: Updater; // TODO - fn new(actor_id: u64) -> Self; + fn new(actor_id: u64, config: Self::Config) -> Self; + + // TODO + fn actor_id(&self) -> u64; /// Emits an event that will be handled by the /// actor. @@ -73,28 +112,40 @@ pub trait Context: Stream> + Unpin + Send { fn actors(&self) -> Vec; // TODO - fn spawn(&mut self, actor: S) -> Option> + fn spawn(&mut self, actor: S) -> Option> where - S: Actor + 'static; + S: Actor + 'static, + C: Context; // TODO - fn wait(&mut self, fut: F, map: M) + fn wait(&mut self, fut: Pin>, map: M) -> Cancellable where F: Future + Unpin + Send + 'static, - M: Fn(O) -> T + Send + 'static, + M: Fn(O) -> T + Unpin + Send + Sync + 'static, A: Handler, + O: Send + 'static, T: Send + 'static; // TODO - fn subscribe(&mut self, stream: S, map: M) + fn blocking_wait(&mut self, fut: Pin>, map: M) -> Cancellable + where + F: Future + Unpin + Send + 'static, + M: Fn(O) -> T + Unpin + Send + Sync + 'static, + A: Handler, + O: Send + 'static, + T: Send + 'static; + + // TODO + fn subscribe(&mut self, stream: Pin>, map: M) -> Cancellable where S: Stream + Unpin + Send + 'static, - M: Fn(I) -> T + Send + 'static, + M: Fn(I) -> T + Unpin + Send + Sync + 'static, A: Handler, + I: Send + 'static, T: Send + 'static; // TODO - fn read(&mut self, read: R, cap: usize, map: M, map_err: N) + fn read(&mut self, read: Pin>, cap: usize, map: M, map_err: N) -> Cancellable where R: AsyncRead + Unpin + Send + 'static, M: Fn(Vec) -> T + Unpin + Send + Sync + 'static, @@ -104,10 +155,20 @@ pub trait Context: Stream> + Unpin + Send { E: Send + 'static; // TODO - fn write(&mut self, write: W, data: Vec, map: M, map_err: N) + fn write(&mut self, write: Pin>, data: Vec, map: M, map_err: N) -> Cancellable where W: AsyncWrite + Unpin + Send + 'static, - M: Fn((Vec, usize), W) -> T + Unpin + Send + Sync + 'static, + M: Fn((Vec, usize), Pin>) -> T + Unpin + Send + Sync + 'static, + N: Fn(io::Error) -> E + Unpin + Send + Sync + 'static, + A: Handler + Handler, + T: Send + 'static, + E: Send + 'static; + + // TODO + fn blocking_write(&mut self, write: Pin>, data: Vec, map: M, map_err: N) -> Cancellable + where + W: AsyncWrite + Unpin + Send + 'static, + M: Fn((Vec, usize), Pin>) -> T + Unpin + Send + Sync + 'static, N: Fn(io::Error) -> E + Unpin + Send + Sync + 'static, A: Handler + Handler, T: Send + 'static, @@ -131,3 +192,81 @@ pub enum Work { /// changed. Update, } + +impl Cancellable { + // TODO + pub fn new(inner: Pin>) -> (Self, CancellableInner) { + let inner = Arc::new(AtomicCell::new(Some(inner))); + let done = Arc::new(AtomicBool::new(false)); + let waker = Arc::new(AtomicCell::new(None)); + + ( + Cancellable { + inner: CancellableInner { + inner: inner.clone(), + done: done.clone(), + waker: waker.clone(), + } + }, + CancellableInner { inner, done, waker, }, + ) + } + + // TODO + pub fn cancel(self) -> Cancelling { + Cancelling { + inner: self.inner.inner, + done: self.inner.done, + waker: self.inner.waker, + } + } +} + +impl CancellableInner { + // TODO + pub fn get(&self) -> Option>> { + self.inner.swap(None) + } + + // TODO + pub fn set(&self, inner: Pin>) { + self.inner.store(Some(inner)); + + if let Some(waker) = self.waker.swap(None) { + waker.wake(); + } + } + + // TODO + pub fn done(&self) { + self.inner.store(None); + self.done.store(true, Ordering::SeqCst); + + if let Some(waker) = self.waker.swap(None) { + waker.wake(); + } + } +} + +impl Future for Cancelling { + type Output = Option>>; + + fn poll(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll>>> { + if self.done.load(Ordering::SeqCst) { + return Poll::Ready(None); + } + + match self.inner.swap(None) { + Some(inner) => { + self.waker.store(None); + + Poll::Ready(Some(inner)) + } + None => { + self.waker.store(Some(ctx.waker().clone())); + + Poll::Pending + } + } + } +} diff --git a/aktoro-raw/src/message.rs b/aktoro-raw/src/message.rs index 597474b..37d4654 100644 --- a/aktoro-raw/src/message.rs +++ b/aktoro-raw/src/message.rs @@ -4,9 +4,7 @@ use std::task::Poll; use crate::actor::Actor; -pub type AsyncMessageOutput = Box>; - -pub type AsyncMessageItem = Option>>; +pub type AsyncMessageRet = Option>>; pub trait Message: Send { type Actor: Actor; @@ -21,14 +19,14 @@ pub trait Message: Send { pub trait AsyncMessageFut: Send { type Actor: Actor; - fn poll(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll>; + fn poll(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll>; } pub trait AsyncMessageStream: Send { type Actor: Actor; fn poll_next(self: Pin<&mut Self>, ctx: &mut FutContext) - -> Poll>; + -> Poll>; } pub trait AsyncReadStream: Send { @@ -37,7 +35,7 @@ pub trait AsyncReadStream: Send { fn poll_read( self: Pin<&mut Self>, ctx: &mut FutContext, - ) -> Poll>; + ) -> Poll>; } pub trait Handler: Actor { diff --git a/aktoro-raw/src/runtime.rs b/aktoro-raw/src/runtime.rs index 29eaffa..074dfa8 100644 --- a/aktoro-raw/src/runtime.rs +++ b/aktoro-raw/src/runtime.rs @@ -3,6 +3,7 @@ use std::error::Error as StdError; use futures_core::Stream; use crate::actor::Actor; +use crate::context::Context; use crate::net::NetworkManager; use crate::spawned::Spawned; @@ -41,6 +42,12 @@ pub trait Runtime: Default + Unpin + Send { where A: Actor + 'static; + // TODO + fn spawn_with(&mut self, actor: A, config: C::Config) -> Option> + where + A: Actor + 'static, + C: Context; + /// Creates a new network manager, that /// can then be used by an actor to /// create a new TCP client, server or diff --git a/aktoro-raw/src/tcp.rs b/aktoro-raw/src/tcp.rs index 9e10950..245df4a 100644 --- a/aktoro-raw/src/tcp.rs +++ b/aktoro-raw/src/tcp.rs @@ -7,8 +7,8 @@ use futures_core::Stream; use futures_io::AsyncRead; use futures_io::AsyncWrite; -pub type TcpServerIncoming<'s, S, E> = Box> + Unpin + Send + 's>; -pub type OwnedTcpServerIncoming = Box> + Unpin + Send>; +pub type TcpServerIncoming<'s, S> = Box::Stream, ::Error>> + Unpin + Send + 's>; +pub type OwnedTcpServerIncoming = Box::Stream, ::Error>> + Unpin + Send>; pub trait TcpClient: TcpStream + Unpin + Send + Sized { type Connect: Future::Error>> + Unpin + Send; @@ -34,12 +34,12 @@ pub trait TcpServer: Unpin + Send + Sized { fn local_addr(&self) -> Result; /// Returns a stream of incoming connections. - fn incoming(&mut self) -> Result, Self::Error>; + fn incoming(&mut self) -> Result, Self::Error>; // TODO fn into_incoming( self, - ) -> Result, Self::Error>; + ) -> Result, Self::Error>; } pub trait TcpStream: AsyncRead + AsyncWrite + Unpin + Send { From 20202d3f88fb2e09e5995daed8a51b82eb73e0e6 Mon Sep 17 00:00:00 2001 From: Matthieu Le Brazidec Date: Fri, 12 Jul 2019 20:00:26 +0200 Subject: [PATCH 14/22] Updated the implementations. --- aktoro-context/src/context.rs | 211 +++++++++++++++++++++++++++++----- aktoro-context/src/message.rs | 187 ++++++++++++++++++++---------- aktoro-runtime/src/actor.rs | 6 +- aktoro-runtime/src/error.rs | 24 ---- aktoro-runtime/src/runtime.rs | 21 ++-- aktoro-runtime/src/tcp.rs | 10 +- 6 files changed, 332 insertions(+), 127 deletions(-) diff --git a/aktoro-context/src/context.rs b/aktoro-context/src/context.rs index 67d8401..9730f58 100644 --- a/aktoro-context/src/context.rs +++ b/aktoro-context/src/context.rs @@ -5,6 +5,7 @@ use std::task::Context as FutContext; use std::task::Poll; use aktoro_channel::error::TrySendError; +use aktoro_channel::Notify; use aktoro_raw as raw; use aktoro_raw::Updater as RawUpdater; use aktoro_raw::Wait as RawWait; @@ -12,8 +13,6 @@ use futures_core::Stream; use futures_io as io; use futures_io::AsyncRead; use futures_io::AsyncWrite; -use futures_util::FutureExt; -use futures_util::StreamExt; use crate::channel; use crate::channel::Receiver; @@ -31,12 +30,19 @@ use crate::update::Update; use crate::update::Updated; use crate::update::Updater; +// TODO +pub struct ContextConfig { + ready: Option, +} + /// An actor context using the [`aktoro-channel`] crate. /// /// [`aktoro-channel`]: https://docs.rs/aktoro-channel pub struct Context { // TODO - pub actor_id: u64, + actor_id: u64, + // TODO + ready: Option, /// The actor's current status. status: A::Status, /// An actor's control channel sender. @@ -47,6 +53,8 @@ pub struct Context { /// and the runtime should be notified. update: bool, // TODO + b_futs: Vec>>>, + // TODO futs: Vec>>>, // TODO streams: Vec>>>, @@ -54,6 +62,8 @@ pub struct Context { reads: Vec>>>, // TODO rt: Option, + // TODO + to_notify: Vec, /// A list of the actor's unhandled events. events: VecDeque>>, /// An actor's message channel sender. @@ -71,11 +81,13 @@ where A: raw::Actor + 'static, RT: raw::Runtime, { + type Config = ContextConfig; + type Controller = Controller; type Sender = Sender; type Updater = Updater; - fn new(actor_id: u64) -> Context { + fn new(actor_id: u64, config: ContextConfig) -> Context { // We create the actor's control, message and // update channels. let (ctrler, ctrled) = control::new(); @@ -84,14 +96,17 @@ where Context { actor_id, + ready: config.ready, status: A::Status::default(), ctrler, ctrled, update: false, - futs: Vec::new(), - streams: Vec::new(), - reads: Vec::new(), + b_futs: vec![], + futs: vec![], + streams: vec![], + reads: vec![], rt: None, + to_notify: vec![], events: VecDeque::new(), sender, recver, @@ -100,6 +115,10 @@ where } } + fn actor_id(&self) -> u64 { + self.actor_id + } + fn emit(&mut self, event: E) where A: raw::EventHandler, @@ -161,9 +180,10 @@ where } } - fn spawn(&mut self, actor: S) -> Option> + fn spawn(&mut self, actor: S) -> Option> where - S: raw::Actor + 'static, + S: raw::Actor + 'static, + C: raw::Context, { let rt = if let Some(rt) = &mut self.rt { rt @@ -172,31 +192,65 @@ where self.rt.as_mut().unwrap() }; - rt.spawn(actor) + let mut config = ContextConfig::default(); + + let (notify, ready) = Notify::new(); + config.ready = Some(ready); + + if let Some(spawned) = rt.spawn_with(actor, config) { + self.to_notify.push(notify); + Some(spawned) + } else { + None + } } - fn wait(&mut self, fut: F, map: M) + fn wait(&mut self, fut: Pin>, map: M) -> raw::Cancellable where F: Future + Unpin + Send + 'static, - M: Fn(O) -> T + Send + 'static, + M: Fn(O) -> T + Unpin + Send + Sync + 'static, A: raw::Handler, + O: Send + 'static, T: Send + 'static, { - self.futs.push(Box::pin(AsyncMessageFut::new(fut.map(map)))); + let (cancellable, inner) = raw::Cancellable::new(fut); + + self.futs.push(Box::pin(AsyncMessageFut::new(inner, map))); + + cancellable } - fn subscribe(&mut self, stream: S, map: M) + fn blocking_wait(&mut self, fut: Pin>, map: M) -> raw::Cancellable + where + F: Future + Unpin + Send + 'static, + M: Fn(O) -> T + Unpin + Send + Sync + 'static, + A: raw::Handler, + O: Send + 'static, + T: Send + 'static, + { + let (cancellable, inner) = raw::Cancellable::new(fut); + self.b_futs.push(Box::pin(AsyncMessageFut::new(inner, map))); + + cancellable + } + + fn subscribe(&mut self, stream: Pin>, map: M) -> raw::Cancellable where S: Stream + Unpin + Send + 'static, - M: Fn(I) -> T + Send + 'static, + M: Fn(I) -> T + Unpin + Send + Sync + 'static, A: raw::Handler, + I: Send + 'static, T: Send + 'static, { + let (cancellable, inner) = raw::Cancellable::new(stream); + self.streams - .push(Box::pin(AsyncMessageStream::new(stream.map(map)))); + .push(Box::pin(AsyncMessageStream::new(inner, map))); + + cancellable } - fn read(&mut self, read: R, cap: usize, map: M, map_err: N) + fn read(&mut self, read: Pin>, cap: usize, map: M, map_err: N) -> raw::Cancellable where R: AsyncRead + Unpin + Send + 'static, M: Fn(Vec) -> T + Unpin + Send + Sync + 'static, @@ -205,21 +259,46 @@ where T: Send + 'static, E: Send + 'static, { + let (cancellable, inner) = raw::Cancellable::new(read); + self.reads - .push(Box::pin(AsyncReadStream::new(read, cap, map, map_err))); + .push(Box::pin(AsyncReadStream::new(inner, cap, map, map_err))); + + cancellable } - fn write(&mut self, write: W, data: Vec, map: M, map_err: N) + fn write(&mut self, write: Pin>, data: Vec, map: M, map_err: N) -> raw::Cancellable where W: AsyncWrite + Unpin + Send + 'static, - M: Fn((Vec, usize), W) -> T + Unpin + Send + Sync + 'static, + M: Fn((Vec, usize), Pin>) -> T + Unpin + Send + Sync + 'static, N: Fn(io::Error) -> E + Unpin + Send + Sync + 'static, A: raw::Handler + raw::Handler, T: Send + 'static, E: Send + 'static, { + let (cancellable, inner) = raw::Cancellable::new(write); + self.futs - .push(Box::pin(AsyncWriteFut::new(write, data, map, map_err))); + .push(Box::pin(AsyncWriteFut::new(inner, data, map, map_err))); + + cancellable + } + + fn blocking_write(&mut self, write: Pin>, data: Vec, map: M, map_err: N) -> raw::Cancellable + where + W: AsyncWrite + Unpin + Send + 'static, + M: Fn((Vec, usize), Pin>) -> T + Unpin + Send + Sync + 'static, + N: Fn(io::Error) -> E + Unpin + Send + Sync + 'static, + A: raw::Handler + raw::Handler, + T: Send + 'static, + E: Send + 'static, + { + let (cancellable, inner) = raw::Cancellable::new(write); + + self.b_futs + .push(Box::pin(AsyncWriteFut::new(inner, data, map, map_err))); + + cancellable } } @@ -232,6 +311,16 @@ where fn poll_next(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll>> { let context = self.get_mut(); + let mut ret = None; + + if let Some(ready) = context.ready.as_mut() { + match Pin::new(ready).poll(ctx) { + Poll::Ready(()) => { + context.ready.take(); + } + Poll::Pending => return Poll::Pending, + } + } // If an action has been received an action has // been received from the actor's control channel, @@ -251,6 +340,36 @@ where return Poll::Ready(Some(raw::Work::Update)); } + // TODO + let mut to_remove = vec![]; + for (i, fut) in context.b_futs.iter_mut().enumerate() { + match fut.as_mut().poll(ctx) { + Poll::Ready(Some(msg)) => { + to_remove.push(i); + ret = Some(raw::Work::Message(msg)); + + break; + } + Poll::Ready(None) => to_remove.push(i), + Poll::Pending => (), + } + } + + for to_remove in to_remove { + context.b_futs.remove(to_remove); + } + + if let Some(ret) = ret { + return Poll::Ready(Some(ret)); + } else if !context.b_futs.is_empty() { + return Poll::Pending; + } + + // TODO + for to_notify in context.to_notify.drain(..) { + to_notify.done(); + } + // If the actor has unhandled events, we ask the // runtime to make the actor handle the oldest // one. @@ -287,24 +406,33 @@ where } // TODO + let mut to_remove = vec![]; for (i, fut) in context.futs.iter_mut().enumerate() { match fut.as_mut().poll(ctx) { - Poll::Ready(msg) => { - context.futs.remove(i); + Poll::Ready(Some(msg)) => { + to_remove.push(i); + ret = Some(raw::Work::Message(msg)); - return Poll::Ready(Some(raw::Work::Message(msg))); + break; } + Poll::Ready(None) => to_remove.push(i), Poll::Pending => (), } } + for to_remove in to_remove { + context.futs.remove(to_remove); + } + + if let Some(ret) = ret { + return Poll::Ready(Some(ret)); + } + // TODO let mut to_remove = vec![]; for (i, stream) in context.streams.iter_mut().enumerate() { match stream.as_mut().poll_next(ctx) { - Poll::Ready(Some(msg)) => { - return Poll::Ready(Some(raw::Work::Message(msg))); - } + Poll::Ready(Some(msg)) => ret = Some(raw::Work::Message(msg)), Poll::Ready(None) => to_remove.push(i), Poll::Pending => (), } @@ -314,13 +442,36 @@ where context.streams.remove(to_remove); } + if let Some(ret) = ret { + return Poll::Ready(Some(ret)); + } + // TODO - for read in context.reads.iter_mut() { - if let Poll::Ready(msg) = read.as_mut().poll_read(ctx) { - return Poll::Ready(Some(raw::Work::Message(msg))); + let mut to_remove = vec![]; + for (i, read) in context.reads.iter_mut().enumerate() { + match read.as_mut().poll_read(ctx) { + Poll::Ready(Some(msg)) => ret = Some(raw::Work::Message(msg)), + Poll::Ready(None) => to_remove.push(i), + Poll::Pending => (), } } + for to_remove in to_remove { + context.reads.remove(to_remove); + } + + if let Some(ret) = ret { + return Poll::Ready(Some(ret)); + } + Poll::Pending } } + +impl Default for ContextConfig { + fn default() -> Self { + ContextConfig { + ready: None, + } + } +} diff --git a/aktoro-context/src/message.rs b/aktoro-context/src/message.rs index d4095e8..147ec6e 100644 --- a/aktoro-context/src/message.rs +++ b/aktoro-context/src/message.rs @@ -32,23 +32,29 @@ where _act: PhantomData, } -pub(crate) struct AsyncMessageFut +pub(crate) struct AsyncMessageFut where - A: raw::Handler, - F: Future + Unpin + Send, - M: Send, + A: raw::Handler, + F: Future + Unpin + Send, + M: Fn(O) -> T + Send, + O: Send, + T: Send, { - fut: F, + inner: raw::CancellableInner, + map: M, _act: PhantomData, } -pub(crate) struct AsyncMessageStream +pub(crate) struct AsyncMessageStream where - A: raw::Handler, - S: Stream + Unpin + Send, - M: Send, + A: raw::Handler, + S: Stream + Unpin + Send, + M: Fn(I) -> T + Send, + I: Send, + T: Send, { - stream: S, + inner: raw::CancellableInner, + map: M, _act: PhantomData, } @@ -63,7 +69,7 @@ where { cap: usize, buf: Vec, - read: R, + inner: raw::CancellableInner, map: M, map_err: N, _act: PhantomData, @@ -73,7 +79,7 @@ pub(crate) struct AsyncWriteFut where A: raw::Handler + raw::Handler, W: AsyncWrite + Unpin + Send, - M: Fn((Vec, usize), W) -> T + Unpin + Send + Sync + 'static, + M: Fn((Vec, usize), Pin>) -> T + Unpin + Send + Sync + 'static, N: Fn(io::Error) -> E + Unpin + Send + Sync + 'static, T: Send, E: Send, @@ -81,7 +87,7 @@ where data: Option>, map: M, map_err: N, - write: Option, + inner: raw::CancellableInner, _act: PhantomData, } @@ -116,29 +122,35 @@ where } } -impl AsyncMessageFut +impl AsyncMessageFut where - A: raw::Handler, - F: Future + Unpin + Send, - M: Send, + A: raw::Handler, + F: Future + Unpin + Send, + M: Fn(O) -> T + Unpin + Send, + O: Send, + T: Send, { - pub(crate) fn new(fut: F) -> Self { + pub(crate) fn new(inner: raw::CancellableInner, map: M) -> Self { AsyncMessageFut { - fut, + inner, + map, _act: PhantomData, } } } -impl AsyncMessageStream +impl AsyncMessageStream where - A: raw::Handler, - S: Stream + Unpin + Send, - M: Send, + A: raw::Handler, + S: Stream + Unpin + Send, + M: Fn(I) -> T + Unpin + Send, + I: Send, + T: Send, { - pub(crate) fn new(stream: S) -> Self { + pub(crate) fn new(inner: raw::CancellableInner, map: M) -> Self { AsyncMessageStream { - stream, + inner, + map, _act: PhantomData, } } @@ -153,11 +165,11 @@ where T: Send, E: Send, { - pub(crate) fn new(read: R, cap: usize, map: M, map_err: N) -> Self { + pub(crate) fn new(inner: raw::CancellableInner, cap: usize, map: M, map_err: N) -> Self { AsyncReadStream { cap, buf: vec![0; cap], - read, + inner, map, map_err, _act: PhantomData, @@ -169,17 +181,17 @@ impl AsyncWriteFut where A: raw::Handler + raw::Handler, W: AsyncWrite + Unpin + Send, - M: Fn((Vec, usize), W) -> T + Unpin + Send + Sync, + M: Fn((Vec, usize), Pin>) -> T + Unpin + Send + Sync, N: Fn(io::Error) -> E + Unpin + Send + Sync, T: Send, E: Send, { - pub(crate) fn new(write: W, data: Vec, map: M, map_err: N) -> Self { + pub(crate) fn new(inner: raw::CancellableInner, data: Vec, map: M, map_err: N) -> Self { AsyncWriteFut { data: Some(data), map, map_err, - write: Some(write), + inner, _act: PhantomData, } } @@ -221,41 +233,78 @@ where } } -impl raw::AsyncMessageFut for AsyncMessageFut +impl raw::AsyncMessageFut for AsyncMessageFut where - A: raw::Handler + 'static, - F: Future + Unpin + Send, - M: Send + 'static, + A: raw::Handler + 'static, + F: Future + Unpin + Send, + M: Fn(O) -> T + Unpin + Send, + O: Send + 'static, + T: Send + 'static, { type Actor = A; fn poll( self: Pin<&mut Self>, ctx: &mut FutContext, - ) -> Poll> { - match Pin::new(&mut self.get_mut().fut).poll(ctx) { - Poll::Ready(msg) => Poll::Ready(Box::new(AsyncMessage::new(msg))), - Poll::Pending => Poll::Pending, + ) -> Poll> { + let fut = self.get_mut(); + let mut inner = if let Some(inner) = fut.inner.get() { + inner + } else { + return Poll::Ready(None); + }; + + match Pin::new(&mut inner).poll(ctx) { + Poll::Ready(output) => { + let msg = (fut.map)(output); + + fut.inner.done(); + Poll::Ready(Some(Box::new(AsyncMessage::new(msg)))) + } + Poll::Pending => { + fut.inner.set(inner); + Poll::Pending + } } } } -impl raw::AsyncMessageStream for AsyncMessageStream +impl raw::AsyncMessageStream for AsyncMessageStream where - A: raw::Handler + 'static, - S: Stream + Unpin + Send, - M: Send + 'static, + A: raw::Handler + 'static, + S: Stream + Unpin + Send, + M: Fn(I) -> T + Unpin + Send, + I: Send + 'static, + T: Send + 'static, { type Actor = A; fn poll_next( self: Pin<&mut Self>, ctx: &mut FutContext, - ) -> Poll> { - match Pin::new(&mut self.get_mut().stream).poll_next(ctx) { - Poll::Ready(Some(msg)) => Poll::Ready(Some(Box::new(AsyncMessage::new(msg)))), - Poll::Ready(None) => Poll::Ready(None), - Poll::Pending => Poll::Pending, + ) -> Poll> { + let stream = self.get_mut(); + let mut inner = if let Some(inner) = stream.inner.get() { + inner + } else { + return Poll::Ready(None); + }; + + match Pin::new(&mut inner).poll_next(ctx) { + Poll::Ready(Some(item)) => { + let msg = (stream.map)(item); + + stream.inner.set(inner); + Poll::Ready(Some(Box::new(AsyncMessage::new(msg)))) + } + Poll::Ready(None) => { + stream.inner.done(); + Poll::Ready(None) + } + Poll::Pending => { + stream.inner.set(inner); + Poll::Pending + } } } } @@ -274,24 +323,34 @@ where fn poll_read( self: Pin<&mut Self>, ctx: &mut FutContext, - ) -> Poll> { + ) -> Poll> { let stream = self.get_mut(); + let mut inner = if let Some(inner) = stream.inner.get() { + inner + } else { + return Poll::Ready(None); + }; - match Pin::new(&mut stream.read).poll_read(ctx, &mut stream.buf) { + match Pin::new(&mut inner).poll_read(ctx, &mut stream.buf) { Poll::Ready(Ok(read)) => { let data = stream.buf.drain(0..read).collect(); stream.buf.resize(stream.cap, 0); let msg = (stream.map)(data); - Poll::Ready(Box::new(AsyncMessage::new(msg))) + stream.inner.set(inner); + Poll::Ready(Some(Box::new(AsyncMessage::new(msg)))) } Poll::Ready(Err(err)) => { let msg = (stream.map_err)(err); - Poll::Ready(Box::new(AsyncMessage::new(msg))) + stream.inner.set(inner); + Poll::Ready(Some(Box::new(AsyncMessage::new(msg)))) + } + Poll::Pending => { + stream.inner.set(inner); + Poll::Pending } - Poll::Pending => Poll::Pending, } } } @@ -300,7 +359,7 @@ impl raw::AsyncMessageFut for AsyncWriteFut where A: raw::Handler + raw::Handler + 'static, W: AsyncWrite + Unpin + Send, - M: Fn((Vec, usize), W) -> T + Unpin + Send + Sync, + M: Fn((Vec, usize), Pin>) -> T + Unpin + Send + Sync, N: Fn(io::Error) -> E + Unpin + Send + Sync, T: Send + 'static, E: Send + 'static, @@ -310,22 +369,32 @@ where fn poll( self: Pin<&mut Self>, ctx: &mut FutContext, - ) -> Poll> { + ) -> Poll> { let fut = self.get_mut(); + let mut inner = if let Some(inner) = fut.inner.get() { + inner + } else { + return Poll::Ready(None); + }; - match Pin::new(&mut fut.write.as_mut().unwrap()).poll_write(ctx, fut.data.as_ref().unwrap()) + match Pin::new(&mut inner).poll_write(ctx, fut.data.as_ref().unwrap()) { Poll::Ready(Ok(wrote)) => { - let msg = (fut.map)((fut.data.take().unwrap(), wrote), fut.write.take().unwrap()); + let msg = (fut.map)((fut.data.take().unwrap(), wrote), inner); - Poll::Ready(Box::new(AsyncMessage::new(msg))) + fut.inner.done(); + Poll::Ready(Some(Box::new(AsyncMessage::new(msg)))) } Poll::Ready(Err(err)) => { let msg = (fut.map_err)(err); - Poll::Ready(Box::new(AsyncMessage::new(msg))) + fut.inner.done(); + Poll::Ready(Some(Box::new(AsyncMessage::new(msg)))) + } + Poll::Pending => { + fut.inner.set(inner); + Poll::Pending } - Poll::Pending => Poll::Pending, } } } diff --git a/aktoro-runtime/src/actor.rs b/aktoro-runtime/src/actor.rs index a10f705..0d308d6 100644 --- a/aktoro-runtime/src/actor.rs +++ b/aktoro-runtime/src/actor.rs @@ -153,10 +153,8 @@ impl Actor { // if the `Spanwed` linked to // this actor has been dropped, // it will return an error. - if let Err(err) = self.ctx.update() { - return Err(Box::new(err).into()); - } - + // TODO: should we take care of the possible errors? + self.ctx.update().ok(); Ok(()) } } diff --git a/aktoro-runtime/src/error.rs b/aktoro-runtime/src/error.rs index f0fb8a6..60a4e67 100644 --- a/aktoro-runtime/src/error.rs +++ b/aktoro-runtime/src/error.rs @@ -10,9 +10,6 @@ pub struct Error { #[derive(Debug)] pub enum ErrorKind { - /// The actor has already been removed from - /// the runtime's actors list. - AlreadyRemoved(u64), /// Returns a `Box` contaning any error type /// that implements the [`Error`] trait. /// @@ -23,13 +20,6 @@ pub enum ErrorKind { } impl Error { - /// Creates a new "already removed" error. - pub(crate) fn already_removed(id: u64) -> Self { - Error { - kind: ErrorKind::AlreadyRemoved(id), - } - } - /// Creates a new boxed error. pub(crate) fn std(err: S) -> Self where @@ -88,17 +78,6 @@ impl Error { } } - /// Whether the error occured because the actor - /// was already removed from the runtime's actors - /// list. - pub fn is_already_removed(&self) -> bool { - if let ErrorKind::AlreadyRemoved(_) = self.kind { - true - } else { - false - } - } - /// Whether multiple errors occured. pub fn is_multiple(&self) -> bool { if let ErrorKind::Multiple(_) = self.kind { @@ -125,9 +104,6 @@ impl StdError for Error {} impl Display for Error { fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { match &self.kind { - ErrorKind::AlreadyRemoved(id) => { - write!(fmt, "actor ({}) already removed from list", id,) - } ErrorKind::Std(err) => write!(fmt, "{}", err), ErrorKind::Multiple(_) => write!(fmt, "multiple errors",), } diff --git a/aktoro-runtime/src/runtime.rs b/aktoro-runtime/src/runtime.rs index d6465c9..47394d9 100644 --- a/aktoro-runtime/src/runtime.rs +++ b/aktoro-runtime/src/runtime.rs @@ -4,7 +4,6 @@ use std::task::Context as FutContext; use std::task::Poll; use aktoro_raw as raw; -use aktoro_raw::Context as RawContext; use fnv::FnvHashMap; use futures_core::Stream; use rand::FromEntropy; @@ -65,12 +64,20 @@ impl raw::Runtime for Runtime { fn spawn(&mut self, actor: A) -> Option> where A: raw::Actor + 'static, + { + self.spawn_with(actor, Default::default()) + } + + fn spawn_with(&mut self, actor: A, config: C::Config) -> Option> + where + A: raw::Actor + 'static, + C: raw::Context, { // Generate the actor's ID. let id = self.rng.next_u64(); // Create a new context for the actor. - let mut ctx = A::Context::new(id); + let mut ctx = C::new(id, config); // Create a new `Spawned` struct from // the actor's context. @@ -151,7 +158,7 @@ impl Stream for Wait { (None, Err(err)) => { return Poll::Ready(Some(Err(( id, - Error::multiple(vec![Error::already_removed(id), Error::std(err)]), + Error::std(err), )))) } _ => return Poll::Ready(Some(Ok(id))), @@ -161,11 +168,9 @@ impl Stream for Wait { // TODO match Pin::new(&mut rt.recver).poll_next(ctx) { Poll::Ready(Some(actor)) => { - if rt.actors.remove(&actor).is_none() { - return Poll::Ready(Some(Err((actor, Error::already_removed(actor))))); - } else { - return Poll::Ready(Some(Ok(actor))); - } + rt.actors.remove(&actor); + + return Poll::Ready(Some(Ok(actor))); } Poll::Ready(None) => return Poll::Ready(None), Poll::Pending => (), diff --git a/aktoro-runtime/src/tcp.rs b/aktoro-runtime/src/tcp.rs index 8c0ce24..c5dda89 100644 --- a/aktoro-runtime/src/tcp.rs +++ b/aktoro-runtime/src/tcp.rs @@ -191,7 +191,10 @@ impl AsyncRead for TcpClient { ctx: &mut FutContext, buf: &mut [u8], ) -> Poll> { - Pin::new(&mut self.get_mut().stream).poll_read(ctx, buf) + match Pin::new(&mut self.get_mut().stream).poll_read(ctx, buf) { + Poll::Ready(Ok(read)) if read == 0 => Poll::Pending, + polled => polled, + } } } @@ -219,7 +222,10 @@ impl AsyncRead for TcpStream { ctx: &mut FutContext, buf: &mut [u8], ) -> Poll> { - Pin::new(&mut self.get_mut().stream).poll_read(ctx, buf) + match Pin::new(&mut self.get_mut().stream).poll_read(ctx, buf) { + Poll::Ready(Ok(read)) if read == 0 => Poll::Pending, + polled => polled, + } } } From 11f8fde376f470bc3f16f20f5c12bf86d4e5f128 Mon Sep 17 00:00:00 2001 From: Matthieu Le Brazidec Date: Fri, 12 Jul 2019 20:00:36 +0200 Subject: [PATCH 15/22] Exported more types. --- src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 75900dd..0c92681 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,6 +9,8 @@ pub use aktoro_runtime as runtime; pub mod prelude { pub use aktoro_raw::Actor; pub use aktoro_raw::Context as RawContext; + pub use aktoro_raw::Cancellable; + pub use aktoro_raw::Cancelling; pub use aktoro_raw::ActionHandler; pub use aktoro_raw::EventHandler; @@ -27,7 +29,9 @@ pub mod prelude { pub use aktoro_raw::NetworkManager as RawNetworkManager; pub use aktoro_raw::TcpClient as RawTcpClient; pub use aktoro_raw::TcpServer as RawTcpServer; + pub use aktoro_raw::TcpServerIncoming; pub use aktoro_raw::TcpStream as RawTcpStream; + pub use aktoro_raw::OwnedTcpServerIncoming; pub use aktoro_raw::UdpSocket as RawUdpSocket; #[cfg(feature = "context")] From 0e3c6322bb7930391fad377993af20cd5c2c8188 Mon Sep 17 00:00:00 2001 From: Matthieu Le Brazidec Date: Fri, 12 Jul 2019 20:00:54 +0200 Subject: [PATCH 16/22] Updated the examples. --- examples/net/src/agent.rs | 80 +++++++++++++++++++ examples/net/src/client.rs | 100 +++++++++++++++++++++++ examples/net/src/main.rs | 160 +++---------------------------------- examples/net/src/server.rs | 80 +++++++++++++++++++ 4 files changed, 271 insertions(+), 149 deletions(-) create mode 100644 examples/net/src/agent.rs create mode 100644 examples/net/src/client.rs create mode 100644 examples/net/src/server.rs diff --git a/examples/net/src/agent.rs b/examples/net/src/agent.rs new file mode 100644 index 0000000..c0e52ab --- /dev/null +++ b/examples/net/src/agent.rs @@ -0,0 +1,80 @@ +use std::pin::Pin; + +use aktoro::prelude::*; +use aktoro::raw; +use futures_util::io::ReadHalf; +use futures_util::io::WriteHalf; + +use crate::Received; +use crate::Sent; + +struct Closed; + +pub(crate) struct Agent { + pub(crate) read: Option>>>, + pub(crate) write: Option>>>, + pub(crate) cancellable: Option>>, +} + +impl Actor for Agent +where + S: raw::TcpStream + 'static, +{ + type Context = Context; + type Status = Status; + type Error = Error; + + fn started(&mut self, ctx: &mut Self::Context) { + println!("agent({}): started", ctx.actor_id()); + + self.cancellable = Some( + ctx.read(self.read.take().unwrap(), 64, Received, |_| ()), + ); + } +} + +impl Handler> for Agent +where + S: raw::TcpStream + 'static, +{ + type Output = (); + + fn handle(&mut self, _: Sent, ctx: &mut Self::Context) -> Result<(), Self::Error> { + println!("agent({}): sent data", ctx.actor_id()); + + println!("agent({}): closing stream", ctx.actor_id()); + ctx.wait(Box::pin(self.cancellable.take().unwrap().cancel()), |_| Closed); + + Ok(()) + } +} + +impl Handler for Agent +where + S: raw::TcpStream + 'static, +{ + type Output = (); + + fn handle(&mut self, msg: Received, ctx: &mut Self::Context) -> Result<(), Self::Error> { + println!("agent({}): received data; data={:?}", ctx.actor_id(), msg.0); + + ctx.write(self.write.take().unwrap(), vec![0], |_, write| Sent(write), |_| ()); + + Ok(()) + } +} + +impl Handler for Agent +where + S: raw::TcpStream + 'static, +{ + type Output = (); + + fn handle(&mut self, _: Closed, ctx: &mut Self::Context) -> Result<(), Self::Error> { + println!("agent({}): closed stream", ctx.actor_id()); + + ctx.set_status(Status::Dead); + + Ok(()) + } +} diff --git a/examples/net/src/client.rs b/examples/net/src/client.rs new file mode 100644 index 0000000..168d158 --- /dev/null +++ b/examples/net/src/client.rs @@ -0,0 +1,100 @@ +use std::pin::Pin; + +use aktoro::prelude::*; +use aktoro::raw; +use futures_util::AsyncReadExt; +use futures_util::io::WriteHalf; + +use crate::Received; +use crate::Sent; + +struct Connected(C); + +struct ConnectedErr(::Error); + +pub(crate) struct Client { + pub(crate) connect: Option>>, + pub(crate) closed_connect: Option>>, + pub(crate) write: Option>>>, +} + +impl Actor for Client +where + C: raw::TcpClient + 'static, +{ + type Context = Context; + type Status = Status; + type Error = Error; + + fn started(&mut self, ctx: &mut Self::Context) { + println!("client({}): started", ctx.actor_id()); + println!("client({}): connecting", ctx.actor_id()); + + let connect = self.connect.take().unwrap(); + ctx.wait(connect, |res| Connected(res.unwrap())); + } +} + +impl Handler> for Client +where + C: raw::TcpClient + 'static, +{ + type Output = (); + + fn handle(&mut self, msg: Connected, ctx: &mut Self::Context) -> Result<(), Self::Error> { + println!("client({}): connected", ctx.actor_id()); + + let (read, write) = msg.0.split(); + ctx.read(Box::pin(read), 64, Received, |_| ()); + ctx.write(Box::pin(write), vec![0], |_, write| Sent(write), |_| ()); + + Ok(()) + } +} + +impl Handler> for Client +where + C: raw::TcpClient + 'static, +{ + type Output = (); + + fn handle(&mut self, msg: ConnectedErr, ctx: &mut Self::Context) -> Result<(), Self::Error> { + println!("client({}): failed connecting; reason={}", ctx.actor_id(), msg.0); + + ctx.set_status(Status::Dead); + + Ok(()) + } +} + +impl Handler> for Client +where + C: raw::TcpClient + 'static, +{ + type Output = (); + + fn handle(&mut self, msg: Sent, ctx: &mut Self::Context) -> Result<(), Self::Error> { + println!("client({}): sent data", ctx.actor_id()); + + self.write = Some(msg.0); + + Ok(()) + } +} + +impl Handler for Client +where + C: raw::TcpClient + 'static, +{ + type Output = (); + + fn handle(&mut self, msg: Received, ctx: &mut Self::Context) -> Result<(), Self::Error> { + println!("client({}): received data; data={:?}", ctx.actor_id(), msg.0); + + println!("client({}): connecting (failing)", ctx.actor_id()); + let connect = self.closed_connect.take().unwrap(); + ctx.wait(connect, |res| ConnectedErr(res.err().unwrap())); + + Ok(()) + } +} diff --git a/examples/net/src/main.rs b/examples/net/src/main.rs index 9191f1f..474ac6d 100644 --- a/examples/net/src/main.rs +++ b/examples/net/src/main.rs @@ -1,163 +1,23 @@ #![feature(async_await)] +use std::pin::Pin; + use aktoro::prelude::*; use aktoro::raw; -use futures_util::io::AsyncReadExt; -use futures_util::io::ReadHalf; use futures_util::io::WriteHalf; use futures_util::StreamExt; -struct Client { - connect: Option, - write: Option>, -} - -struct Server { - tcp: Option, -} - -struct Agent { - read: Option>, -} - -struct Connected(C); +mod agent; +mod client; +mod server; -struct Connection(S::Stream); +use client::Client; +use server::Server; -struct Sent(WriteHalf); +struct Sent(Pin>>); struct Received(Vec); -struct Died; - -impl Actor for Client -where - C: raw::TcpClient + 'static, -{ - type Context = Context; - type Status = Status; - type Error = Error; - - fn started(&mut self, ctx: &mut Self::Context) { - let connect = self.connect.take().unwrap(); - - ctx.wait(connect, |client| Connected(client.unwrap())); - } -} - -impl Actor for Server -where - S: raw::TcpServer + 'static, -{ - type Context = Context; - type Status = Status; - type Error = Error; - - fn started(&mut self, ctx: &mut Self::Context) { - let tcp = self.tcp.take().unwrap(); - println!("listening on {}", tcp.local_addr().unwrap()); - - ctx.subscribe(tcp.into_incoming().unwrap(), |conn| { - Connection(conn.unwrap()) - }); - } -} - -impl Actor for Agent -where - S: raw::TcpStream + 'static, -{ - type Context = Context; - type Status = Status; - type Error = Error; - - fn started(&mut self, ctx: &mut Self::Context) { - ctx.read(self.read.take().unwrap(), 64, Received, |_| ()); - } -} - -impl Handler> for Client -where - C: raw::TcpClient + 'static, -{ - type Output = (); - - fn handle(&mut self, msg: Connected, ctx: &mut Self::Context) -> Result<(), Self::Error> { - let client = msg.0; - println!("connected to {}", client.peer_addr().unwrap()); - - let (_, write) = client.split(); - ctx.write(write, vec![0], |_, write| Sent(write), |_| ()); - - Ok(()) - } -} - -impl Handler> for Server -where - S: raw::TcpServer + 'static, -{ - type Output = (); - - fn handle(&mut self, msg: Connection, ctx: &mut Self::Context) -> Result<(), Self::Error> { - let conn = msg.0; - println!("new connection from {}", conn.peer_addr().unwrap()); - - let (read, _) = conn.split(); - let spawned = ctx.spawn(Agent { read: Some(read) }).unwrap(); - - ctx.subscribe(spawned, |_| Died); - - Ok(()) - } -} - -impl Handler> for Client -where - C: raw::TcpClient + 'static, -{ - type Output = (); - - fn handle(&mut self, sent: Sent, ctx: &mut Self::Context) -> Result<(), Self::Error> { - println!("sent data"); - self.write = Some(sent.0); - - ctx.set_status(Status::Dead); - - Ok(()) - } -} - -impl Handler for Agent -where - S: raw::TcpStream + 'static, -{ - type Output = (); - - fn handle(&mut self, msg: Received, ctx: &mut Self::Context) -> Result<(), Self::Error> { - println!("received {:?}", msg.0); - - ctx.set_status(Status::Dead); - - Ok(()) - } -} - -impl Handler for Server -where - S: raw::TcpServer + 'static, -{ - type Output = (); - - fn handle(&mut self, _: Died, ctx: &mut Self::Context) -> Result<(), Self::Error> { - println!("agent died; remaining agents: {:?}", ctx.actors()); - - ctx.set_status(Status::Dead); - - Ok(()) - } -} - #[runtime::main] async fn main() { let mut rt = Runtime::new(); @@ -165,12 +25,14 @@ async fn main() { let server = Server { tcp: Some(net.tcp_bind("127.0.0.1:5555").unwrap()), + cancellable: None, }; rt.spawn(server).unwrap(); let client = Client:: { - connect: Some(net.tcp_connect("127.0.0.1:5555").unwrap()), + connect: Some(Box::pin(net.tcp_connect("127.0.0.1:5555").unwrap())), + closed_connect: Some(Box::pin(net.tcp_connect("127.0.0.1:5555").unwrap())), write: None, }; diff --git a/examples/net/src/server.rs b/examples/net/src/server.rs new file mode 100644 index 0000000..2579255 --- /dev/null +++ b/examples/net/src/server.rs @@ -0,0 +1,80 @@ +use aktoro::prelude::*; +use aktoro::raw; +use futures_util::AsyncReadExt; +use futures_util::StreamExt; + +use crate::agent::Agent; + +struct Connection(S::Stream); + +struct Died; + +pub(crate) struct Server { + pub(crate) tcp: Option, + pub(crate) cancellable: Option>>, +} + +impl Actor for Server +where + S: raw::TcpServer + 'static, +{ + type Context = Context; + type Status = Status; + type Error = Error; + + fn started(&mut self, ctx: &mut Self::Context) { + println!("server({}): started", ctx.actor_id()); + println!("server({}): listening", ctx.actor_id()); + + let tcp = self.tcp.take().unwrap(); + self.cancellable = Some( + ctx.subscribe(Box::pin(tcp.into_incoming().unwrap()), |conn| { + Connection(conn.unwrap()) + }), + ); + } +} + +impl Handler> for Server +where + S: raw::TcpServer + 'static, +{ + type Output = (); + + fn handle(&mut self, msg: Connection, ctx: &mut Self::Context) -> Result<(), Self::Error> { + println!("server({}): new connection", ctx.actor_id()); + + let actor_id = ctx.actor_id(); + println!("server({}): closing", actor_id); + ctx.blocking_wait(Box::pin(self.cancellable.take().unwrap().cancel()), move |_| { + println!("server({}): closed", actor_id); + () + }); + + let (read, write) = msg.0.split(); + let spawned = ctx.spawn(Agent { + read: Some(Box::pin(read)), + write: Some(Box::pin(write)), + cancellable: None, + }).unwrap(); + + ctx.subscribe(spawned.boxed(), |_| Died); + + Ok(()) + } +} + +impl Handler for Server +where + S: raw::TcpServer + 'static, +{ + type Output = (); + + fn handle(&mut self, _: Died, ctx: &mut Self::Context) -> Result<(), Self::Error> { + println!("server({}): agent died; remaining: {:?}", ctx.actor_id(), ctx.actors()); + + ctx.set_status(Status::Dead); + + Ok(()) + } +} From 49d8b1253a144ef09a93a687e2d7b5870dd25ceb Mon Sep 17 00:00:00 2001 From: Matthieu Le Brazidec Date: Fri, 12 Jul 2019 20:45:08 +0200 Subject: [PATCH 17/22] Removed the tests for now. --- aktoro-channel/tests/tests.rs | 185 ---------------------------------- 1 file changed, 185 deletions(-) delete mode 100644 aktoro-channel/tests/tests.rs diff --git a/aktoro-channel/tests/tests.rs b/aktoro-channel/tests/tests.rs deleted file mode 100644 index 6326adc..0000000 --- a/aktoro-channel/tests/tests.rs +++ /dev/null @@ -1,185 +0,0 @@ -#![feature(async_await)] - -use aktoro_channel::*; -use futures_util::poll; -use futures_util::StreamExt; - -#[test] -fn base() { - let (sender, recver) = Builder::new().build(); - works(&sender, &recver); -} - -#[runtime::test] -async fn async_base() { - let (sender, recver) = Builder::new().build(); - async_works(&sender, &recver).await; -} - -#[runtime::test] -async fn notify() { - let (sender, recver) = Builder::new().build(); - async_works(&sender, &recver).await; - - let mut notify = sender.try_send_notify(2).unwrap(); - assert!(poll!(&mut notify).is_pending()); - - assert_eq!(recver.try_recv(), Ok(Some(2))); - assert!(poll!(&mut notify).is_ready()); -} - -#[test] -fn disconnect_sender() { - let (mut sender, recver) = Builder::new().build(); - works(&sender, &recver); - - assert_eq!(sender.try_send(2), Ok(())); - - sender.disconnect(); - - assert!(sender.is_closed()); - assert!(recver.is_closed()); - - assert_eq!(recver.try_recv(), Ok(Some(2))); - assert!(recver.try_recv().unwrap_err().is_closed()); -} - -#[test] -fn disconnect_recver() { - let (sender, mut recver) = Builder::new().build(); - works(&sender, &recver); - - recver.disconnect(); - - assert!(sender.is_closed()); - assert!(recver.is_closed()); -} - -#[test] -fn close_sender() { - let (sender, recver) = Builder::new().build(); - works(&sender, &recver); - - assert_eq!(sender.try_send(2), Ok(())); - - sender.close_channel(); - - assert!(sender.is_closed()); - assert!(recver.is_closed()); - - assert_eq!(recver.try_recv(), Ok(Some(2))); - assert!(sender.try_send(1).unwrap_err().is_closed()); - assert!(recver.try_recv().unwrap_err().is_closed()); -} - -#[test] -fn close_recver() { - let (sender, recver) = Builder::new().build(); - works(&sender, &recver); - - assert_eq!(sender.try_send(2), Ok(())); - - recver.close_channel(); - - assert!(sender.is_closed()); - assert!(recver.is_closed()); - - assert_eq!(recver.try_recv(), Ok(Some(2))); - assert!(sender.try_send(1).unwrap_err().is_closed()); - assert!(recver.try_recv().unwrap_err().is_closed()); -} - -#[test] -fn drop_senders() { - let (sender, recver) = Builder::new().build(); - works(&sender, &recver); - - assert_eq!(sender.try_send(2), Ok(())); - - drop(sender); - - assert!(recver.is_closed()); - assert_eq!(recver.try_recv(), Ok(Some(2))); - assert!(recver.try_recv().unwrap_err().is_closed()); -} - -#[test] -fn drop_recvers() { - let (sender, recver) = Builder::new().build(); - works(&sender, &recver); - - drop(recver); - - assert!(sender.is_closed()); - assert!(sender.try_send(2).unwrap_err().is_closed()); -} - -#[test] -fn msgs_limit() { - let (sender, recver) = Builder::new().limited_msgs(3).build(); - works(&sender, &recver); - - assert_eq!(sender.try_send(2), Ok(())); - assert!(sender.try_send(3).unwrap_err().is_limit()); -} - -#[test] -fn senders_limit() { - let (sender, recver) = Builder::new().limited_senders(3).build(); - works(&sender, &recver); - - let _2 = sender.try_clone().unwrap(); - let _1 = sender.try_clone().unwrap(); - - assert!(sender.try_clone().is_err()); -} - -#[test] -fn recvers_limit() { - let (sender, recver) = Builder::new().limited_receivers(3).build(); - works(&sender, &recver); - - let _2 = recver.try_clone().unwrap(); - let _1 = recver.try_clone().unwrap(); - - assert!(recver.try_clone().is_err()); -} - -fn works(sender: &Sender, recver: &Receiver) { - let (sender1, recver1) = (sender.try_clone().unwrap(), recver.try_clone().unwrap()); - - let (sender2, recver2) = (sender1.try_clone().unwrap(), recver1.try_clone().unwrap()); - - assert_eq!(recver1.try_recv(), Ok(None)); - assert_eq!(recver2.try_recv(), Ok(None)); - - assert_eq!(sender1.try_send(0), Ok(())); - assert_eq!(sender2.try_send(1), Ok(())); - - assert_eq!(recver2.try_recv(), Ok(Some(0))); - assert_eq!(recver1.try_recv(), Ok(Some(1))); - - assert_eq!(recver1.try_recv(), Ok(None)); - assert_eq!(recver2.try_recv(), Ok(None)); -} - -async fn async_works<'c>(sender: &'c Sender, recver: &'c Receiver) { - let (sender1, mut recver1) = (sender.try_clone().unwrap(), recver.try_clone().unwrap()); - - let (sender2, mut recver2) = (sender1.try_clone().unwrap(), recver1.try_clone().unwrap()); - - let mut next1 = recver1.next(); - let mut next2 = recver2.next(); - - assert!(poll!(&mut next1).is_pending()); - assert!(poll!(&mut next2).is_pending()); - - assert_eq!(sender1.try_send(0), Ok(())); - assert_eq!(sender2.try_send(1), Ok(())); - - assert_eq!(next1.await, Some(0)); - assert_eq!(next2.await, Some(1)); - - assert_eq!(recver1.try_recv(), Ok(None)); - assert_eq!(recver2.try_recv(), Ok(None)); -} From 0366a71d5c38b4e435daee3f6e82e4d1620f26e9 Mon Sep 17 00:00:00 2001 From: Matthieu Le Brazidec Date: Fri, 12 Jul 2019 20:50:47 +0200 Subject: [PATCH 18/22] Updated the CI configuration for better clippy integration. --- ci/azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/azure-pipelines.yml b/ci/azure-pipelines.yml index 4e84802..4d246c0 100644 --- a/ci/azure-pipelines.yml +++ b/ci/azure-pipelines.yml @@ -11,5 +11,5 @@ jobs: displayName: 'Test' - bash: | rustup component add clippy - cargo clippy --all-targets --all-features -- -D warnings + cargo clippy --all --all-features -- -D warnings displayName: 'Clippy' From 61b754c37e17ef044156f4d85d2499b3904b018f Mon Sep 17 00:00:00 2001 From: Matthieu Le Brazidec Date: Fri, 12 Jul 2019 20:53:04 +0200 Subject: [PATCH 19/22] Formatting. --- aktoro-context/src/context.rs | 28 ++++++++++++++++++++++------ aktoro-context/src/message.rs | 13 +++---------- aktoro-raw/src/context.rs | 28 +++++++++++++++++++++++----- aktoro-raw/src/message.rs | 8 ++------ aktoro-raw/src/tcp.rs | 15 ++++++++++----- aktoro-runtime/src/runtime.rs | 7 +------ examples/hello_world/src/main.rs | 15 ++++++--------- examples/net/src/agent.rs | 15 ++++++++++----- examples/net/src/client.rs | 14 +++++++++++--- examples/net/src/server.rs | 26 ++++++++++++++++---------- src/lib.rs | 4 ++-- 11 files changed, 106 insertions(+), 67 deletions(-) diff --git a/aktoro-context/src/context.rs b/aktoro-context/src/context.rs index 9730f58..98532d6 100644 --- a/aktoro-context/src/context.rs +++ b/aktoro-context/src/context.rs @@ -250,7 +250,13 @@ where cancellable } - fn read(&mut self, read: Pin>, cap: usize, map: M, map_err: N) -> raw::Cancellable + fn read( + &mut self, + read: Pin>, + cap: usize, + map: M, + map_err: N, + ) -> raw::Cancellable where R: AsyncRead + Unpin + Send + 'static, M: Fn(Vec) -> T + Unpin + Send + Sync + 'static, @@ -267,7 +273,13 @@ where cancellable } - fn write(&mut self, write: Pin>, data: Vec, map: M, map_err: N) -> raw::Cancellable + fn write( + &mut self, + write: Pin>, + data: Vec, + map: M, + map_err: N, + ) -> raw::Cancellable where W: AsyncWrite + Unpin + Send + 'static, M: Fn((Vec, usize), Pin>) -> T + Unpin + Send + Sync + 'static, @@ -284,7 +296,13 @@ where cancellable } - fn blocking_write(&mut self, write: Pin>, data: Vec, map: M, map_err: N) -> raw::Cancellable + fn blocking_write( + &mut self, + write: Pin>, + data: Vec, + map: M, + map_err: N, + ) -> raw::Cancellable where W: AsyncWrite + Unpin + Send + 'static, M: Fn((Vec, usize), Pin>) -> T + Unpin + Send + Sync + 'static, @@ -470,8 +488,6 @@ where impl Default for ContextConfig { fn default() -> Self { - ContextConfig { - ready: None, - } + ContextConfig { ready: None } } } diff --git a/aktoro-context/src/message.rs b/aktoro-context/src/message.rs index 147ec6e..9f8f674 100644 --- a/aktoro-context/src/message.rs +++ b/aktoro-context/src/message.rs @@ -243,10 +243,7 @@ where { type Actor = A; - fn poll( - self: Pin<&mut Self>, - ctx: &mut FutContext, - ) -> Poll> { + fn poll(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll> { let fut = self.get_mut(); let mut inner = if let Some(inner) = fut.inner.get() { inner @@ -366,10 +363,7 @@ where { type Actor = A; - fn poll( - self: Pin<&mut Self>, - ctx: &mut FutContext, - ) -> Poll> { + fn poll(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll> { let fut = self.get_mut(); let mut inner = if let Some(inner) = fut.inner.get() { inner @@ -377,8 +371,7 @@ where return Poll::Ready(None); }; - match Pin::new(&mut inner).poll_write(ctx, fut.data.as_ref().unwrap()) - { + match Pin::new(&mut inner).poll_write(ctx, fut.data.as_ref().unwrap()) { Poll::Ready(Ok(wrote)) => { let msg = (fut.map)((fut.data.take().unwrap(), wrote), inner); diff --git a/aktoro-raw/src/context.rs b/aktoro-raw/src/context.rs index bfeb32f..8dd5f07 100644 --- a/aktoro-raw/src/context.rs +++ b/aktoro-raw/src/context.rs @@ -145,7 +145,13 @@ pub trait Context: Stream> + Unpin + Send + Sized { T: Send + 'static; // TODO - fn read(&mut self, read: Pin>, cap: usize, map: M, map_err: N) -> Cancellable + fn read( + &mut self, + read: Pin>, + cap: usize, + map: M, + map_err: N, + ) -> Cancellable where R: AsyncRead + Unpin + Send + 'static, M: Fn(Vec) -> T + Unpin + Send + Sync + 'static, @@ -155,7 +161,13 @@ pub trait Context: Stream> + Unpin + Send + Sized { E: Send + 'static; // TODO - fn write(&mut self, write: Pin>, data: Vec, map: M, map_err: N) -> Cancellable + fn write( + &mut self, + write: Pin>, + data: Vec, + map: M, + map_err: N, + ) -> Cancellable where W: AsyncWrite + Unpin + Send + 'static, M: Fn((Vec, usize), Pin>) -> T + Unpin + Send + Sync + 'static, @@ -165,7 +177,13 @@ pub trait Context: Stream> + Unpin + Send + Sized { E: Send + 'static; // TODO - fn blocking_write(&mut self, write: Pin>, data: Vec, map: M, map_err: N) -> Cancellable + fn blocking_write( + &mut self, + write: Pin>, + data: Vec, + map: M, + map_err: N, + ) -> Cancellable where W: AsyncWrite + Unpin + Send + 'static, M: Fn((Vec, usize), Pin>) -> T + Unpin + Send + Sync + 'static, @@ -206,9 +224,9 @@ impl Cancellable { inner: inner.clone(), done: done.clone(), waker: waker.clone(), - } + }, }, - CancellableInner { inner, done, waker, }, + CancellableInner { inner, done, waker }, ) } diff --git a/aktoro-raw/src/message.rs b/aktoro-raw/src/message.rs index 37d4654..682094f 100644 --- a/aktoro-raw/src/message.rs +++ b/aktoro-raw/src/message.rs @@ -25,17 +25,13 @@ pub trait AsyncMessageFut: Send { pub trait AsyncMessageStream: Send { type Actor: Actor; - fn poll_next(self: Pin<&mut Self>, ctx: &mut FutContext) - -> Poll>; + fn poll_next(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll>; } pub trait AsyncReadStream: Send { type Actor: Actor; - fn poll_read( - self: Pin<&mut Self>, - ctx: &mut FutContext, - ) -> Poll>; + fn poll_read(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll>; } pub trait Handler: Actor { diff --git a/aktoro-raw/src/tcp.rs b/aktoro-raw/src/tcp.rs index 245df4a..69f173d 100644 --- a/aktoro-raw/src/tcp.rs +++ b/aktoro-raw/src/tcp.rs @@ -7,8 +7,15 @@ use futures_core::Stream; use futures_io::AsyncRead; use futures_io::AsyncWrite; -pub type TcpServerIncoming<'s, S> = Box::Stream, ::Error>> + Unpin + Send + 's>; -pub type OwnedTcpServerIncoming = Box::Stream, ::Error>> + Unpin + Send>; +pub type TcpServerIncoming<'s, S> = Box< + dyn Stream::Stream, ::Error>> + + Unpin + + Send + + 's, +>; +pub type OwnedTcpServerIncoming = Box< + dyn Stream::Stream, ::Error>> + Unpin + Send, +>; pub trait TcpClient: TcpStream + Unpin + Send + Sized { type Connect: Future::Error>> + Unpin + Send; @@ -37,9 +44,7 @@ pub trait TcpServer: Unpin + Send + Sized { fn incoming(&mut self) -> Result, Self::Error>; // TODO - fn into_incoming( - self, - ) -> Result, Self::Error>; + fn into_incoming(self) -> Result, Self::Error>; } pub trait TcpStream: AsyncRead + AsyncWrite + Unpin + Send { diff --git a/aktoro-runtime/src/runtime.rs b/aktoro-runtime/src/runtime.rs index 47394d9..03d9efc 100644 --- a/aktoro-runtime/src/runtime.rs +++ b/aktoro-runtime/src/runtime.rs @@ -155,12 +155,7 @@ impl Stream for Wait { match (removed, res) { (Some(_), Err(err)) => return Poll::Ready(Some(Err((id, err)))), - (None, Err(err)) => { - return Poll::Ready(Some(Err(( - id, - Error::std(err), - )))) - } + (None, Err(err)) => return Poll::Ready(Some(Err((id, Error::std(err))))), _ => return Poll::Ready(Some(Ok(id))), } } diff --git a/examples/hello_world/src/main.rs b/examples/hello_world/src/main.rs index 24509c7..9fcbb07 100644 --- a/examples/hello_world/src/main.rs +++ b/examples/hello_world/src/main.rs @@ -52,15 +52,12 @@ async fn main() { let mut run = runtime::spawn(run("World", spawned)).fuse(); let mut wait = rt.wait().fuse(); - loop { - select! { - _ = run => break, - res = wait.next() => { - res.unwrap() - .expect("an error occured while waiting for the runtime to stop"); - break; - }, - } + select! { + _ = run => (), + res = wait.next() => { + res.unwrap() + .expect("an error occured while waiting for the runtime to stop"); + }, } } diff --git a/examples/net/src/agent.rs b/examples/net/src/agent.rs index c0e52ab..75bd02f 100644 --- a/examples/net/src/agent.rs +++ b/examples/net/src/agent.rs @@ -27,9 +27,7 @@ where fn started(&mut self, ctx: &mut Self::Context) { println!("agent({}): started", ctx.actor_id()); - self.cancellable = Some( - ctx.read(self.read.take().unwrap(), 64, Received, |_| ()), - ); + self.cancellable = Some(ctx.read(self.read.take().unwrap(), 64, Received, |_| ())); } } @@ -43,7 +41,9 @@ where println!("agent({}): sent data", ctx.actor_id()); println!("agent({}): closing stream", ctx.actor_id()); - ctx.wait(Box::pin(self.cancellable.take().unwrap().cancel()), |_| Closed); + ctx.wait(Box::pin(self.cancellable.take().unwrap().cancel()), |_| { + Closed + }); Ok(()) } @@ -58,7 +58,12 @@ where fn handle(&mut self, msg: Received, ctx: &mut Self::Context) -> Result<(), Self::Error> { println!("agent({}): received data; data={:?}", ctx.actor_id(), msg.0); - ctx.write(self.write.take().unwrap(), vec![0], |_, write| Sent(write), |_| ()); + ctx.write( + self.write.take().unwrap(), + vec![0], + |_, write| Sent(write), + |_| (), + ); Ok(()) } diff --git a/examples/net/src/client.rs b/examples/net/src/client.rs index 168d158..34c4635 100644 --- a/examples/net/src/client.rs +++ b/examples/net/src/client.rs @@ -2,8 +2,8 @@ use std::pin::Pin; use aktoro::prelude::*; use aktoro::raw; -use futures_util::AsyncReadExt; use futures_util::io::WriteHalf; +use futures_util::AsyncReadExt; use crate::Received; use crate::Sent; @@ -59,7 +59,11 @@ where type Output = (); fn handle(&mut self, msg: ConnectedErr, ctx: &mut Self::Context) -> Result<(), Self::Error> { - println!("client({}): failed connecting; reason={}", ctx.actor_id(), msg.0); + println!( + "client({}): failed connecting; reason={}", + ctx.actor_id(), + msg.0 + ); ctx.set_status(Status::Dead); @@ -89,7 +93,11 @@ where type Output = (); fn handle(&mut self, msg: Received, ctx: &mut Self::Context) -> Result<(), Self::Error> { - println!("client({}): received data; data={:?}", ctx.actor_id(), msg.0); + println!( + "client({}): received data; data={:?}", + ctx.actor_id(), + msg.0 + ); println!("client({}): connecting (failing)", ctx.actor_id()); let connect = self.closed_connect.take().unwrap(); diff --git a/examples/net/src/server.rs b/examples/net/src/server.rs index 2579255..0f14802 100644 --- a/examples/net/src/server.rs +++ b/examples/net/src/server.rs @@ -46,17 +46,19 @@ where let actor_id = ctx.actor_id(); println!("server({}): closing", actor_id); - ctx.blocking_wait(Box::pin(self.cancellable.take().unwrap().cancel()), move |_| { - println!("server({}): closed", actor_id); - () - }); + ctx.blocking_wait( + Box::pin(self.cancellable.take().unwrap().cancel()), + move |_| println!("server({}): closed", actor_id), + ); let (read, write) = msg.0.split(); - let spawned = ctx.spawn(Agent { - read: Some(Box::pin(read)), - write: Some(Box::pin(write)), - cancellable: None, - }).unwrap(); + let spawned = ctx + .spawn(Agent { + read: Some(Box::pin(read)), + write: Some(Box::pin(write)), + cancellable: None, + }) + .unwrap(); ctx.subscribe(spawned.boxed(), |_| Died); @@ -71,7 +73,11 @@ where type Output = (); fn handle(&mut self, _: Died, ctx: &mut Self::Context) -> Result<(), Self::Error> { - println!("server({}): agent died; remaining: {:?}", ctx.actor_id(), ctx.actors()); + println!( + "server({}): agent died; remaining: {:?}", + ctx.actor_id(), + ctx.actors() + ); ctx.set_status(Status::Dead); diff --git a/src/lib.rs b/src/lib.rs index 0c92681..34cf4e8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,9 +8,9 @@ pub use aktoro_runtime as runtime; pub mod prelude { pub use aktoro_raw::Actor; - pub use aktoro_raw::Context as RawContext; pub use aktoro_raw::Cancellable; pub use aktoro_raw::Cancelling; + pub use aktoro_raw::Context as RawContext; pub use aktoro_raw::ActionHandler; pub use aktoro_raw::EventHandler; @@ -27,11 +27,11 @@ pub mod prelude { pub use aktoro_raw::Updater as RawUpdater; pub use aktoro_raw::NetworkManager as RawNetworkManager; + pub use aktoro_raw::OwnedTcpServerIncoming; pub use aktoro_raw::TcpClient as RawTcpClient; pub use aktoro_raw::TcpServer as RawTcpServer; pub use aktoro_raw::TcpServerIncoming; pub use aktoro_raw::TcpStream as RawTcpStream; - pub use aktoro_raw::OwnedTcpServerIncoming; pub use aktoro_raw::UdpSocket as RawUdpSocket; #[cfg(feature = "context")] From 7aa35442ec8ccc4c215c658781e450bf0d442430 Mon Sep 17 00:00:00 2001 From: Matthieu Le Brazidec Date: Fri, 12 Jul 2019 22:03:21 +0200 Subject: [PATCH 20/22] Formatting. --- aktoro-channel/src/channel.rs | 8 +++++--- aktoro-channel/src/error.rs | 8 ++++---- aktoro-context/src/channel.rs | 4 ++-- aktoro-context/src/context.rs | 4 ++-- aktoro-context/src/control.rs | 4 ++-- aktoro-context/src/message.rs | 16 +++++++++++----- aktoro-context/src/respond.rs | 4 ++-- aktoro-context/src/update.rs | 4 ++-- aktoro-raw/src/actor.rs | 4 ++-- aktoro-raw/src/channel.rs | 4 ++-- aktoro-raw/src/context.rs | 4 ++-- aktoro-raw/src/control.rs | 4 ++-- aktoro-raw/src/lib.rs | 2 -- aktoro-raw/src/message.rs | 14 ++++++++++---- aktoro-raw/src/runtime.rs | 4 ++-- aktoro-raw/src/spawned.rs | 4 ++-- aktoro-raw/src/tcp.rs | 8 ++++---- aktoro-raw/src/udp.rs | 4 ++-- aktoro-raw/src/update.rs | 4 ++-- aktoro-runtime/src/actor.rs | 8 ++++---- aktoro-runtime/src/error.rs | 10 +++++----- aktoro-runtime/src/runtime.rs | 4 ++-- aktoro-runtime/src/tcp.rs | 34 +++++++++++++++++----------------- aktoro-runtime/src/udp.rs | 6 +++--- 24 files changed, 91 insertions(+), 79 deletions(-) diff --git a/aktoro-channel/src/channel.rs b/aktoro-channel/src/channel.rs index 3e104eb..a234c03 100644 --- a/aktoro-channel/src/channel.rs +++ b/aktoro-channel/src/channel.rs @@ -1,7 +1,7 @@ use std::sync::atomic::AtomicBool; use std::sync::atomic::Ordering; use std::sync::Arc; -use std::task::Waker; +use std::task; use crossbeam_queue::SegQueue; use crossbeam_utils::atomic::AtomicCell; @@ -11,6 +11,8 @@ use crate::error::*; use crate::message::Message; use crate::queue::Queue; +type Waker = Arc)>>; + /// A channel allowing senders to pass /// messages over it, and receivers to /// retrieve them. @@ -22,7 +24,7 @@ pub(crate) struct Channel { // TODO pub(crate) counters: Counters, // TODO - pub(crate) wakers: SegQueue)>>>, + pub(crate) wakers: SegQueue, } impl Channel { @@ -78,7 +80,7 @@ impl Channel { } // TODO - pub(crate) fn register(&self, waker: Arc)>>) { + pub(crate) fn register(&self, waker: Waker) { self.wakers.push(waker); } diff --git a/aktoro-channel/src/error.rs b/aktoro-channel/src/error.rs index 7799570..b2d64e6 100644 --- a/aktoro-channel/src/error.rs +++ b/aktoro-channel/src/error.rs @@ -1,4 +1,4 @@ -use std::error::Error as StdError; +use std::error; use std::fmt; use std::fmt::Debug; use std::fmt::Display; @@ -207,11 +207,11 @@ impl TryRecvError { } } -impl StdError for CloneError {} +impl error::Error for CloneError {} -impl StdError for TrySendError {} +impl error::Error for TrySendError {} -impl StdError for TryRecvError {} +impl error::Error for TryRecvError {} impl Display for CloneError { fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { diff --git a/aktoro-context/src/channel.rs b/aktoro-context/src/channel.rs index f1faf0a..bd6aa2b 100644 --- a/aktoro-context/src/channel.rs +++ b/aktoro-context/src/channel.rs @@ -1,5 +1,5 @@ use std::pin::Pin; -use std::task::Context as FutContext; +use std::task; use std::task::Poll; use aktoro_channel as channel; @@ -67,7 +67,7 @@ where { type Item = Box>; - fn poll_next(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll> { + fn poll_next(self: Pin<&mut Self>, ctx: &mut task::Context) -> Poll> { Pin::new(&mut self.get_mut().0).poll_next(ctx) } } diff --git a/aktoro-context/src/context.rs b/aktoro-context/src/context.rs index 98532d6..9bb5d16 100644 --- a/aktoro-context/src/context.rs +++ b/aktoro-context/src/context.rs @@ -1,7 +1,7 @@ use std::collections::VecDeque; use std::future::Future; use std::pin::Pin; -use std::task::Context as FutContext; +use std::task; use std::task::Poll; use aktoro_channel::error::TrySendError; @@ -327,7 +327,7 @@ where { type Item = raw::Work; - fn poll_next(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll>> { + fn poll_next(self: Pin<&mut Self>, ctx: &mut task::Context) -> Poll>> { let context = self.get_mut(); let mut ret = None; diff --git a/aktoro-context/src/control.rs b/aktoro-context/src/control.rs index 205211d..d9f5a25 100644 --- a/aktoro-context/src/control.rs +++ b/aktoro-context/src/control.rs @@ -1,5 +1,5 @@ use std::pin::Pin; -use std::task::Context as FutContext; +use std::task; use std::task::Poll; use aktoro_channel as channel; @@ -69,7 +69,7 @@ where fn poll_next( self: Pin<&mut Self>, - ctx: &mut FutContext, + ctx: &mut task::Context, ) -> Poll>>> { Pin::new(&mut self.get_mut().0).poll_next(ctx) } diff --git a/aktoro-context/src/message.rs b/aktoro-context/src/message.rs index 9f8f674..bbc365a 100644 --- a/aktoro-context/src/message.rs +++ b/aktoro-context/src/message.rs @@ -1,7 +1,7 @@ use std::future::Future; use std::marker::PhantomData; use std::pin::Pin; -use std::task::Context as FutContext; +use std::task; use std::task::Poll; use aktoro_raw as raw; @@ -243,7 +243,10 @@ where { type Actor = A; - fn poll(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll> { + fn poll( + self: Pin<&mut Self>, + ctx: &mut task::Context, + ) -> Poll> { let fut = self.get_mut(); let mut inner = if let Some(inner) = fut.inner.get() { inner @@ -278,7 +281,7 @@ where fn poll_next( self: Pin<&mut Self>, - ctx: &mut FutContext, + ctx: &mut task::Context, ) -> Poll> { let stream = self.get_mut(); let mut inner = if let Some(inner) = stream.inner.get() { @@ -319,7 +322,7 @@ where fn poll_read( self: Pin<&mut Self>, - ctx: &mut FutContext, + ctx: &mut task::Context, ) -> Poll> { let stream = self.get_mut(); let mut inner = if let Some(inner) = stream.inner.get() { @@ -363,7 +366,10 @@ where { type Actor = A; - fn poll(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll> { + fn poll( + self: Pin<&mut Self>, + ctx: &mut task::Context, + ) -> Poll> { let fut = self.get_mut(); let mut inner = if let Some(inner) = fut.inner.get() { inner diff --git a/aktoro-context/src/respond.rs b/aktoro-context/src/respond.rs index bc32e1e..cdf956c 100644 --- a/aktoro-context/src/respond.rs +++ b/aktoro-context/src/respond.rs @@ -1,7 +1,7 @@ use std::future::Future; use std::pin::Pin; use std::sync::Arc; -use std::task::Context as FutContext; +use std::task; use std::task::Poll; use std::task::Waker; @@ -53,7 +53,7 @@ impl Respond { impl Future for Respond { type Output = O; - fn poll(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll { + fn poll(self: Pin<&mut Self>, ctx: &mut task::Context) -> Poll { // If the output is available, we // complete the future with it. if let Some(out) = self.0.out.swap(None) { diff --git a/aktoro-context/src/update.rs b/aktoro-context/src/update.rs index a7020d5..5570b06 100644 --- a/aktoro-context/src/update.rs +++ b/aktoro-context/src/update.rs @@ -1,5 +1,5 @@ use std::pin::Pin; -use std::task::Context as FutContext; +use std::task; use std::task::Poll; use aktoro_channel as channel; @@ -149,7 +149,7 @@ where { type Item = Update; - fn poll_next(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll>> { + fn poll_next(self: Pin<&mut Self>, ctx: &mut task::Context) -> Poll>> { Pin::new(&mut self.get_mut().0).poll_next(ctx) } } diff --git a/aktoro-raw/src/actor.rs b/aktoro-raw/src/actor.rs index 67e4e9a..a2d7004 100644 --- a/aktoro-raw/src/actor.rs +++ b/aktoro-raw/src/actor.rs @@ -1,4 +1,4 @@ -use std::error::Error as StdError; +use std::error; use crate::context::Context; @@ -7,7 +7,7 @@ pub trait Actor: Unpin + Send + Sized { type Status: Status + Unpin; - type Error: StdError + Send + 'static; + type Error: error::Error + Send + 'static; #[allow(unused)] /// Called when the actor's context has been created diff --git a/aktoro-raw/src/channel.rs b/aktoro-raw/src/channel.rs index f8feab3..f2f6f62 100644 --- a/aktoro-raw/src/channel.rs +++ b/aktoro-raw/src/channel.rs @@ -1,4 +1,4 @@ -use std::error::Error as StdError; +use std::error; use futures_core::future::BoxFuture; use futures_core::Stream; @@ -19,7 +19,7 @@ pub type SenderRes<'s, O, E> = Result>, E>; pub trait Sender: Unpin + Clone + Send { type Receiver: Receiver; - type Error: StdError + Send + 'static; + type Error: error::Error + Send + 'static; /// Tries to send a message to be handled by the /// actor. diff --git a/aktoro-raw/src/context.rs b/aktoro-raw/src/context.rs index 8dd5f07..e86d8b6 100644 --- a/aktoro-raw/src/context.rs +++ b/aktoro-raw/src/context.rs @@ -3,7 +3,7 @@ use std::pin::Pin; use std::sync::atomic::AtomicBool; use std::sync::atomic::Ordering; use std::sync::Arc; -use std::task::Context as FutContext; +use std::task; use std::task::Poll; use std::task::Waker; @@ -269,7 +269,7 @@ impl CancellableInner { impl Future for Cancelling { type Output = Option>>; - fn poll(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll>>> { + fn poll(self: Pin<&mut Self>, ctx: &mut task::Context) -> Poll>>> { if self.done.load(Ordering::SeqCst) { return Poll::Ready(None); } diff --git a/aktoro-raw/src/control.rs b/aktoro-raw/src/control.rs index 39e0338..c2c05fd 100644 --- a/aktoro-raw/src/control.rs +++ b/aktoro-raw/src/control.rs @@ -1,4 +1,4 @@ -use std::error::Error as StdError; +use std::error; use futures_core::future::BoxFuture; use futures_core::Stream; @@ -19,7 +19,7 @@ pub type ControllerRes<'c, O, E> = Result>, E>; pub trait Controller: Unpin + Clone + Send { type Controlled: Controlled; - type Error: StdError + Send + 'static; + type Error: error::Error + Send + 'static; /// Tries to send an action to be handled by the /// actor. diff --git a/aktoro-raw/src/lib.rs b/aktoro-raw/src/lib.rs index c8ec5d9..ee6b6f4 100644 --- a/aktoro-raw/src/lib.rs +++ b/aktoro-raw/src/lib.rs @@ -25,5 +25,3 @@ pub use crate::spawned::*; pub use crate::tcp::*; pub use crate::udp::*; pub use crate::update::*; - -pub use futures_core::future::BoxFuture; diff --git a/aktoro-raw/src/message.rs b/aktoro-raw/src/message.rs index 682094f..99fc834 100644 --- a/aktoro-raw/src/message.rs +++ b/aktoro-raw/src/message.rs @@ -1,5 +1,5 @@ use std::pin::Pin; -use std::task::Context as FutContext; +use std::task; use std::task::Poll; use crate::actor::Actor; @@ -19,19 +19,25 @@ pub trait Message: Send { pub trait AsyncMessageFut: Send { type Actor: Actor; - fn poll(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll>; + fn poll(self: Pin<&mut Self>, ctx: &mut task::Context) -> Poll>; } pub trait AsyncMessageStream: Send { type Actor: Actor; - fn poll_next(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll>; + fn poll_next( + self: Pin<&mut Self>, + ctx: &mut task::Context, + ) -> Poll>; } pub trait AsyncReadStream: Send { type Actor: Actor; - fn poll_read(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll>; + fn poll_read( + self: Pin<&mut Self>, + ctx: &mut task::Context, + ) -> Poll>; } pub trait Handler: Actor { diff --git a/aktoro-raw/src/runtime.rs b/aktoro-raw/src/runtime.rs index 074dfa8..47d663d 100644 --- a/aktoro-raw/src/runtime.rs +++ b/aktoro-raw/src/runtime.rs @@ -1,4 +1,4 @@ -use std::error::Error as StdError; +use std::error; use futures_core::Stream; @@ -25,7 +25,7 @@ pub trait Runtime: Default + Unpin + Send { // TODO type Wait: Wait; - type Error: StdError + Send + 'static; + type Error: error::Error + Send + 'static; // TODO fn actors(&self) -> Vec; diff --git a/aktoro-raw/src/spawned.rs b/aktoro-raw/src/spawned.rs index 3bf8a96..9576ca4 100644 --- a/aktoro-raw/src/spawned.rs +++ b/aktoro-raw/src/spawned.rs @@ -1,5 +1,5 @@ use std::pin::Pin; -use std::task::Context as FutContext; +use std::task; use std::task::Poll; use futures_core::Stream; @@ -103,7 +103,7 @@ impl Unpin for Spawned {} impl Stream for Spawned { type Item = Update; - fn poll_next(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll>> { + fn poll_next(self: Pin<&mut Self>, ctx: &mut task::Context) -> Poll>> { if let Some(updted) = &mut self.get_mut().updted { Pin::new(updted).poll_next(ctx) } else { diff --git a/aktoro-raw/src/tcp.rs b/aktoro-raw/src/tcp.rs index 69f173d..7e1cbe2 100644 --- a/aktoro-raw/src/tcp.rs +++ b/aktoro-raw/src/tcp.rs @@ -1,4 +1,4 @@ -use std::error::Error as StdError; +use std::error; use std::future::Future; use std::net::SocketAddr; use std::net::ToSocketAddrs; @@ -20,7 +20,7 @@ pub type OwnedTcpServerIncoming = Box< pub trait TcpClient: TcpStream + Unpin + Send + Sized { type Connect: Future::Error>> + Unpin + Send; - type Error: StdError + Send + 'static; + type Error: error::Error + Send + 'static; /// Tries to connect to a TCP server at the /// given address. @@ -30,7 +30,7 @@ pub trait TcpClient: TcpStream + Unpin + Send + Sized { pub trait TcpServer: Unpin + Send + Sized { type Stream: TcpStream; - type Error: StdError + Send + 'static; + type Error: error::Error + Send + 'static; /// Tries to create a new TCP server that /// will be bound to the given address. @@ -48,7 +48,7 @@ pub trait TcpServer: Unpin + Send + Sized { } pub trait TcpStream: AsyncRead + AsyncWrite + Unpin + Send { - type Error: StdError + Send + 'static; + type Error: error::Error + Send + 'static; /// Returns the address that the server /// is bound to. diff --git a/aktoro-raw/src/udp.rs b/aktoro-raw/src/udp.rs index e39c362..8063d0c 100644 --- a/aktoro-raw/src/udp.rs +++ b/aktoro-raw/src/udp.rs @@ -1,4 +1,4 @@ -use std::error::Error as StdError; +use std::error; use std::net::SocketAddr; use std::net::ToSocketAddrs; @@ -9,7 +9,7 @@ pub type UdpSocketSendTo<'s, E> = Box> + 's pub type UdpSocketRecv<'s, E> = Box> + 's>; pub trait UdpSocket: Unpin + Send + Sized { - type Error: StdError + Send + 'static; + type Error: error::Error + Send + 'static; /// Tries to create a new UDP socket that /// will be bound to the given address. diff --git a/aktoro-raw/src/update.rs b/aktoro-raw/src/update.rs index bba7589..bd7eb9f 100644 --- a/aktoro-raw/src/update.rs +++ b/aktoro-raw/src/update.rs @@ -1,4 +1,4 @@ -use std::error::Error as StdError; +use std::error; use futures_core::Stream; @@ -16,7 +16,7 @@ pub trait Updater: Unpin + Send { type Updated: Updated; - type Error: StdError + Send + 'static; + type Error: error::Error + Send + 'static; // TODO fn try_send(&mut self, update: Self::Update) -> Result<(), Self::Error>; diff --git a/aktoro-runtime/src/actor.rs b/aktoro-runtime/src/actor.rs index 0d308d6..ae72043 100644 --- a/aktoro-runtime/src/actor.rs +++ b/aktoro-runtime/src/actor.rs @@ -1,6 +1,6 @@ use std::future::Future; use std::pin::Pin; -use std::task::Context as FutContext; +use std::task; use std::task::Poll; use aktoro_channel as channel; @@ -225,7 +225,7 @@ where { type Output = Result<(), Error>; - fn poll(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll { + fn poll(self: Pin<&mut Self>, ctx: &mut task::Context) -> Poll { let actor = self.get_mut(); loop { @@ -330,7 +330,7 @@ where impl Future for KillRecver { type Output = (); - fn poll(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll<()> { + fn poll(self: Pin<&mut Self>, ctx: &mut task::Context) -> Poll<()> { let recver = self.get_mut(); if let Some(notify) = &mut recver.0 { @@ -348,7 +348,7 @@ impl Future for KillRecver { impl Stream for KilledRecver { type Item = u64; - fn poll_next(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll> { + fn poll_next(self: Pin<&mut Self>, ctx: &mut task::Context) -> Poll> { Pin::new(&mut self.get_mut().0).poll_next(ctx) } } diff --git a/aktoro-runtime/src/error.rs b/aktoro-runtime/src/error.rs index 60a4e67..bed48ec 100644 --- a/aktoro-runtime/src/error.rs +++ b/aktoro-runtime/src/error.rs @@ -1,4 +1,4 @@ -use std::error::Error as StdError; +use std::error; use std::fmt; use std::fmt::Display; use std::fmt::Formatter; @@ -14,7 +14,7 @@ pub enum ErrorKind { /// that implements the [`Error`] trait. /// /// [`Error`]: https://doc.rust-lang.org/std/error/trait.Error.html - Std(Box), + Std(Box), /// Multiple errors occured. Multiple(Vec), } @@ -23,7 +23,7 @@ impl Error { /// Creates a new boxed error. pub(crate) fn std(err: S) -> Self where - S: StdError + Send + 'static, + S: error::Error + Send + 'static, { Error { kind: ErrorKind::Std(Box::new(err)), @@ -99,7 +99,7 @@ impl Error { } } -impl StdError for Error {} +impl error::Error for Error {} impl Display for Error { fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { @@ -118,7 +118,7 @@ impl From for Error { impl From> for Error where - S: StdError + Send + 'static, + S: error::Error + Send + 'static, { fn from(err: Box) -> Error { Error { diff --git a/aktoro-runtime/src/runtime.rs b/aktoro-runtime/src/runtime.rs index 03d9efc..d75db9d 100644 --- a/aktoro-runtime/src/runtime.rs +++ b/aktoro-runtime/src/runtime.rs @@ -1,6 +1,6 @@ use std::future::Future; use std::pin::Pin; -use std::task::Context as FutContext; +use std::task; use std::task::Poll; use aktoro_raw as raw; @@ -133,7 +133,7 @@ impl Stream for Wait { fn poll_next( self: Pin<&mut Self>, - ctx: &mut FutContext, + ctx: &mut task::Context, ) -> Poll>> { let rt = &mut self.get_mut().0; diff --git a/aktoro-runtime/src/tcp.rs b/aktoro-runtime/src/tcp.rs index c5dda89..f69e8ea 100644 --- a/aktoro-runtime/src/tcp.rs +++ b/aktoro-runtime/src/tcp.rs @@ -2,14 +2,14 @@ use std::future::Future; use std::net::SocketAddr; use std::net::ToSocketAddrs; use std::pin::Pin; -use std::task::Context as FutContext; +use std::task; use std::task::Poll; use aktoro_raw as raw; use futures_core::Stream; +use futures_io as io; use futures_io::AsyncRead; use futures_io::AsyncWrite; -use futures_io::Error as FutError; use runtime::net; use crate::error::Error; @@ -149,7 +149,7 @@ impl raw::TcpStream for TcpStream { impl Future for Connect { type Output = Result; - fn poll(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll { + fn poll(self: Pin<&mut Self>, ctx: &mut task::Context) -> Poll { match Pin::new(&mut self.get_mut().connect).poll(ctx) { Poll::Ready(Ok(stream)) => Poll::Ready(Ok(TcpClient { stream })), Poll::Ready(Err(err)) => Poll::Ready(Err(Box::new(err).into())), @@ -161,7 +161,7 @@ impl Future for Connect { impl<'i> Stream for TcpIncoming<'i> { type Item = Result; - fn poll_next(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll> { + fn poll_next(self: Pin<&mut Self>, ctx: &mut task::Context) -> Poll> { match Pin::new(&mut self.get_mut().incoming).poll_next(ctx) { Poll::Ready(Some(res)) => match res { Ok(stream) => Poll::Ready(Some(Ok(TcpStream { stream }))), @@ -176,7 +176,7 @@ impl<'i> Stream for TcpIncoming<'i> { impl Stream for OwnedTcpIcoming { type Item = Result; - fn poll_next(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll> { + fn poll_next(self: Pin<&mut Self>, ctx: &mut task::Context) -> Poll> { match Pin::new(&mut self.get_mut().server.listener.accept()).poll(ctx) { Poll::Ready(Ok((stream, _))) => Poll::Ready(Some(Ok(TcpStream { stream }))), Poll::Ready(Err(err)) => Poll::Ready(Some(Err(Box::new(err).into()))), @@ -188,9 +188,9 @@ impl Stream for OwnedTcpIcoming { impl AsyncRead for TcpClient { fn poll_read( self: Pin<&mut Self>, - ctx: &mut FutContext, + ctx: &mut task::Context, buf: &mut [u8], - ) -> Poll> { + ) -> Poll> { match Pin::new(&mut self.get_mut().stream).poll_read(ctx, buf) { Poll::Ready(Ok(read)) if read == 0 => Poll::Pending, polled => polled, @@ -201,17 +201,17 @@ impl AsyncRead for TcpClient { impl AsyncWrite for TcpClient { fn poll_write( self: Pin<&mut Self>, - ctx: &mut FutContext, + ctx: &mut task::Context, buf: &[u8], - ) -> Poll> { + ) -> Poll> { Pin::new(&mut self.get_mut().stream).poll_write(ctx, buf) } - fn poll_flush(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll> { + fn poll_flush(self: Pin<&mut Self>, ctx: &mut task::Context) -> Poll> { Pin::new(&mut self.get_mut().stream).poll_flush(ctx) } - fn poll_close(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll> { + fn poll_close(self: Pin<&mut Self>, ctx: &mut task::Context) -> Poll> { Pin::new(&mut self.get_mut().stream).poll_close(ctx) } } @@ -219,9 +219,9 @@ impl AsyncWrite for TcpClient { impl AsyncRead for TcpStream { fn poll_read( self: Pin<&mut Self>, - ctx: &mut FutContext, + ctx: &mut task::Context, buf: &mut [u8], - ) -> Poll> { + ) -> Poll> { match Pin::new(&mut self.get_mut().stream).poll_read(ctx, buf) { Poll::Ready(Ok(read)) if read == 0 => Poll::Pending, polled => polled, @@ -232,17 +232,17 @@ impl AsyncRead for TcpStream { impl AsyncWrite for TcpStream { fn poll_write( self: Pin<&mut Self>, - ctx: &mut FutContext, + ctx: &mut task::Context, buf: &[u8], - ) -> Poll> { + ) -> Poll> { Pin::new(&mut self.get_mut().stream).poll_write(ctx, buf) } - fn poll_flush(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll> { + fn poll_flush(self: Pin<&mut Self>, ctx: &mut task::Context) -> Poll> { Pin::new(&mut self.get_mut().stream).poll_flush(ctx) } - fn poll_close(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll> { + fn poll_close(self: Pin<&mut Self>, ctx: &mut task::Context) -> Poll> { Pin::new(&mut self.get_mut().stream).poll_close(ctx) } } diff --git a/aktoro-runtime/src/udp.rs b/aktoro-runtime/src/udp.rs index d3ebd9e..f3f74ee 100644 --- a/aktoro-runtime/src/udp.rs +++ b/aktoro-runtime/src/udp.rs @@ -2,7 +2,7 @@ use std::future::Future; use std::net::SocketAddr; use std::net::ToSocketAddrs; use std::pin::Pin; -use std::task::Context as FutContext; +use std::task; use std::task::Poll; use aktoro_raw as raw; @@ -80,7 +80,7 @@ impl raw::UdpSocket for UdpSocket { impl<'s, 'b> Future for SendTo<'s, 'b> { type Output = Result; - fn poll(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll { + fn poll(self: Pin<&mut Self>, ctx: &mut task::Context) -> Poll { match Pin::new(&mut self.get_mut().send_to).poll(ctx) { Poll::Ready(Ok(sent)) => Poll::Ready(Ok(sent)), Poll::Ready(Err(err)) => Poll::Ready(Err(Box::new(err).into())), @@ -92,7 +92,7 @@ impl<'s, 'b> Future for SendTo<'s, 'b> { impl<'s, 'b> Future for Recv<'s, 'b> { type Output = Result<(usize, SocketAddr), Error>; - fn poll(self: Pin<&mut Self>, ctx: &mut FutContext) -> Poll { + fn poll(self: Pin<&mut Self>, ctx: &mut task::Context) -> Poll { match Pin::new(&mut self.get_mut().recv_from).poll(ctx) { Poll::Ready(Ok(recved)) => Poll::Ready(Ok(recved)), Poll::Ready(Err(err)) => Poll::Ready(Err(Box::new(err).into())), From b969f36510578b09b3a9b51e90a1cf43f128e389 Mon Sep 17 00:00:00 2001 From: Matthieu Le Brazidec Date: Fri, 12 Jul 2019 23:16:02 +0200 Subject: [PATCH 21/22] Updated the documentation. --- aktoro-channel/src/channel.rs | 16 ++- aktoro-channel/src/queue.rs | 4 + aktoro-channel/src/receiver.rs | 7 +- aktoro-context/src/context.rs | 88 ++++++++++++++--- aktoro-context/src/update.rs | 5 +- aktoro-raw/src/context.rs | 176 ++++++++++++++++++++++++++------- aktoro-raw/src/runtime.rs | 31 +++++- aktoro-raw/src/spawned.rs | 9 +- aktoro-raw/src/tcp.rs | 3 +- aktoro-raw/src/update.rs | 4 +- aktoro-runtime/src/runtime.rs | 30 ++++-- aktoro-runtime/src/tcp.rs | 12 ++- 12 files changed, 310 insertions(+), 75 deletions(-) diff --git a/aktoro-channel/src/channel.rs b/aktoro-channel/src/channel.rs index a234c03..b0c0f64 100644 --- a/aktoro-channel/src/channel.rs +++ b/aktoro-channel/src/channel.rs @@ -17,13 +17,19 @@ type Waker = Arc)>>; /// messages over it, and receivers to /// retrieve them. pub(crate) struct Channel { - // TODO + /// The queue that is holding the + /// messages that have not been + /// received yet. pub(crate) queue: Queue>, - // TODO + /// Whether the channel is closed. pub(crate) closed: AtomicBool, - // TODO + /// The counters used to store the + /// current number of senders, + /// receivers, messages and the + /// channel's limits. pub(crate) counters: Counters, - // TODO + /// A list of the wakers that can + /// be used to wake up receivers. pub(crate) wakers: SegQueue, } @@ -79,7 +85,7 @@ impl Channel { } } - // TODO + /// Registers a new waker. pub(crate) fn register(&self, waker: Waker) { self.wakers.push(waker); } diff --git a/aktoro-channel/src/queue.rs b/aktoro-channel/src/queue.rs index 605cb83..7c77dab 100644 --- a/aktoro-channel/src/queue.rs +++ b/aktoro-channel/src/queue.rs @@ -1,8 +1,12 @@ use crossbeam_queue::ArrayQueue; use crossbeam_queue::SegQueue; +/// The queue used by the channels to send +/// and receive data. pub(crate) enum Queue { + /// The bounded queue variant. Bounded(ArrayQueue), + /// The unbounded queue variant. Unbounded(SegQueue), } diff --git a/aktoro-channel/src/receiver.rs b/aktoro-channel/src/receiver.rs index bae11bd..40bb3d7 100644 --- a/aktoro-channel/src/receiver.rs +++ b/aktoro-channel/src/receiver.rs @@ -18,8 +18,13 @@ use crate::error::*; /// /// [`try_recv`]: #method.try_recv pub struct Receiver { - waker: Arc)>>, + /// The channel the receiver will + /// receive data from. channel: Option>>, + /// A reference to the space the + /// receiver was assigned to store + /// its waker. + waker: Arc)>>, } impl Receiver { diff --git a/aktoro-context/src/context.rs b/aktoro-context/src/context.rs index 9bb5d16..5fb882a 100644 --- a/aktoro-context/src/context.rs +++ b/aktoro-context/src/context.rs @@ -30,8 +30,16 @@ use crate::update::Update; use crate::update::Updated; use crate::update::Updater; -// TODO +/// The configuration that is used by [`Context`]. +/// +/// ## Note +/// +/// This is only used when spawning sub-actors and +/// shoudln't be used elsewhere. pub struct ContextConfig { + /// Whether the context should wait to get + /// notified before starting to handle + /// messages, events, etc. ready: Option, } @@ -39,9 +47,12 @@ pub struct ContextConfig { /// /// [`aktoro-channel`]: https://docs.rs/aktoro-channel pub struct Context { - // TODO + /// The identifier of the actor, as used by + /// the runtime. actor_id: u64, - // TODO + /// Whether the context should wait to get + /// notified before starting to handle + /// messages, events, etc. ready: Option, /// The actor's current status. status: A::Status, @@ -52,17 +63,26 @@ pub struct Context { /// Whether the status has been recently updated /// and the runtime should be notified. update: bool, - // TODO + /// A list of futures that should be fully + /// executed before handling messages, events, + /// non-blocking futures, etc. b_futs: Vec>>>, - // TODO + /// A list of futures that the context should + /// give the output to the actor as a message. futs: Vec>>>, - // TODO + /// A list of streams that the context should + /// give the yielded items to the actor as + /// messages. streams: Vec>>>, - // TODO + /// A list of asynchronous readers that the + /// context should forward the data to the + /// actor as messages. reads: Vec>>>, - // TODO + /// An eventual inner runtime that the context + /// can use to run/spawn sub-actors. rt: Option, - // TODO + /// A list of contexts that should be notified + /// when all blocking futures have been handled. to_notify: Vec, /// A list of the actor's unhandled events. events: VecDeque>>, @@ -331,6 +351,8 @@ where let context = self.get_mut(); let mut ret = None; + // If the context hasn't been marked as being + // ready yet, we try to see if it should be now. if let Some(ready) = context.ready.as_mut() { match Pin::new(ready).poll(ctx) { Poll::Ready(()) => { @@ -358,7 +380,9 @@ where return Poll::Ready(Some(raw::Work::Update)); } - // TODO + // We try to poll all blocking futures until they + // all finished executing, making the actor handle + // the returned messages as they are yielded. let mut to_remove = vec![]; for (i, fut) in context.b_futs.iter_mut().enumerate() { match fut.as_mut().poll(ctx) { @@ -373,17 +397,24 @@ where } } + // We remove the fully executed futures. for to_remove in to_remove { context.b_futs.remove(to_remove); } + // We eventually return the output of the first + // fully executed future... if let Some(ret) = ret { return Poll::Ready(Some(ret)); + // ...or we wait if all blocking futures havn't + // fully executed. } else if !context.b_futs.is_empty() { return Poll::Pending; } - // TODO + // If there are no more blocking futures, we + // notify the context of all the recently + // spawned actors that they are ready. for to_notify in context.to_notify.drain(..) { to_notify.done(); } @@ -406,15 +437,19 @@ where Poll::Pending => (), } - // TODO + // We poll the inner runtime if there is one. if let Some(rt) = context.rt.take() { let mut wait = rt.wait(); + // We poll until there is either... loop { + // ...no running actors or... if wait.runtime().actors().is_empty() { break; } + // ...the runtime is waiting for them + // to yield. if let Poll::Pending = Pin::new(&mut wait).poll_next(ctx) { break; } @@ -423,7 +458,8 @@ where context.rt = Some(wait.into_runtime()); } - // TODO + // We poll all the futures that the context + // was asked to handle. let mut to_remove = vec![]; for (i, fut) in context.futs.iter_mut().enumerate() { match fut.as_mut().poll(ctx) { @@ -438,15 +474,19 @@ where } } + // We remove the fully executed futures... for to_remove in to_remove { context.futs.remove(to_remove); } + // ...and return the output of the futures + // that returned one. if let Some(ret) = ret { return Poll::Ready(Some(ret)); } - // TODO + // We poll all the streams that the context + // was asked to handle. let mut to_remove = vec![]; for (i, stream) in context.streams.iter_mut().enumerate() { match stream.as_mut().poll_next(ctx) { @@ -456,15 +496,18 @@ where } } + // We remove all the closed streams... for to_remove in to_remove { context.streams.remove(to_remove); } + // ...and return the yielded items. if let Some(ret) = ret { return Poll::Ready(Some(ret)); } - // TODO + // We poll all the asynchronous readers that + // the context was asked to handle. let mut to_remove = vec![]; for (i, read) in context.reads.iter_mut().enumerate() { match read.as_mut().poll_read(ctx) { @@ -474,10 +517,13 @@ where } } + // We remove all the closed readers... for to_remove in to_remove { context.reads.remove(to_remove); } + // ...and transfer the data read to the + // actor. if let Some(ret) = ret { return Poll::Ready(Some(ret)); } @@ -491,3 +537,15 @@ impl Default for ContextConfig { ContextConfig { ready: None } } } + +impl Drop for Context +where + A: raw::Actor, + R: raw::Runtime, +{ + fn drop(&mut self) { + if let Some(rt) = &mut self.rt { + rt.stop(); + } + } +} diff --git a/aktoro-context/src/update.rs b/aktoro-context/src/update.rs index 5570b06..d6f2491 100644 --- a/aktoro-context/src/update.rs +++ b/aktoro-context/src/update.rs @@ -7,12 +7,15 @@ use aktoro_channel::error::TrySendError; use aktoro_raw as raw; use futures_core::Stream; -// TODO +/// A wrapper around an actor's status, +/// containing its identifier. pub struct Update where A: raw::Actor, { + /// The actor's identifier. actor_id: u64, + /// The actor's new status. status: A::Status, } diff --git a/aktoro-raw/src/context.rs b/aktoro-raw/src/context.rs index e86d8b6..502cfb1 100644 --- a/aktoro-raw/src/context.rs +++ b/aktoro-raw/src/context.rs @@ -24,29 +24,51 @@ use crate::message::Message; use crate::spawned::Spawned; use crate::update::Updater; -// TODO -pub struct Cancellable { - // TODO - inner: CancellableInner, -} - -// TODO +/// A wrapper around a future/stream/reader +/// that is returned by a context after asking +/// it to wait/subscribe/read, to allow to +/// cancel the action. +pub struct Cancellable(CancellableInner); + +/// The structure that is actually holding +/// what [`Cancellable`] needs. It is also +/// what contexts will have to store and +/// update. +/// +/// [`Cancellable`]: struct.Cancellable.html pub struct CancellableInner { - // TODO + /// The future/stream/reader that + /// is holded. inner: Arc>>>>, - // TODO + /// Whether the action(s) are done or + /// what is holded can be released. done: Arc, - // TODO + /// A reference to the space that + /// was assigned to store the + /// [`Cancelling`]'s waker, to wake it + /// up when needed. + /// + /// [`Cancelling`]: struct.Cancelling.html waker: Arc>>, } -// TODO +/// A future returned by [`Cancellable::cancel`] +/// that resolves when what is handled has +/// been cancelled (in which case it returns +/// it) or the action(s) are done. pub struct Cancelling { - // TODO + /// The future/stream/reader that is + /// holded. inner: Arc>>>>, - // TODO + /// Whether the action(s) are done or + /// what is holded can be released. done: Arc, - // TODO + /// A reference to the space that + /// was assigned to store the + /// [`Cancelling`]'s waker, to wake it + /// up when needed. + /// + /// [`Cancelling`]: struct.Cancelling.html waker: Arc>>, } @@ -57,10 +79,11 @@ pub trait Context: Stream> + Unpin + Send + Sized { type Sender: Sender; type Updater: Updater; - // TODO + /// Creates a new context with the provided + /// config and an identifier for the actor. fn new(actor_id: u64, config: Self::Config) -> Self; - // TODO + /// Returns the actor's identifier. fn actor_id(&self) -> u64; /// Emits an event that will be handled by the @@ -108,16 +131,31 @@ pub trait Context: Stream> + Unpin + Send + Sized { /// update channel receiver. fn updater(&mut self) -> &mut Self::Updater; - // TODO + /// Returns a list of the context's inner + /// runtime's actors' identifier. fn actors(&self) -> Vec; - // TODO + /// Spawns a sub-actor on the context's inner + /// runtime. + /// + /// ## Note + /// + /// The new actor must have a context with the + /// same configuration structure as this context. fn spawn(&mut self, actor: S) -> Option> where S: Actor + 'static, C: Context; - // TODO + /// Waits for a future to yield before mapping it + /// to a message and passing it to the actor. + /// + /// The execution can be cancelled using the + /// returned [`Cancellable`]. Cancelling the + /// execution, if it isn't done, will return + /// the original `fut`. + /// + /// [`Cancellable`]: struct.Cancellable.html fn wait(&mut self, fut: Pin>, map: M) -> Cancellable where F: Future + Unpin + Send + 'static, @@ -126,7 +164,19 @@ pub trait Context: Stream> + Unpin + Send + Sized { O: Send + 'static, T: Send + 'static; - // TODO + /// Waits for a future to yield before mapping it + /// to a message and passing it to the actor. + /// + /// Until all the blocking futures/asynchronous writes + /// have yielded, no messages, events, streams, etc. + /// will be handled by the context. + /// + /// The execution can be cancelled using the + /// returned [`Cancellable`]. Cancelling the + /// execution, if it isn't done, will return + /// the original `fut`. + /// + /// [`Cancellable`]: struct.Cancellable.html fn blocking_wait(&mut self, fut: Pin>, map: M) -> Cancellable where F: Future + Unpin + Send + 'static, @@ -135,7 +185,15 @@ pub trait Context: Stream> + Unpin + Send + Sized { O: Send + 'static, T: Send + 'static; - // TODO + /// Forwards the items yielded by a stream to + /// the actor after mapping them to a message. + /// + /// The execution can be cancelled using the + /// returned [`Cancellable`]. Cancelling the + /// execution, if it isn't done, will return + /// the original `fut`. + /// + /// [`Cancellable`]: struct.Cancellable.html fn subscribe(&mut self, stream: Pin>, map: M) -> Cancellable where S: Stream + Unpin + Send + 'static, @@ -144,7 +202,16 @@ pub trait Context: Stream> + Unpin + Send + Sized { I: Send + 'static, T: Send + 'static; - // TODO + /// Forwards the received data to the actor + /// after either mapping it or a returned + /// error to a message. + /// + /// The execution can be cancelled using the + /// returned [`Cancellable`]. Cancelling the + /// execution, if it isn't done, will return + /// the original `fut`. + /// + /// [`Cancellable`]: struct.Cancellable.html fn read( &mut self, read: Pin>, @@ -160,7 +227,17 @@ pub trait Context: Stream> + Unpin + Send + Sized { T: Send + 'static, E: Send + 'static; - // TODO + /// Waits for data to be written over an asynchronous + /// writer, then passing a message returned by either + /// `map` or `map_err` (depending on whether an error + /// was returned by the writer) to the actor. + /// + /// The execution can be cancelled using the + /// returned [`Cancellable`]. Cancelling the + /// execution, if it isn't done, will return + /// the original `fut`. + /// + /// [`Cancellable`]: struct.Cancellable.html fn write( &mut self, write: Pin>, @@ -176,7 +253,21 @@ pub trait Context: Stream> + Unpin + Send + Sized { T: Send + 'static, E: Send + 'static; - // TODO + /// Waits for data to be written over an asynchronous + /// writer, then passing a message returned by either + /// `map` or `map_err` (depending on whether an error + /// was returned by the writer) to the actor. + /// + /// Until all the blocking futures/asynchronous writes + /// have yielded, no messages, events, streams, etc. + /// will be handled by the context. + /// + /// The execution can be cancelled using the + /// returned [`Cancellable`]. Cancelling the + /// execution, if it isn't done, will return + /// the original `fut`. + /// + /// [`Cancellable`]: struct.Cancellable.html fn blocking_write( &mut self, write: Pin>, @@ -212,54 +303,69 @@ pub enum Work { } impl Cancellable { - // TODO pub fn new(inner: Pin>) -> (Self, CancellableInner) { let inner = Arc::new(AtomicCell::new(Some(inner))); let done = Arc::new(AtomicBool::new(false)); let waker = Arc::new(AtomicCell::new(None)); ( - Cancellable { - inner: CancellableInner { + Cancellable( + CancellableInner { inner: inner.clone(), done: done.clone(), waker: waker.clone(), }, - }, + ), CancellableInner { inner, done, waker }, ) } - // TODO + /// Creates a future that will yield when + /// the action(s) have either been cancelled, + /// in which case it will also give back what + /// was holded, or are done. pub fn cancel(self) -> Cancelling { Cancelling { - inner: self.inner.inner, - done: self.inner.done, - waker: self.inner.waker, + inner: self.0.inner, + done: self.0.done, + waker: self.0.waker, } } } impl CancellableInner { - // TODO + /// Gets what the wrapper holds. + /// + /// ## Note + /// + /// If the action(s) aren't done, you need + /// to call [`set`]. + /// + /// [`set`]: #method.set pub fn get(&self) -> Option>> { self.inner.swap(None) } - // TODO + /// Sets what the wrapper holds to `inner`. pub fn set(&self, inner: Pin>) { self.inner.store(Some(inner)); + // We eventually wake up the future + // that wants to get what's holded back. if let Some(waker) = self.waker.swap(None) { waker.wake(); } } - // TODO + /// Sets the action(s) as done. pub fn done(&self) { self.inner.store(None); self.done.store(true, Ordering::SeqCst); + // We eventually wake up the future + // that wanted to get what's holded back, + // so that it can know that it wont be + // able to. if let Some(waker) = self.waker.swap(None) { waker.wake(); } diff --git a/aktoro-raw/src/runtime.rs b/aktoro-raw/src/runtime.rs index 47d663d..281183c 100644 --- a/aktoro-raw/src/runtime.rs +++ b/aktoro-raw/src/runtime.rs @@ -8,8 +8,11 @@ use crate::net::NetworkManager; use crate::spawned::Spawned; pub trait Wait: Stream> + Unpin + Send { + /// Returns a reference to the runtime. fn runtime(&self) -> &R; + /// Returns the runtime, consuming the + /// stream. fn into_runtime(self) -> R; } @@ -22,12 +25,16 @@ pub trait Runtime: Default + Unpin + Send { /// runtime implementation). type NetworkManager: NetworkManager; - // TODO + /// The type that is allowing the runtime to + /// be polled after calling [`wait`]. + /// + /// [`wait`]: #method.wait type Wait: Wait; type Error: error::Error + Send + 'static; - // TODO + /// Returns a list of the runtime's actors' + /// identifier. fn actors(&self) -> Vec; /// Spawns a new actor on the runtime, @@ -42,7 +49,15 @@ pub trait Runtime: Default + Unpin + Send { where A: Actor + 'static; - // TODO + /// Spawns a new actor on the runtime, + /// passing its context the provided config + /// and returning [`Some(Spawned)`] if it + /// succeeded or [`None`] if it failed or + /// if the actor stopped itself when + /// [`Actor::starting`] was called. + /// + /// [`Some(Spawned)`]: sturct.Spawned.html + /// [`Actor::starting`]: trait.Actor.html#method.starting fn spawn_with(&mut self, actor: A, config: C::Config) -> Option> where A: Actor + 'static, @@ -54,9 +69,15 @@ pub trait Runtime: Default + Unpin + Send { /// an UDP socket. fn net(&mut self) -> Self::NetworkManager; - // TODO + /// Returns a stream allowing to poll the + /// runtime's actors. + /// + /// ## Note + /// + /// The stream can be transformed back into + /// a runtime. fn wait(self) -> Self::Wait; - // TODO + /// Asks all the runtime's actors to stop. fn stop(&mut self); } diff --git a/aktoro-raw/src/spawned.rs b/aktoro-raw/src/spawned.rs index 9576ca4..012af14 100644 --- a/aktoro-raw/src/spawned.rs +++ b/aktoro-raw/src/spawned.rs @@ -27,11 +27,14 @@ type Updated = <<::Context as Context>::Updater as Updater> /// message, control and update /// channels. pub struct Spawned { - // TODO + /// The actor's message channel's + /// sender. sender: Sender, - // TODO + /// The actor's control channel's + /// sender. ctrler: Controller, - // TODO + /// The actor's update channel's + /// receiver. updted: Option>, } diff --git a/aktoro-raw/src/tcp.rs b/aktoro-raw/src/tcp.rs index 7e1cbe2..6cae86a 100644 --- a/aktoro-raw/src/tcp.rs +++ b/aktoro-raw/src/tcp.rs @@ -43,7 +43,8 @@ pub trait TcpServer: Unpin + Send + Sized { /// Returns a stream of incoming connections. fn incoming(&mut self) -> Result, Self::Error>; - // TODO + /// Returns a stream of incoming connections, + /// consuming the server. fn into_incoming(self) -> Result, Self::Error>; } diff --git a/aktoro-raw/src/update.rs b/aktoro-raw/src/update.rs index bd7eb9f..758dd96 100644 --- a/aktoro-raw/src/update.rs +++ b/aktoro-raw/src/update.rs @@ -18,7 +18,9 @@ pub trait Updater: Unpin + Send { type Error: error::Error + Send + 'static; - // TODO + /// Tries to send an update to be handled by + /// whatever is holding the update channel's + /// receiver. fn try_send(&mut self, update: Self::Update) -> Result<(), Self::Error>; } diff --git a/aktoro-runtime/src/runtime.rs b/aktoro-runtime/src/runtime.rs index d75db9d..bdc7fa6 100644 --- a/aktoro-runtime/src/runtime.rs +++ b/aktoro-runtime/src/runtime.rs @@ -4,6 +4,7 @@ use std::task; use std::task::Poll; use aktoro_raw as raw; +use aktoro_raw::Runtime as RawRuntime; use fnv::FnvHashMap; use futures_core::Stream; use rand::FromEntropy; @@ -34,13 +35,19 @@ pub struct Runtime { /// A receiver the the actors' killed /// channel, notified when an actor /// has stopped/been killed. + /// + /// It is shared among all the runtime's + /// actors. recver: KilledRecver, /// A fast (non-cryptographic) random /// number generator. rng: Xoshiro512StarStar, } -// TODO +/// The stream returned by [`Runtime::wait`] +/// that allows to poll its actors. +/// +/// [`Runtime::wait`]: struct.Runtime.html#method.wait pub struct Wait(Runtime); impl Runtime { @@ -104,12 +111,10 @@ impl raw::Runtime for Runtime { NetworkManager } - // TODO fn wait(self) -> Wait { Wait(self) } - // TODO fn stop(&mut self) { // Ask to every actor to stop. for (_, actor) in self.actors.iter_mut() { @@ -141,15 +146,20 @@ impl Stream for Wait { return Poll::Ready(None); } - // TODO + // We poll all the runtime's actors until + // one yields. let mut remove = None; for (id, act) in rt.actors.iter_mut() { if let Poll::Ready(res) = Pin::new(&mut act.1).poll(ctx) { remove = Some((*id, res)); + + break; } } - // TODO + // If an actor yielded, we remove it from + // the actors list and yield what's been + // yielded. if let Some((id, res)) = remove { let removed = rt.actors.remove(&id); @@ -160,7 +170,9 @@ impl Stream for Wait { } } - // TODO + // We try to receive the identifier of the + // dead actors via the killed channel, to + // remove them and yield an update. match Pin::new(&mut rt.recver).poll_next(ctx) { Poll::Ready(Some(actor)) => { rt.actors.remove(&actor); @@ -187,3 +199,9 @@ impl Default for Runtime { } } } + +impl Drop for Runtime { + fn drop(&mut self) { + self.stop() + } +} diff --git a/aktoro-runtime/src/tcp.rs b/aktoro-runtime/src/tcp.rs index f69e8ea..9318ab8 100644 --- a/aktoro-runtime/src/tcp.rs +++ b/aktoro-runtime/src/tcp.rs @@ -50,9 +50,17 @@ pub struct TcpIncoming<'i> { incoming: net::tcp::IncomingStream<'i>, } -// TODO +/// A stream that yields new TCP +/// connections. +/// +/// ## Note +/// +/// It is similar to [`TcpIncoming`] +/// but because it actually holds the +/// tcp server it doesn't have lifetime +/// issues. pub struct OwnedTcpIcoming { - // TODO + /// The tcp server. server: TcpServer, } From 863b643df25116c89211de9602ab6c2432e6a920 Mon Sep 17 00:00:00 2001 From: Matthieu Le Brazidec Date: Fri, 12 Jul 2019 23:16:42 +0200 Subject: [PATCH 22/22] Formatting. --- aktoro-raw/src/context.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/aktoro-raw/src/context.rs b/aktoro-raw/src/context.rs index 502cfb1..2309937 100644 --- a/aktoro-raw/src/context.rs +++ b/aktoro-raw/src/context.rs @@ -309,13 +309,11 @@ impl Cancellable { let waker = Arc::new(AtomicCell::new(None)); ( - Cancellable( - CancellableInner { - inner: inner.clone(), - done: done.clone(), - waker: waker.clone(), - }, - ), + Cancellable(CancellableInner { + inner: inner.clone(), + done: done.clone(), + waker: waker.clone(), + }), CancellableInner { inner, done, waker }, ) }