├── .gitignore ├── src ├── net │ ├── mod.rs │ ├── uds.rs │ ├── tcp.rs │ └── stream.rs ├── sync │ ├── mod.rs │ ├── broadcast.rs │ ├── signal.rs │ └── queue.rs ├── reactor │ ├── consumers.rs │ ├── producers.rs │ ├── combinators.rs │ └── mod.rs ├── lib.rs ├── errors.rs ├── system.rs └── prevec.rs ├── .travis.yml ├── Cargo.toml ├── CONTRIBUTING.md ├── tests ├── test_signal_receiver.rs ├── test_or.rs ├── test_listener.rs └── test_broadcast.rs ├── LICENSE ├── examples ├── writer.rs ├── multithreaded.rs └── webserver.rs └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /benches 3 | **/*.rs.bk 4 | Cargo.lock 5 | perf.data* 6 | scripts/ 7 | -------------------------------------------------------------------------------- /src/net/mod.rs: -------------------------------------------------------------------------------- 1 | //! Network Reactors 2 | 3 | pub mod tcp; 4 | pub mod stream; 5 | 6 | #[cfg(unix)] 7 | pub mod uds; 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - stable 4 | - beta 5 | - nightly 6 | os: 7 | - linux 8 | - osx 9 | script: 10 | - cargo test -- --test-threads=1 11 | notifications: 12 | email: 13 | on_success: never 14 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sonr" 3 | version = "0.1.0" 4 | authors = ["Hagsteel "] 5 | edition = "2018" 6 | license = "MIT" 7 | 8 | [dependencies] 9 | mio = "0.6.16" 10 | crossbeam = "0.7.1" 11 | parking_lot = "0.7.1" 12 | 13 | [target.'cfg(unix)'.dependencies] 14 | mio-uds = "0.6.7" 15 | 16 | [features] 17 | -------------------------------------------------------------------------------- /src/sync/mod.rs: -------------------------------------------------------------------------------- 1 | //! Reactive queue, broadcaster and single mpsc 2 | pub mod queue; 3 | pub mod signal; 4 | pub mod broadcast; 5 | 6 | #[derive(Clone, Copy)] 7 | /// Queue / Signal capacity 8 | pub enum Capacity { 9 | /// Unlimited number of messages 10 | Unbounded, 11 | /// Limited number of messages 12 | Bounded(usize), 13 | } 14 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Sonr 2 | 3 | Contributions are welcome, be it writing a tutorial, raising a bug or submitting 4 | a pull request. 5 | 6 | ## Raising an issue / contributing to an issue 7 | 8 | * If you believe you have discovered a bug, please include a 9 | test case that demonstrates the bug. 10 | 11 | 12 | ## Submitting a bug report 13 | 14 | A bug report should include a test case that demonstrates the bug. 15 | 16 | 17 | ## Creating a pull request 18 | 19 | Before creating a pull request, create a new issue describing the change this 20 | pull request would make. 21 | -------------------------------------------------------------------------------- /tests/test_signal_receiver.rs: -------------------------------------------------------------------------------- 1 | use std::thread; 2 | use sonr::prelude::*; 3 | use sonr::sync::signal::{SignalReceiver, ReactiveSignalReceiver, SignalSender}; 4 | use sonr::sync::Capacity; 5 | 6 | 7 | #[test] 8 | fn test_signal_receiver() { 9 | let rx: SignalReceiver = SignalReceiver::unbounded(); 10 | let tx = rx.sender(); 11 | 12 | let handle = thread::spawn(move || { 13 | let handle = System::init().unwrap(); 14 | let rx = ReactiveSignalReceiver::new(rx).unwrap(); 15 | 16 | let run = rx.map(|val| { 17 | assert_eq!(val, 123); 18 | handle.send(SystemEvent::Stop); 19 | }); 20 | System::start(run); 21 | }); 22 | 23 | tx.send(123); 24 | 25 | handle.join(); 26 | } 27 | -------------------------------------------------------------------------------- /tests/test_or.rs: -------------------------------------------------------------------------------- 1 | use sonr::errors::Result; 2 | use sonr::prelude::*; 3 | use sonr::reactor::producers::Mono; 4 | use sonr::reactor::Either; 5 | use sonr::reactor::consumers::Consume; 6 | 7 | type R = Result<()>; 8 | 9 | 10 | #[test] 11 | fn test_or() -> R { 12 | let system_sig = System::init()?; 13 | 14 | let int_consumer = Consume::new(); 15 | let string_consumer = Consume::new(); 16 | 17 | // Convert the output to a u32 as `or` can only apply 18 | // to reactors with the same `Output`. 19 | let string_consumer = string_consumer.map(|_| 0u32); 20 | 21 | let producer = Mono::new(2u32)?; 22 | let mut test_complete = false; 23 | let run = producer.map(|val: u32| { 24 | if val == 1 { 25 | Either::A(val) 26 | } else { 27 | Either::B(format!("{}", val)) 28 | } 29 | }).chain(int_consumer.or(string_consumer).map(|_| { 30 | system_sig.send(SystemEvent::Stop); 31 | test_complete = true; 32 | })); 33 | 34 | System::start(run)?; 35 | 36 | assert!(test_complete); 37 | Ok(()) 38 | } 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Jonas 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/reactor/consumers.rs: -------------------------------------------------------------------------------- 1 | //! Consumers consume the output of other reactors. 2 | use super::{Reaction, Reactor}; 3 | use std::marker::PhantomData; 4 | 5 | /// Consume the output of a `Reactor`. 6 | /// 7 | /// Mostly useful for testing. 8 | /// ``` 9 | /// # use sonr::prelude::*; 10 | /// # use sonr::reactor::producers::Mono; 11 | /// # use sonr::errors::Result; 12 | /// use sonr::reactor::consumers::Consume; 13 | /// 14 | /// fn main() -> Result<()> { 15 | /// let sys_sig = System::init()?; 16 | /// 17 | /// let reactor_a = Mono::new(1u8)?; 18 | /// let reactor_b = Consume::new().map(|_| sys_sig.send(SystemEvent::Stop)); 19 | /// 20 | /// System::start(reactor_a.chain(reactor_b)); 21 | /// # Ok(()) 22 | /// } 23 | /// ``` 24 | pub struct Consume { 25 | _p: PhantomData, 26 | } 27 | 28 | impl Consume { 29 | /// Create a new `Consume` 30 | pub fn new() -> Self { 31 | Self { _p: PhantomData } 32 | } 33 | } 34 | 35 | impl Reactor for Consume { 36 | type Input = T; 37 | type Output = T; 38 | 39 | fn react(&mut self, reaction: Reaction) -> Reaction { 40 | reaction 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /examples/writer.rs: -------------------------------------------------------------------------------- 1 | use std::io::Write; 2 | use std::net::SocketAddr; 3 | use sonr::prelude::*; 4 | use sonr::net::tcp::{ReactiveTcpListener, TcpStream}; 5 | use sonr::errors::Result; 6 | 7 | // ----------------------------------------------------------------------------- 8 | // - Writer - 9 | // Write "bye" and drop the connection. 10 | // ----------------------------------------------------------------------------- 11 | struct Writer; 12 | 13 | impl Reactor for Writer { 14 | type Input = (TcpStream, SocketAddr); 15 | type Output = (); 16 | 17 | fn react(&mut self, reaction: Reaction) -> Reaction { 18 | use Reaction::*; 19 | match reaction { 20 | Value((mut stream, addr)) => { 21 | eprintln!("{:?} connected", addr); 22 | stream.write(b"bye\n"); 23 | Continue 24 | } 25 | Event(ev) => Continue, 26 | Continue => Continue, 27 | } 28 | } 29 | } 30 | 31 | fn main() -> Result<()> { 32 | System::init()?; 33 | 34 | let listener = ReactiveTcpListener::bind("127.0.0.1:8000")?; 35 | let writer = Writer; 36 | let run = listener.chain(writer); 37 | 38 | System::start(run)?; 39 | Ok(()) 40 | } 41 | -------------------------------------------------------------------------------- /examples/multithreaded.rs: -------------------------------------------------------------------------------- 1 | use std::io::Write; 2 | use std::thread; 3 | use sonr::prelude::*; 4 | use sonr::errors::Result; 5 | use sonr::sync::queue::{ReactiveQueue, ReactiveDeque}; 6 | use sonr::net::tcp::{ReactiveTcpListener, TcpStream, ReactiveTcpStream}; 7 | 8 | // ----------------------------------------------------------------------------- 9 | // - Writer - 10 | // Writer "bye" and drop the connection 11 | // ----------------------------------------------------------------------------- 12 | struct Writer; 13 | 14 | impl Reactor for Writer { 15 | type Input = TcpStream; 16 | type Output = (); 17 | 18 | fn react(&mut self, reaction: Reaction) -> Reaction { 19 | use Reaction::*; 20 | match reaction { 21 | Value(mut stream) => { 22 | stream.write(b"bye\n"); 23 | Continue 24 | } 25 | Event(ev) => Continue, 26 | Continue => Continue, 27 | } 28 | } 29 | } 30 | 31 | fn main() -> Result<()> { 32 | System::init()?; 33 | 34 | // Listen for incoming connections 35 | let listener = ReactiveTcpListener::bind("127.0.0.1:8000")?.map(|(s, _)| s); 36 | // Connection queue for connections to be sent to another thread. 37 | let mut queue = ReactiveQueue::unbounded(); 38 | 39 | for _ in 0..4 { 40 | let deque = queue.deque(); 41 | thread::spawn(move || -> Result<()> { 42 | System::init()?; 43 | let deque = ReactiveDeque::new(deque)?; 44 | let writer = Writer; 45 | let run = deque.chain(writer); 46 | System::start(run)?; 47 | Ok(()) 48 | }); 49 | } 50 | 51 | let run = listener.chain(queue); 52 | System::start(run)?; 53 | Ok(()) 54 | } 55 | -------------------------------------------------------------------------------- /tests/test_listener.rs: -------------------------------------------------------------------------------- 1 | use sonr::net::{stream, tcp}; 2 | use sonr::reactor::{Reaction, Reactor}; 3 | use sonr::sync::signal::SignalSender; 4 | use sonr::system::{System, SystemEvent}; 5 | use sonr::Event; 6 | use std::io::{Read, Write}; 7 | use std::thread; 8 | 9 | // ----------------------------------------------------------------------------- 10 | // - Test tcp client - 11 | // Reads "hi" from the underlying stream 12 | // and if successful it will issue a `Stop` 13 | // system event and stop the main loop 14 | // ----------------------------------------------------------------------------- 15 | struct TcpClient { 16 | stream: tcp::ReactiveTcpStream, 17 | system_sig: SignalSender, 18 | } 19 | 20 | impl TcpClient { 21 | pub fn new(stream: tcp::ReactiveTcpStream, system_sig: SignalSender) -> Self { 22 | Self { stream, system_sig } 23 | } 24 | } 25 | 26 | impl Reactor for TcpClient { 27 | type Output = (); 28 | type Input = (); 29 | 30 | fn react(&mut self, reaction: Reaction) -> Reaction { 31 | if let Reaction::Event(event) = reaction { 32 | if let Reaction::Value(()) = self.stream.react(Reaction::Event(event)) { 33 | if self.stream.readable() { 34 | let mut buf = [0u8; 2]; 35 | self.stream.read(&mut buf); 36 | if &buf[..] == b"hi" { 37 | self.system_sig.send(SystemEvent::Stop); 38 | } 39 | } 40 | } 41 | } 42 | 43 | Reaction::Continue 44 | } 45 | } 46 | 47 | #[test] 48 | fn test_listener() { 49 | let system_sig = System::init().unwrap(); 50 | 51 | let handle = thread::spawn(move || { 52 | System::init(); 53 | let tcp = tcp::ReactiveTcpListener::bind("127.0.0.1:5555").unwrap(); 54 | let tcp = tcp.map(|(mut stream, addr): (tcp::TcpStream, _)| { 55 | stream.write(&b"hi"[..]); 56 | (stream, addr) 57 | }); 58 | System::start(tcp); 59 | }); 60 | 61 | thread::sleep_ms(200); 62 | let stream = tcp::TcpStream::connect(&"127.0.0.1:5555".parse().unwrap()).unwrap(); 63 | let client = TcpClient::new(tcp::ReactiveTcpStream::new(stream).unwrap(), system_sig); 64 | System::start(client); 65 | } 66 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Simple Opinionated Networking in Rust 2 | //! 3 | //! Sonr builds on the idea of chaining reactors together to form the flow of the application. 4 | //! 5 | //! The two main components of Sonr are the [`Reactor`] and the [`System`]. 6 | //! 7 | //! 8 | //! A [`Reactor`] reacts to the output of another reactor or a mio::[`Event`], and has 9 | //! an input and an output. This makes it possible (and intended) to chain two 10 | //! reactors. Such a chain is in it self a [`Reactor`], and can be chained further. 11 | //! 12 | //! The [`System`] runs the reactors and handles the registration and re-registration 13 | //! of reactors (using `mio::Poll::register`). 14 | //! 15 | //!```no_run 16 | //! use std::io::Write; 17 | //! use std::net::SocketAddr; 18 | //! use sonr::prelude::*; 19 | //! use sonr::net::tcp::{ReactiveTcpListener, TcpStream}; 20 | //! use sonr::errors::Result; 21 | //! 22 | //! // ----------------------------------------------------------------------------- 23 | //! // - Writer - 24 | //! // Write "bye" and drop the connection. 25 | //! // ----------------------------------------------------------------------------- 26 | //! struct Writer; 27 | //! 28 | //! impl Reactor for Writer { 29 | //! type Input = (TcpStream, SocketAddr); 30 | //! type Output = (); 31 | //! 32 | //! fn react(&mut self, reaction: Reaction) -> Reaction { 33 | //! use Reaction::*; 34 | //! match reaction { 35 | //! Value((mut stream, addr)) => { 36 | //! eprintln!("{:?} connected", addr); 37 | //! stream.write(b"bye\n"); 38 | //! Continue 39 | //! } 40 | //! Event(ev) => Continue, 41 | //! Continue => Continue, 42 | //! } 43 | //! } 44 | //! } 45 | //! 46 | //! fn main() -> Result<()> { 47 | //! System::init()?; 48 | //! 49 | //! let listener = ReactiveTcpListener::bind("127.0.0.1:8000")?; 50 | //! let writer = Writer; 51 | //! let run = listener.chain(writer); 52 | //! 53 | //! System::start(run)?; 54 | //! Ok(()) 55 | //! } 56 | //! ``` 57 | //! 58 | //! [`Reactor`]: reactor/trait.Reactor.html 59 | //! [`System`]: system/struct.System.html 60 | //! [`Event`]: struct.Event.html 61 | #[deny(missing_docs)] 62 | pub mod reactor; 63 | 64 | #[deny(missing_docs)] 65 | pub mod system; 66 | 67 | #[deny(missing_docs)] 68 | pub mod net; 69 | 70 | #[deny(missing_docs)] 71 | pub mod sync; 72 | 73 | #[deny(missing_docs)] 74 | pub mod errors; 75 | 76 | #[deny(missing_docs)] 77 | mod prevec; 78 | 79 | pub use prevec::PreVec; 80 | 81 | // Re-exports 82 | pub use mio::{Token, Event, Evented, PollOpt, Poll, Ready, SetReadiness, Registration}; 83 | 84 | pub mod prelude { 85 | pub use mio::{Token, Event}; 86 | pub use crate::reactor::{Reaction, Reactor}; 87 | pub use crate::system::{SystemEvent, System}; 88 | pub use crate::net::stream::Stream; 89 | } 90 | -------------------------------------------------------------------------------- /src/errors.rs: -------------------------------------------------------------------------------- 1 | //! SONR default `Error` 2 | use std; 3 | use std::net::AddrParseError; 4 | use std::string::FromUtf8Error; 5 | use mio::Token; 6 | 7 | use crossbeam::channel::{TryRecvError, RecvError}; 8 | 9 | /// Result type: `std::result::Error` 10 | pub type Result = std::result::Result; 11 | 12 | 13 | /// Wrapping error type. 14 | #[derive(Debug)] 15 | pub enum Error { 16 | /// std::io::Error 17 | Io(std::io::Error), 18 | 19 | /// No connection: 20 | /// A connection with a specific `Token` no longer exists 21 | NoConnection(Token), 22 | 23 | /// The connection was removed either by closing 24 | /// the socket or through a socket error 25 | ConnectionRemoved(Token), 26 | 27 | /// The `PreVec` does not have capacity for the new entry 28 | NoCapacity, 29 | 30 | /// The session was already registered. 31 | /// A session can only be registered once 32 | /// (but reregistered multiple times) 33 | AlreadyRegistered, 34 | 35 | /// No unix domain socket waiting for a connection 36 | NoUdsConnection, 37 | 38 | /// Try receive error 39 | TryRecvError(TryRecvError), 40 | 41 | /// Receive error 42 | RecvError(RecvError), 43 | 44 | /// Address parse error 45 | AddrParseError, 46 | 47 | /// From UTF8 error 48 | FromUtf8Error(FromUtf8Error), 49 | } 50 | 51 | 52 | // ----------------------------------------------------------------------------- 53 | // - IO error - 54 | // ----------------------------------------------------------------------------- 55 | impl From for Error { 56 | fn from(err: std::io::Error) -> Error { 57 | Error::Io(err) 58 | } 59 | } 60 | 61 | // ----------------------------------------------------------------------------- 62 | // - mpsc::RecvError - 63 | // ----------------------------------------------------------------------------- 64 | impl From for Error { 65 | fn from(err: RecvError) -> Error { 66 | Error::RecvError(err) 67 | } 68 | } 69 | 70 | // ----------------------------------------------------------------------------- 71 | // - mpsc::TryRecvError - 72 | // ----------------------------------------------------------------------------- 73 | impl From for Error { 74 | fn from(err: TryRecvError) -> Error { 75 | Error::TryRecvError(err) 76 | } 77 | } 78 | 79 | // ----------------------------------------------------------------------------- 80 | // - AddrParseError - 81 | // ----------------------------------------------------------------------------- 82 | impl From for Error { 83 | fn from(_: AddrParseError) -> Error { 84 | Error::AddrParseError 85 | } 86 | } 87 | 88 | // ----------------------------------------------------------------------------- 89 | // - FromUtf8Error - 90 | // ----------------------------------------------------------------------------- 91 | impl From for Error { 92 | fn from(err: FromUtf8Error) -> Error { 93 | Error::FromUtf8Error(err) 94 | } 95 | } 96 | 97 | -------------------------------------------------------------------------------- /examples/webserver.rs: -------------------------------------------------------------------------------- 1 | use std::io::Write; 2 | use std::io::ErrorKind::WouldBlock; 3 | use std::net::SocketAddr; 4 | use std::collections::HashMap; 5 | use std::thread; 6 | 7 | use sonr::{Token, Event}; 8 | use sonr::errors::Result; 9 | use sonr::net::tcp::{ReactiveTcpListener, ReactiveTcpStream, TcpStream}; 10 | use sonr::reactor::{Reactor, Reaction}; 11 | use sonr::system::System; 12 | use sonr::sync::queue::{ReactiveDeque, ReactiveQueue}; 13 | 14 | // ----------------------------------------------------------------------------- 15 | // - Disclaimer - 16 | // This example will simply write the response to the 17 | // underlying tcp stream until it either blocks 18 | // or errors out. This is not how a web server should behave, 19 | // but it's useful for testing. 20 | // ----------------------------------------------------------------------------- 21 | 22 | static RESPONSE: &'static [u8] = b"HTTP/1.1 200 OK\nContent-Length: 13\n\nHello World\n\n"; 23 | 24 | struct Connections { 25 | inner: HashMap 26 | } 27 | 28 | impl Connections { 29 | fn handle_connection_event(&mut self, event: Event) -> bool { 30 | let reacting = self.inner.get(&event.token()).is_some(); 31 | 32 | let stream = self.inner.remove(&event.token()).map(|mut stream| { 33 | stream.react(Reaction::Event(event)); 34 | while stream.writable() { 35 | match stream.write(&RESPONSE) { 36 | Ok(_) => {}, 37 | Err(ref e) if e.kind() == WouldBlock => return Some(stream), 38 | Err(e) => return None, 39 | } 40 | } 41 | return None 42 | }); 43 | 44 | match stream { 45 | Some(Some(stream)) => { self.inner.insert(stream.token(), stream); } 46 | _ => {} 47 | } 48 | 49 | reacting 50 | } 51 | } 52 | 53 | impl Reactor for Connections { 54 | type Input = (TcpStream, SocketAddr); 55 | type Output = (); 56 | 57 | fn react(&mut self, reaction: Reaction) -> Reaction { 58 | match reaction { 59 | Reaction::Value(input) => { 60 | let (stream, _) = input; // ignore address 61 | let tcp_stream = ReactiveTcpStream::new(stream).unwrap(); 62 | self.inner.insert(tcp_stream.token(), tcp_stream); 63 | Reaction::Continue 64 | } 65 | Reaction::Event(event) => { 66 | match self.handle_connection_event(event) { 67 | true => Reaction::Continue, 68 | false => Reaction::Event(event) 69 | } 70 | } 71 | Reaction::Continue => Reaction::Continue, 72 | } 73 | } 74 | } 75 | 76 | fn main() -> Result<()> { 77 | System::init(); 78 | let listener = ReactiveTcpListener::bind("127.0.0.1:5555")?; 79 | let mut stream_q = ReactiveQueue::unbounded(); 80 | 81 | for _ in 0..8 { 82 | let deque = stream_q.deque(); 83 | thread::spawn(move || { 84 | System::init(); 85 | let incoming_streams = ReactiveDeque::new(deque).unwrap(); 86 | let connections = Connections { inner: HashMap::new() }; 87 | 88 | let streams = incoming_streams.chain(connections); 89 | System::start(streams); 90 | }); 91 | } 92 | 93 | let server = listener.chain(stream_q); 94 | System::start(server); 95 | Ok(()) 96 | } 97 | -------------------------------------------------------------------------------- /src/sync/broadcast.rs: -------------------------------------------------------------------------------- 1 | //! Broadcast 2 | use std::sync::Arc; 3 | use parking_lot::RwLock; 4 | 5 | use crate::sync::signal::{SignalReceiver, SignalSender}; 6 | use crate::reactor::{Reaction, Reactor}; 7 | 8 | use super::Capacity; 9 | 10 | // ----------------------------------------------------------------------------- 11 | // - Broadcast - 12 | // notify every subscriber, meaning T has to be Clone 13 | // ----------------------------------------------------------------------------- 14 | /// Broadcast value to all subscribers. 15 | /// 16 | /// This is useful in a pub/sub setup, however it requires that each value implements 17 | /// clone as the data is cloned. 18 | pub struct Broadcast { 19 | subscribers: Arc>>>, 20 | capacity: Capacity, 21 | } 22 | 23 | impl From for Broadcast { 24 | fn from(capacity: Capacity) -> Self { 25 | Self { 26 | subscribers: Arc::new(RwLock::new(Vec::new())), 27 | capacity, 28 | } 29 | } 30 | } 31 | 32 | impl Broadcast { 33 | /// Create an unbounded broadcaster 34 | pub fn unbounded() -> Self { 35 | Self::from(Capacity::Unbounded) 36 | } 37 | 38 | /// Create an bounded broadcaster 39 | pub fn bounded(capacity: usize) -> Self { 40 | Self::from(Capacity::Bounded(capacity)) 41 | } 42 | 43 | /// Create a new subscriber of the data 44 | pub fn subscriber(&self) -> SignalReceiver { 45 | let signal = SignalReceiver::from(&self.capacity); 46 | let trigger = signal.sender(); 47 | { 48 | let mut subs = self.subscribers.write(); 49 | subs.push(trigger); 50 | } 51 | 52 | signal 53 | } 54 | 55 | /// Publish data to all subscribers. 56 | /// Note that the published data is cloned for each subscriber. 57 | pub fn publish(&self, val: T) { 58 | let subs = self.subscribers.read(); 59 | for sub in subs.iter() { 60 | let val_c = val.clone(); 61 | let _ = sub.send(val_c); 62 | } 63 | } 64 | } 65 | 66 | impl Clone for Broadcast { 67 | fn clone(&self) -> Self { 68 | Self { 69 | subscribers: self.subscribers.clone(), 70 | capacity: self.capacity 71 | } 72 | } 73 | } 74 | 75 | // ----------------------------------------------------------------------------- 76 | // - Reactive broadcast - 77 | // ----------------------------------------------------------------------------- 78 | /// A reactive broadcaster 79 | pub struct ReactiveBroadcast { 80 | inner: Broadcast, 81 | } 82 | 83 | impl ReactiveBroadcast { 84 | /// Create a bounded reactive broadcast 85 | pub fn bounded(capacity: usize) -> Self { 86 | Self { 87 | inner: Broadcast::bounded(capacity) 88 | } 89 | } 90 | 91 | /// Create an unbounded reactive broadcast 92 | pub fn unbounded() -> Self { 93 | Self { 94 | inner: Broadcast::unbounded() 95 | } 96 | } 97 | 98 | /// Create a new subscriber of the data 99 | pub fn subscriber(&self) -> SignalReceiver { 100 | self.inner.subscriber() 101 | } 102 | } 103 | 104 | impl Reactor for ReactiveBroadcast { 105 | type Output = (); 106 | type Input = T; 107 | 108 | fn react(&mut self, reaction: Reaction) -> Reaction { 109 | match reaction { 110 | Reaction::Value(val) => { 111 | self.inner.publish(val); 112 | Reaction::Value(()) 113 | }, 114 | Reaction::Event(e) => Reaction::Event(e), 115 | Reaction::Continue => Reaction::Continue, 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/net/uds.rs: -------------------------------------------------------------------------------- 1 | //! Unix Domain Sockets 2 | 3 | use std::io::ErrorKind::WouldBlock; 4 | use std::os::unix::net::SocketAddr; 5 | 6 | use mio::{Ready, Token}; 7 | 8 | use crate::reactor::Reactor; 9 | use crate::reactor::{Reaction, EventedReactor}; 10 | use crate::system::System; 11 | use crate::errors::Result; 12 | use crate::net::stream::{Stream, StreamRef}; 13 | 14 | // Re-exports 15 | pub use mio_uds::{UnixListener, UnixStream}; 16 | 17 | // ----------------------------------------------------------------------------- 18 | // - Uds Listener - 19 | // ----------------------------------------------------------------------------- 20 | /// Accept incoming connections and output `(UnixStream, SocketAddr)`; 21 | /// 22 | ///``` 23 | /// # use std::time::Duration; 24 | /// # use std::net::SocketAddr; 25 | /// # use std::thread; 26 | /// # use std::fs::remove_file; 27 | /// # use sonr::prelude::*; 28 | /// # use sonr::errors::Result; 29 | /// use sonr::net::uds::{ReactiveUdsListener, UnixStream}; 30 | /// 31 | /// fn main() -> Result<()> { 32 | /// let system_signals = System::init()?; 33 | /// 34 | /// # remove_file("/tmp/sonr-uds-test.sock"); 35 | /// let listener = ReactiveUdsListener::bind("/tmp/sonr-uds-test.sock")?; 36 | /// let run = listener.map(|(strm, addr)| { 37 | /// eprintln!("connection from: {:?}", addr); 38 | /// strm 39 | /// }); 40 | /// # thread::spawn(move || { 41 | /// # thread::sleep(Duration::from_millis(100)); 42 | /// # UnixStream::connect("/tmp/sonr-uds-test.sock"); 43 | /// # system_signals.send(SystemEvent::Stop); 44 | /// # }); 45 | /// 46 | /// System::start(run)?; 47 | /// Ok(()) 48 | /// } 49 | /// ``` 50 | pub struct ReactiveUdsListener { 51 | inner: EventedReactor, 52 | } 53 | 54 | impl ReactiveUdsListener { 55 | /// Create a new Reactive UnixListener 56 | pub fn bind(path: impl AsRef) -> Result { 57 | Ok(Self { 58 | inner: EventedReactor::new( 59 | UnixListener::bind(path.as_ref())?, 60 | Ready::readable(), 61 | )?, 62 | }) 63 | } 64 | 65 | /// Get `Token` registered with the listener; 66 | pub fn token(&self) -> Token { 67 | self.inner.token() 68 | } 69 | } 70 | 71 | impl Reactor for ReactiveUdsListener { 72 | type Output = (UnixStream, SocketAddr); 73 | type Input = (); 74 | 75 | fn react(&mut self, reaction: Reaction) -> Reaction { 76 | if let Reaction::Event(event) = reaction { 77 | if self.inner.token() == event.token() { 78 | let res = self.inner.inner().accept(); 79 | match res { 80 | Ok(Some(val)) => return Reaction::Value(val), 81 | Ok(None) => return Reaction::Continue, 82 | Err(ref e) if e.kind() == WouldBlock => { 83 | System::reregister(&self.inner).unwrap(); 84 | return Reaction::Continue 85 | } 86 | Err(_) => return Reaction::Continue, 87 | } 88 | } 89 | } 90 | 91 | if let Reaction::Continue = reaction { 92 | let res = self.inner.inner().accept(); 93 | match res { 94 | Ok(Some(val)) => return Reaction::Value(val), 95 | Ok(None) => return Reaction::Continue, 96 | Err(ref e) if e.kind() == WouldBlock => { 97 | System::reregister(&self.inner).unwrap(); 98 | return Reaction::Continue 99 | } 100 | Err(_) => return Reaction::Continue, 101 | } 102 | } 103 | 104 | match reaction { 105 | Reaction::Event(e) => Reaction::Event(e), 106 | Reaction::Continue => Reaction::Continue, 107 | Reaction::Value(_) => Reaction::Continue, 108 | } 109 | } 110 | } 111 | 112 | 113 | /// Type alias for `Stream` 114 | pub type ReactiveUdsStream = Stream; 115 | 116 | impl ReactiveUdsStream { 117 | /// Create a new reactive uds stream from a &str 118 | pub fn connect(path: &str) -> Result { 119 | let stream = UnixStream::connect(path)?; 120 | Ok(Self::new(stream)?) 121 | } 122 | } 123 | 124 | impl StreamRef for ReactiveUdsStream { 125 | type Evented = UnixStream; 126 | 127 | fn stream_ref(&self) -> &Self { 128 | self 129 | } 130 | 131 | fn stream_mut(&mut self) -> &mut Self { 132 | self 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /src/net/tcp.rs: -------------------------------------------------------------------------------- 1 | //! Reactive Tcp networking 2 | 3 | use std::io::ErrorKind::WouldBlock; 4 | use std::net::SocketAddr; 5 | 6 | use mio::{Ready, Token}; 7 | 8 | use crate::errors::Result; 9 | use crate::net::stream::{Stream, StreamRef}; 10 | use crate::reactor::Reactor; 11 | use crate::reactor::{EventedReactor, Reaction}; 12 | use crate::system::System; 13 | 14 | // Re-exports 15 | pub use mio::net::{TcpStream, TcpListener}; 16 | 17 | // ----------------------------------------------------------------------------- 18 | // - Tcp Listener - 19 | // ----------------------------------------------------------------------------- 20 | /// Accept incoming connections and output `(TcpStream, SocketAddr)`; 21 | /// 22 | ///``` 23 | /// # use std::time::Duration; 24 | /// # use std::net::SocketAddr; 25 | /// # use std::thread; 26 | /// # use std::net::TcpStream as StdStream; 27 | /// # use sonr::prelude::*; 28 | /// # use sonr::errors::Result; 29 | /// use sonr::net::tcp::{ReactiveTcpListener, TcpStream}; 30 | /// 31 | /// fn main() -> Result<()> { 32 | /// let system_signals = System::init()?; 33 | /// 34 | /// let listener = ReactiveTcpListener::bind("127.0.0.1:5555")?; 35 | /// let run = listener.map(|(strm, addr)| { 36 | /// eprintln!("connection from: {:?}", addr); 37 | /// strm 38 | /// }); 39 | /// # thread::spawn(move || { 40 | /// # thread::sleep(Duration::from_millis(100)); 41 | /// # StdStream::connect("127.0.0.1:5555"); 42 | /// # system_signals.send(SystemEvent::Stop); 43 | /// # }); 44 | /// 45 | /// System::start(run)?; 46 | /// Ok(()) 47 | /// } 48 | /// ``` 49 | pub struct ReactiveTcpListener { 50 | inner: EventedReactor, 51 | } 52 | 53 | impl ReactiveTcpListener { 54 | /// Create a new listener from a mio::TcpListener 55 | pub fn new(listener: mio::net::TcpListener) -> Result { 56 | Ok(Self { 57 | inner: EventedReactor::new(listener, Ready::readable())?, 58 | }) 59 | } 60 | 61 | /// Create a new listener from an address 62 | pub fn bind(addr: &str) -> Result { 63 | Ok(Self { 64 | inner: EventedReactor::new( 65 | mio::net::TcpListener::bind(&addr.parse()?)?, 66 | Ready::readable(), 67 | )?, 68 | }) 69 | } 70 | 71 | /// Get `Token` registered with the listener; 72 | pub fn token(&self) -> Token { 73 | self.inner.token() 74 | } 75 | } 76 | 77 | impl Reactor for ReactiveTcpListener { 78 | type Output = (mio::net::TcpStream, SocketAddr); 79 | type Input = (); 80 | 81 | fn react(&mut self, reaction: Reaction) -> Reaction { 82 | if let Reaction::Event(event) = reaction { 83 | if self.inner.token() == event.token() { 84 | let res = self.inner.inner().accept(); 85 | match res { 86 | Ok(val) => return Reaction::Value(val), 87 | Err(ref e) if e.kind() == WouldBlock => { 88 | let _ = System::reregister(&self.inner); 89 | return Reaction::Continue 90 | } 91 | Err(_) => return Reaction::Continue, 92 | } 93 | } else { 94 | return Reaction::Event(event); 95 | } 96 | } 97 | 98 | if let Reaction::Continue = reaction { 99 | let res = self.inner.inner().accept(); 100 | match res { 101 | Ok(val) => return Reaction::Value(val), 102 | Err(ref e) if e.kind() == WouldBlock => { 103 | let _ = System::reregister(&self.inner); 104 | return Reaction::Continue 105 | } 106 | Err(_) => return Reaction::Continue, 107 | } 108 | } 109 | 110 | match reaction { 111 | Reaction::Event(e) => Reaction::Event(e), 112 | _ => Reaction::Continue, 113 | } 114 | } 115 | } 116 | 117 | /// A reactive tcp stream. 118 | /// See [`Stream`]. 119 | /// 120 | /// [`Stream`]: ../stream/struct.Stream.html 121 | pub type ReactiveTcpStream = Stream; 122 | 123 | impl ReactiveTcpStream { 124 | /// Create a new reactive tcp stream from a &SocketAddr 125 | pub fn connect(addr: &SocketAddr) -> Result { 126 | let stream = mio::net::TcpStream::connect(addr)?; 127 | Ok(Self::new(stream)?) 128 | } 129 | } 130 | 131 | impl StreamRef for ReactiveTcpStream { 132 | type Evented = mio::net::TcpStream; 133 | 134 | fn stream_ref(&self) -> &Self { 135 | self 136 | } 137 | 138 | fn stream_mut(&mut self) -> &mut Self { 139 | self 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/reactor/producers.rs: -------------------------------------------------------------------------------- 1 | //! There are two producers: 2 | //! * [`Mono`] 3 | //! * [`ReactiveGenerator`] 4 | //! 5 | //! The producer is useful to give a [`System`] an initial start value if no 6 | //! Reactors driven by external events are provided (e.g no Listener or Stream). 7 | //! 8 | //! ``` 9 | //! # use sonr::system::{System, SystemEvent}; 10 | //! # use sonr::reactor::Reactor; 11 | //! # use sonr::reactor::producers::Mono; 12 | //! fn main() { 13 | //! let handle = System::init().unwrap(); 14 | //! let produce_u8 = Mono::new(0u8).unwrap() 15 | //! .map(|byte| { 16 | //! eprintln!("received byte: {:?}", byte); 17 | //! handle.send(SystemEvent::Stop) 18 | //! }); 19 | //! 20 | //! System::start(produce_u8); 21 | //! } 22 | //! ``` 23 | //! 24 | //! [`Mono`]: struct.Mono.html 25 | //! [`ReactiveGenerator`]: struct.ReactiveGenerator.html 26 | //! [`System`]: ../../system/struct.System.html 27 | use std::mem; 28 | use std::collections::VecDeque; 29 | use mio::{Registration, Ready}; 30 | use crate::errors::Result; 31 | 32 | use super::{Reactor, Reaction, EventedReactor}; 33 | 34 | /// The [`ReactiveGenerator`] reacts as soon as the [`System`] starts. 35 | /// ``` 36 | /// # use sonr::system::{System, SystemEvent}; 37 | /// # use sonr::reactor::Reactor; 38 | /// # use sonr::reactor::producers::ReactiveGenerator; 39 | /// fn main() { 40 | /// let handle = System::init().unwrap(); 41 | /// let gen = ReactiveGenerator::new(vec![0u8]).unwrap(); 42 | /// 43 | /// System::start(gen.map(|i| { 44 | /// assert_eq!(i, 0u8); 45 | /// handle.send(SystemEvent::Stop) 46 | /// })); 47 | /// } 48 | /// ``` 49 | /// 50 | /// [`ReactiveGenerator`]: struct.ReactiveGenerator.html 51 | /// [`System`]: ../../system/struct.System.html 52 | pub struct ReactiveGenerator { 53 | inner: VecDeque, 54 | reactor: EventedReactor, 55 | } 56 | 57 | impl ReactiveGenerator { 58 | /// Creates a new `ReactiveGenerator` with the given collection. 59 | pub fn new(inner: Vec) -> Result { 60 | let (reg, set_ready) = Registration::new2(); 61 | let reactor = EventedReactor::new(reg, Ready::readable())?; 62 | set_ready.set_readiness(Ready::readable())?; 63 | Ok(Self { 64 | inner: inner.into(), 65 | reactor, 66 | }) 67 | } 68 | } 69 | 70 | 71 | impl Reactor for ReactiveGenerator { 72 | type Output = T; 73 | type Input = (); 74 | 75 | fn react(&mut self, reaction: Reaction) -> Reaction { 76 | match reaction { 77 | Reaction::Event(ev) => { 78 | if ev.token() != self.reactor.token() { 79 | return ev.into() 80 | } 81 | 82 | match self.inner.pop_front() { 83 | Some(val) => Reaction::Value(val), 84 | None => Reaction::Continue, 85 | } 86 | } 87 | Reaction::Continue => { 88 | match self.inner.pop_front() { 89 | Some(val) => Reaction::Value(val), 90 | None => Reaction::Continue, 91 | } 92 | } 93 | Reaction::Value(_) => Reaction::Continue, 94 | } 95 | } 96 | } 97 | 98 | /// A [`Mono`] reacts as soon as the [`System`] starts and produces exactly one value 99 | /// (the value set by the constructor). 100 | /// ``` 101 | /// # use sonr::system::{System, SystemEvent}; 102 | /// # use sonr::reactor::Reactor; 103 | /// # use sonr::reactor::producers::Mono; 104 | /// fn main() { 105 | /// let handle = System::init().unwrap(); 106 | /// let gen = Mono::new(0u8).unwrap(); 107 | /// 108 | /// System::start(gen.map(|i| { 109 | /// assert_eq!(i, 0u8); 110 | /// handle.send(SystemEvent::Stop) 111 | /// })); 112 | /// } 113 | /// ``` 114 | /// 115 | /// [`Mono`]: struct.Mono.html 116 | /// [`System`]: ../../system/struct.System.html 117 | pub struct Mono { 118 | inner: Reaction, 119 | reactor: EventedReactor, 120 | } 121 | 122 | impl Mono { 123 | /// Create a new `Mono`. 124 | pub fn new(val: T) -> Result { 125 | let (reg, set_ready) = Registration::new2(); 126 | let reactor = EventedReactor::new(reg, Ready::readable())?; 127 | set_ready.set_readiness(Ready::readable())?; 128 | Ok(Self { 129 | inner: Reaction::Value(val), 130 | reactor, 131 | }) 132 | } 133 | } 134 | 135 | impl Reactor for Mono { 136 | type Input = (); 137 | type Output = T; 138 | 139 | fn react(&mut self, reaction: Reaction<()>) -> Reaction { 140 | if let Reaction::Event(ev) = reaction { 141 | if ev.token() != self.reactor.token() { 142 | return ev.into() 143 | } 144 | 145 | let mut output = Reaction::Continue; 146 | mem::swap(&mut self.inner, &mut output); 147 | return output; 148 | } 149 | 150 | match reaction { 151 | Reaction::Continue => Reaction::Continue, 152 | Reaction::Event(ev) => Reaction::Event(ev), 153 | Reaction::Value(_) => Reaction::Continue, 154 | } 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /tests/test_broadcast.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use std::thread; 3 | 4 | use mio::Event; 5 | 6 | use sonr::reactor::producers::ReactiveGenerator; 7 | use sonr::reactor::{Reaction, Reactor}; 8 | use sonr::sync::broadcast::Broadcast; 9 | use sonr::sync::queue::{ReactiveDeque, ReactiveQueue}; 10 | use sonr::sync::signal::{ReactiveSignalReceiver, SignalSender}; 11 | use sonr::system::{System, SystemEvent}; 12 | 13 | #[derive(Debug)] 14 | struct Counter { 15 | sender: SignalSender, 16 | counter: u8, 17 | } 18 | 19 | impl Reactor for Counter { 20 | type Output = (); 21 | type Input = String; 22 | 23 | fn react(&mut self, reaction: Reaction) -> Reaction { 24 | use Reaction::*; 25 | if let Value(_) = reaction { 26 | self.counter += 1; 27 | if self.counter == 2 { 28 | self.sender.send(SystemEvent::Stop); 29 | } 30 | } 31 | Reaction::Continue 32 | } 33 | } 34 | 35 | #[test] 36 | fn test_broadcast() { 37 | // ----------------------------------------------------------------------------- 38 | // - Broadcast a message from two threads to two different threads - 39 | // Each receiving thread should receive two messages and then 40 | // signal the system to stop 41 | // ----------------------------------------------------------------------------- 42 | let bc = Broadcast::::unbounded(); 43 | let bc1 = bc.clone(); 44 | let bc2 = bc.clone(); 45 | 46 | // First receiving thread 47 | let s1 = bc.subscriber(); 48 | let h1 = thread::spawn(move || { 49 | let sender = System::init().unwrap(); 50 | let counter = Counter { sender, counter: 0 }; 51 | let subscriber = ReactiveSignalReceiver::new(s1) 52 | .unwrap() 53 | .map(|v| { 54 | eprintln!("-> thread 1: : {:?}", v); 55 | v 56 | }) 57 | .chain(counter); 58 | System::start(subscriber); 59 | }); 60 | 61 | // Second receiving thread 62 | let s2 = bc.subscriber(); 63 | let h2 = thread::spawn(move || { 64 | let sender = System::init().unwrap(); 65 | let counter = Counter { sender, counter: 0 }; 66 | let subscriber = ReactiveSignalReceiver::new(s2) 67 | .unwrap() 68 | .map(|v| { 69 | eprintln!("-> thread 2: : {:?}", v); 70 | v 71 | }) 72 | .chain(counter); 73 | System::start(subscriber); 74 | }); 75 | 76 | // Give the queue some time 77 | thread::sleep_ms(10); 78 | 79 | // First broadcasting thread 80 | let h3 = thread::spawn(move || { 81 | bc1.publish("first broadcast".into()); 82 | }); 83 | 84 | // Second broadcasting thread 85 | let h4 = thread::spawn(move || { 86 | bc2.publish("second broadcast".into()); 87 | }); 88 | 89 | h1.join(); 90 | h2.join(); 91 | h3.join(); 92 | h4.join(); 93 | } 94 | 95 | #[test] 96 | fn test_bounded_queue() { 97 | let handle = System::init().unwrap(); 98 | let gen = ReactiveGenerator::new((1u8..=4).collect()).unwrap(); 99 | let mut queue = ReactiveQueue::bounded(10); 100 | 101 | let deque = queue.deque(); 102 | 103 | let thread_handle = thread::spawn(move || { 104 | thread::sleep_ms(30); 105 | let fo_handle = System::init().unwrap(); 106 | let dq = ReactiveDeque::new(deque).unwrap(); 107 | let run = dq.map(|s| { 108 | eprintln!("<- rx: {:?}", s); 109 | if s == 4 { 110 | let fo_handle = fo_handle.clone(); 111 | thread::spawn(move || { 112 | fo_handle.send(SystemEvent::Stop); 113 | }); 114 | } 115 | }); 116 | System::start(run); 117 | }); 118 | 119 | let run = gen 120 | .map(|i| { 121 | eprintln!("-> tx: {:?}", i); 122 | if i == 4 { 123 | handle.send(SystemEvent::Stop); 124 | } 125 | i 126 | }) 127 | .chain(queue); 128 | System::start(run); 129 | thread_handle.join(); 130 | } 131 | 132 | #[test] 133 | fn test_bounded_broadcast() { 134 | // ----------------------------------------------------------------------------- 135 | // - Broadcast a message from two threads to two different threads - 136 | // Each receiving thread should receive two messages and then 137 | // signal the system to stop 138 | // ----------------------------------------------------------------------------- 139 | let bc = Broadcast::::bounded(0); 140 | let bc1 = bc.clone(); 141 | let bc2 = bc.clone(); 142 | 143 | // First receiving thread 144 | let s1 = bc.subscriber(); 145 | let h1 = thread::spawn(move || { 146 | let sender = System::init().unwrap(); 147 | let counter = Counter { sender, counter: 0 }; 148 | let subscriber = ReactiveSignalReceiver::new(s1) 149 | .unwrap() 150 | .map(|v| { 151 | eprintln!("-> thread 1: : {:?}", v); 152 | v 153 | }) 154 | .chain(counter); 155 | System::start(subscriber); 156 | }); 157 | 158 | // Second receiving thread 159 | let s2 = bc.subscriber(); 160 | let h2 = thread::spawn(move || { 161 | let sender = System::init().unwrap(); 162 | let counter = Counter { sender, counter: 0 }; 163 | let subscriber = ReactiveSignalReceiver::new(s2) 164 | .unwrap() 165 | .map(|v| { 166 | eprintln!("-> thread 2: : {:?}", v); 167 | v 168 | }) 169 | .chain(counter); 170 | System::start(subscriber); 171 | }); 172 | 173 | // First broadcasting thread 174 | let h3 = thread::spawn(move || { 175 | bc1.publish("first broadcast".into()); 176 | }); 177 | 178 | // Second broadcasting thread 179 | let h4 = thread::spawn(move || { 180 | bc2.publish("second broadcast".into()); 181 | }); 182 | 183 | h1.join(); 184 | h2.join(); 185 | h3.join(); 186 | h4.join(); 187 | } 188 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sonr 2 | 3 | ### Note: this is a work in progress and the api may change 4 | ### Note: currently not on crates.io, use: 5 | 6 | [![Build Status](https://travis-ci.com/hagsteel/sonr.svg?branch=master)](https://travis-ci.com/hagsteel/sonr) 7 | 8 | ``` 9 | [dependencies] 10 | sonr = {git = "https://github.com/hagsteel/sonr" } 11 | 12 | ``` 13 | 14 | ------ 15 | 16 | Simple Opinionated Networking in Rust 17 | 18 | * [API docs](https://hagsteel.github.io/sonr/) 19 | * [Examples](https://github.com/hagsteel/sonr/tree/master/examples) 20 | 21 | ------ 22 | 23 | Sonr is built on top of Mio with the aim to make it easier to create networking 24 | applications. 25 | 26 | The two main components of Sonr are the `Reactor` and the `System`. 27 | 28 | A `Reactor` is anything that reacts to the output of another reactor, and has 29 | an input and an output. This makes it possible (and intended) to chain two 30 | reactors. Such a chain is in it self a `Reactor`, and can be chained further. 31 | 32 | The `System` runs the reactors and handles the registration and re-registration 33 | of reactors (using `mio::Poll::register`). 34 | 35 | `System` is thread local and has to exist for each thread using `Reactors`. 36 | There can only be *one* instance of a `System` per thread, and this instance is created by 37 | calling `System::init()`. Calling `System::init()` twice in the same thread will 38 | panic. 39 | 40 | ```rust 41 | fn main() -> Result<(), sonr::errors::Error> { 42 | System::init()? 43 | 44 | let reactor_1 = Reactor1::new()?; 45 | let reactor_2 = Reactor2::new()?; 46 | let reactor_3 = Reactor3::new()?; 47 | 48 | let run = reactor_1.chain(reactor_2.chain(reactor_3)); 49 | 50 | System::start(run)?; 51 | Ok(()) 52 | } 53 | ``` 54 | 55 | ## Reactor 56 | 57 | The reactor trait consists of two types and a method: 58 | 59 | ```rust 60 | trait Reactor { 61 | type Input; 62 | type Output; 63 | 64 | fn react(&mut self, reaction: Reaction) -> Reaction; 65 | } 66 | ``` 67 | 68 | To chain one reactor with another the `Output` of the first one needs to be of 69 | the same type as the `Input` of the second one. 70 | 71 | The following example shows the creation of a chain from two reactors. 72 | Since none of the reactors are responding to `Event`s there is no need for the 73 | `System` to be initialised. 74 | 75 | ```rust 76 | use sonr::prelude::*; 77 | 78 | struct VecToString; 79 | 80 | impl Reactor for VecToString { 81 | type Input = Vec; 82 | type Output = String; 83 | 84 | fn react(&mut self, reaction: Reaction) -> Reaction { 85 | use Reaction::*; 86 | match reaction { 87 | Value(bytes) => Value(String::from_utf8(bytes).unwrap()), 88 | Event(ev) => Event(ev), 89 | Continue => Continue, 90 | } 91 | } 92 | } 93 | 94 | struct UppercaseString; 95 | 96 | impl Reactor for UppercaseString { 97 | type Input = String; 98 | type Output = String; 99 | 100 | fn react(&mut self, reaction: Reaction) -> Reaction { 101 | use Reaction::*; 102 | match reaction { 103 | Value(mut s) => { 104 | s.make_ascii_uppercase(); 105 | Value(s) 106 | } 107 | Event(ev) => Event(ev), 108 | Continue => Continue, 109 | } 110 | } 111 | } 112 | 113 | fn main() { 114 | let input = "hello world".to_owned().into_bytes(); 115 | 116 | let r1 = VecToString; 117 | let r2 = UppercaseString; 118 | let mut chain = r1.chain(r2); 119 | chain.react(Reaction::Value(input)); 120 | } 121 | ``` 122 | 123 | Since reactors in a chain will always push data forward and never return 124 | anything other than `Reaction::Continue` it is not possible to capture the 125 | output from `chain.react(Raction::Value(input));` here. 126 | 127 | To print the result in the above example it would be possible to create a third 128 | reactor that prints the `Input`, however there is a lot of boilerplate to create 129 | yet another reactor so in this case the `map` function of a reactor could be 130 | used. 131 | 132 | ### Map 133 | 134 | Updating the previous example to use `map` to print the output of 135 | `UppercaseString`: 136 | 137 | ```rust 138 | fn main() { 139 | let input = "hello world".to_owned().into_bytes(); 140 | 141 | let r1 = VecToString; 142 | let r2 = UppercaseString.map(|the_string| println!("{}", the_string)); 143 | let mut chain = r1.chain(r2); 144 | chain.react(Reaction::Value(input)); 145 | } 146 | ``` 147 | 148 | The `map` function takes a closure as an argument, where the argument for the 149 | closure is the `Output` of the reactor. 150 | Since the output of `UppercaseString` is a `String`, the `map` function is 151 | called with a closure `FnMut(UppercaseString::Output) -> T`. 152 | 153 | This is a convenient way to change the output of a reactor. 154 | 155 | The `ReactiveTcpListener` outputs a tuple: `(mio::net::TcpStream, SocketAddr)`. 156 | The map function could be useful here if the `SocketAddr` is not required: 157 | 158 | ```rust 159 | use sonr::prelude::*; 160 | use sonr::net::tcp::ReactiveTcpListener; 161 | 162 | fn main() { 163 | System::init(); 164 | 165 | let listener = ReactiveTcpListener::bind("127.0.0.1:8000") 166 | .unwrap() 167 | .map(|(stream, _socket_addr)| stream); // ignore the SocketAddr 168 | 169 | System::start(listener); 170 | } 171 | ``` 172 | 173 | ### And 174 | 175 | The last method on a Reactor is `and`. 176 | This is useful to run more than one (evented) reactor in parallel. 177 | 178 | Since the output of a tcp listener is a stream and a socket address, it would 179 | not be possible to chain two tcp listeners together. 180 | It is also not possible to call `System::start` twice in the same thread. 181 | 182 | To run two tcp listeners at the same time use `and`: 183 | 184 | ```rust 185 | use sonr::prelude::*; 186 | use sonr::net::tcp::ReactiveTcpListener; 187 | 188 | fn main() { 189 | System::init(); 190 | 191 | let listener_1 = ReactiveTcpListener::bind("127.0.0.1:8000").unwrap(); 192 | let listener_2 = ReactiveTcpListener::bind("127.0.0.1:9000").unwrap(); 193 | 194 | System::start(listener_1.and(listener_2)); 195 | } 196 | ``` 197 | 198 | This means a `Reaction::Event(event)` from the `System` will be sent to both 199 | listeners. 200 | -------------------------------------------------------------------------------- /src/net/stream.rs: -------------------------------------------------------------------------------- 1 | //! Stream 2 | 3 | use std::fmt::{self, Debug, Formatter}; 4 | use std::io::{self, Read, Write}; 5 | 6 | use mio::{Evented, Ready, Token}; 7 | 8 | use crate::errors::Result; 9 | use crate::reactor::Reactor; 10 | use crate::reactor::{EventedReactor, Reaction}; 11 | 12 | /// Anything that has a stream 13 | pub trait StreamRef { 14 | /// The Evented type for the Stream 15 | type Evented: Evented + Read + Write; 16 | 17 | /// Immutable reference to the stream 18 | fn stream_ref(&self) -> &Stream; 19 | 20 | /// Mutable reference to the stream 21 | fn stream_mut(&mut self) -> &mut Stream; 22 | 23 | /// Stream token 24 | fn token(&self) -> Token { 25 | self.stream_ref().token() 26 | } 27 | } 28 | 29 | // ----------------------------------------------------------------------------- 30 | // - Stream - 31 | // ----------------------------------------------------------------------------- 32 | /// When a [`Stream`] `react`s the inner evented reactor 33 | /// is marked as either readable and / or writable depending on the [`Ready`] state of the 34 | /// [`Event`]. 35 | /// 36 | /// It is likely that a Stream is used as part of a larger `Reactor`, and the `react` 37 | /// method is called not by the `System` but rather the container of the `Stream`: 38 | /// 39 | ///``` 40 | /// # use std::collections::HashMap; 41 | /// use sonr::prelude::*; 42 | /// use sonr::net::tcp::ReactiveTcpStream; 43 | /// 44 | /// type WriteBuffer = Vec; 45 | /// 46 | /// struct Connections { 47 | /// streams: HashMap 48 | /// } 49 | /// 50 | /// impl Connections { 51 | /// pub fn new() -> Self { 52 | /// Self { 53 | /// streams: HashMap::new(), 54 | /// } 55 | /// } 56 | /// } 57 | /// 58 | /// impl Reactor for Connections { 59 | /// type Input = ReactiveTcpStream; 60 | /// type Output = (); 61 | /// 62 | /// fn react(&mut self, reaction: Reaction) -> Reaction { 63 | /// use Reaction::*; 64 | /// match reaction { 65 | /// Value(stream) => { 66 | /// // New stream 67 | /// self.streams.insert(stream.token(), (stream, WriteBuffer::new())); 68 | /// Continue 69 | /// } 70 | /// Event(event) => { 71 | /// // Check if the event belongs to one of the streams, otherwise 72 | /// // pass the event to the next reactor 73 | /// if let Some((stream, write_buffer)) = self.streams.get_mut(&event.token()) { 74 | /// stream.react(event.into()); 75 | /// 76 | /// // Read 77 | /// while stream.readable() { 78 | /// // Read until the stream block 79 | /// // as the stream will not receive 80 | /// // a new read event until it blocks 81 | /// break 82 | /// } 83 | /// 84 | /// while stream.writable() && !write_buffer.is_empty() { 85 | /// // Write to the stream until there is nothing 86 | /// // left in the write buffer 87 | /// break 88 | /// } 89 | /// 90 | /// Continue 91 | /// } else { 92 | /// event.into() 93 | /// } 94 | /// } 95 | /// Continue => Continue, 96 | /// } 97 | /// } 98 | /// } 99 | /// # fn main() { 100 | /// # } 101 | ///``` 102 | /// 103 | /// [`Stream`]: struct.Stream.html 104 | /// [`Ready`]: ../../struct.Ready.html 105 | /// [`Event`]: ../../struct.Event.html 106 | pub struct Stream { 107 | inner: EventedReactor, 108 | } 109 | 110 | impl AsRef> for Stream { 111 | fn as_ref(&self) -> &Stream { 112 | &self 113 | } 114 | } 115 | 116 | impl Stream 117 | where 118 | T: Debug + Evented + Read + Write, 119 | { 120 | /// Consume the stream and return the underlying evented reactor 121 | pub fn into_inner(self) -> EventedReactor { 122 | self.inner 123 | } 124 | } 125 | 126 | impl Debug for Stream 127 | where 128 | T: Debug + Evented + Read + Write, 129 | { 130 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { 131 | f.debug_struct("Stream") 132 | .field("inner", &self.inner) 133 | .finish() 134 | } 135 | } 136 | 137 | impl From> for Stream { 138 | fn from(reactor: EventedReactor) -> Self { 139 | Self { inner: reactor } 140 | } 141 | } 142 | 143 | impl Stream { 144 | /// Create a new stream 145 | pub fn new(inner: T) -> Result { 146 | let inner = EventedReactor::new(inner, Ready::readable() | Ready::writable())?; 147 | Ok(Self { inner }) 148 | } 149 | 150 | /// The token used to track readiness of the underlying stream 151 | pub fn token(&self) -> Token { 152 | self.inner.token() 153 | } 154 | 155 | /// Is the underlying object readable? 156 | pub fn readable(&self) -> bool { 157 | self.inner.is_readable 158 | } 159 | 160 | /// Is the underlying object writable? 161 | pub fn writable(&self) -> bool { 162 | self.inner.is_writable 163 | } 164 | 165 | /// Reference the underlying object 166 | pub fn inner(&self) -> &T { 167 | self.inner.inner() 168 | } 169 | 170 | /// Mutable reference to the underlying object 171 | pub fn inner_mut(&mut self) -> &mut T { 172 | self.inner.inner_mut() 173 | } 174 | } 175 | 176 | impl Reactor for Stream { 177 | type Output = (); 178 | type Input = (); 179 | 180 | fn react(&mut self, reaction: Reaction) -> Reaction { 181 | if let Reaction::Event(event) = reaction { 182 | if event.token() != self.inner.token() { 183 | return reaction; 184 | } 185 | 186 | self.inner.is_readable |= event.readiness().is_readable(); 187 | self.inner.is_writable |= event.readiness().is_writable(); 188 | 189 | Reaction::Value(()) 190 | } else { 191 | reaction 192 | } 193 | } 194 | } 195 | 196 | impl Read for Stream { 197 | fn read(&mut self, buf: &mut [u8]) -> io::Result { 198 | self.inner.read(buf) 199 | } 200 | } 201 | 202 | impl Write for Stream { 203 | fn write(&mut self, buf: &[u8]) -> io::Result { 204 | self.inner.write(buf) 205 | } 206 | 207 | fn flush(&mut self) -> io::Result<()> { 208 | self.inner.flush() 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /src/system.rs: -------------------------------------------------------------------------------- 1 | //! The `System` handles polling events, registering evented reactors and token management. 2 | //! 3 | //! When [`init`] is called, the [`System`] is setup for the local thread. 4 | //! 5 | //! Once [`start`] is called with a reactor the system begins to poll [`Event`]s. 6 | //! 7 | //! When an [`Event`] becomes available the [`Reactor`]s [`react`] functions is called with 8 | //! [`Reaction::Event(event)`] and starts propagating the [`Reaction`]s. 9 | //! 10 | //! 11 | //! [`Event`]: ../struct.Event.html 12 | //! [`Token`]: ../struct.Token.html 13 | //! [`System`]: struct.System.html 14 | //! [`init`]: struct.System.html#method.init 15 | //! [`start`]: struct.System.html#method.start 16 | //! [`Reactor`]: ../reactor/trait.Reactor.html 17 | //! [`react`]: ../reactor/trait.Reactor.html#tymethod.react 18 | //! [`Reaction::Event(event)`]: ../reactor/enum.Reaction.html 19 | //! 20 | use std::cell::RefCell; 21 | 22 | use mio::{Evented, Events, Poll, Token, Ready, PollOpt}; 23 | 24 | use crate::PreVec; 25 | use crate::sync::signal::{SignalReceiver, SignalSender}; 26 | use crate::errors::Result; 27 | 28 | use super::reactor::{Reactor, EventedReactor, Reaction}; 29 | 30 | thread_local! { 31 | static CURRENT_SYSTEM: RefCell> = RefCell::new(None); 32 | } 33 | 34 | /// Specific event the [`System`] responds to 35 | /// NOTE: There should only be one [`System::init`] call per thread 36 | /// The System handles registration and pushes `Event`s to the reactors 37 | /// passed to [`System::start`]. 38 | /// 39 | /// [`System`]: struct.System.html 40 | /// [`System::start`]: struct.System.html#method.start 41 | /// [`System::init`]: struct.System.html#method.init 42 | #[derive(Debug)] 43 | pub enum SystemEvent { 44 | /// Stop the System 45 | Stop, 46 | } 47 | 48 | /// `System` is thread local and has to exist for each thread using `Reactors` that react to 49 | /// [`Reaction::Event(event)`]. 50 | /// There can only be **one** instance of a `System` per thread, and this instance is created by 51 | /// calling `System::init()`. 52 | /// 53 | /// [`System::init()`]: struct.System.html#method.init 54 | /// [`Reaction::Event(event)`]: ../reactor/enum.Reaction.html 55 | /// [`System::start()`]: struct.System.html#method.start 56 | pub struct System { 57 | reactors: PreVec<()>, 58 | poll: Poll, 59 | rx: SignalReceiver, 60 | } 61 | 62 | static SYSTEM_TOKEN: Token = Token(0); 63 | 64 | macro_rules! with_system { 65 | ($cu:ident, $x:block) => ( 66 | { 67 | CURRENT_SYSTEM.with(|cell| match *cell.borrow_mut() { 68 | Some(ref mut $cu) => { 69 | $x 70 | } 71 | None => panic!("System was not started") 72 | }) 73 | } 74 | ) 75 | } 76 | 77 | impl System { 78 | fn new() -> Result { 79 | let capacity = 100_000; 80 | let rx = SignalReceiver::unbounded(); 81 | let poll = Poll::new()?; 82 | 83 | let mut reactors = PreVec::with_capacity(capacity); 84 | reactors.insert(())?; // Reserve the first token as it's the SERVER_TOKEN 85 | 86 | poll.register( 87 | &rx, 88 | SYSTEM_TOKEN, 89 | Ready::readable(), 90 | PollOpt::edge() 91 | )?; 92 | 93 | Ok(Self { 94 | reactors, 95 | poll, 96 | rx, 97 | }) 98 | } 99 | 100 | /// Initialise the system for the current thread. 101 | /// Should only be called once per thread. 102 | pub fn init() -> Result> { 103 | CURRENT_SYSTEM.with(|cell| { 104 | let mut current = cell.borrow_mut(); 105 | if let Some(ref mut c) = *current { 106 | return Ok(c.rx.sender()); 107 | } 108 | let system = Self::new()?; 109 | let handle = system.rx.sender(); 110 | *current = Some(system); 111 | Ok(handle) 112 | }) 113 | } 114 | 115 | /// Register an `Evented` with the System. 116 | pub fn register(evented: &impl Evented, interest: Ready, token: Token) -> Result<()> { 117 | with_system! (current, { 118 | current.poll.register( 119 | evented, 120 | token, 121 | interest, 122 | PollOpt::edge() 123 | )?; 124 | Ok(()) 125 | }) 126 | } 127 | 128 | /// Reregister an evented reactor. 129 | pub fn reregister(evented: &EventedReactor) -> Result<()> { 130 | with_system! (current, { 131 | current.poll.reregister( 132 | evented.inner(), 133 | evented.token(), 134 | evented.interest(), 135 | PollOpt::edge() 136 | )?; 137 | Ok(()) 138 | }) 139 | } 140 | 141 | /// Start the event loop. 142 | /// This will run until `SystemEvent::Stop` is sent to the system's `SignalReceiver`. 143 | /// 144 | /// The `SignalReceiver` is returned from `System::init()`. 145 | pub fn start(mut reactor: R) -> Result<()> { 146 | let mut events = Events::with_capacity(1024); 147 | 148 | 'system: loop { 149 | with_system!(current, { current.poll.poll(&mut events, None) })?; 150 | 151 | for event in &events { 152 | if event.token() == SYSTEM_TOKEN { 153 | let sys_events = with_system!(current, { 154 | let mut sys_events = Vec::new(); 155 | if let Ok(sys_event) = current.rx.try_recv() { 156 | sys_events.push(sys_event); 157 | } 158 | sys_events 159 | }); 160 | 161 | for sys_event in sys_events { 162 | match sys_event { 163 | SystemEvent::Stop => break 'system, 164 | } 165 | } 166 | } else { 167 | let reaction = reactor.react(Reaction::Event(event)); 168 | 169 | if let Reaction::Value(_) = reaction { 170 | while let Reaction::Value(_) = reactor.react(Reaction::Continue) { } 171 | } 172 | } 173 | } 174 | } 175 | 176 | Ok(()) 177 | } 178 | 179 | /// The token can be registered with another reactor. 180 | /// This is called when an [`EventedReactor`] is dropped. 181 | /// 182 | /// [`EventedReactor`]: ../reactor/struct.EventedReactor.html 183 | pub fn free_token(token: Token) { 184 | let _ = with_system!(current, { current.reactors.remove(token.0); }); 185 | } 186 | 187 | /// Reserve a token 188 | pub fn reserve_token() -> Result { 189 | with_system!(current, { 190 | let token = current.reactors.insert(())?; 191 | Ok(Token(token)) 192 | }) 193 | } 194 | 195 | /// Send a system event to the current system. 196 | pub fn send(sys_event: SystemEvent) { 197 | let _ = with_system!(current, { current.rx.sender().send(sys_event) }); 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /src/sync/signal.rs: -------------------------------------------------------------------------------- 1 | //! Signals used to send data between threads. 2 | use std::io; 3 | use std::fmt::{self, Debug}; 4 | 5 | use crossbeam::channel::{Sender, Receiver, TrySendError}; 6 | use crossbeam::channel::{unbounded as channel, bounded}; 7 | use mio::{Poll, PollOpt, Registration, SetReadiness, Ready, Evented, Token}; 8 | 9 | use crate::reactor::{Reactor, Reaction, EventedReactor}; 10 | use crate::errors; 11 | 12 | use super::Capacity; 13 | 14 | 15 | // ----------------------------------------------------------------------------- 16 | // - Signal sender - 17 | // ----------------------------------------------------------------------------- 18 | /// Evented signal sender, used to send data between threads. 19 | /// A sender can not be created by it self, but has to exist as a result 20 | /// of a receiver. Thus a sender can only be created from a receiver. 21 | pub struct SignalSender { 22 | sender: Sender, 23 | set_readiness: SetReadiness, 24 | } 25 | 26 | impl SignalSender { 27 | fn new(sender: Sender, set_readiness: SetReadiness) -> Self { 28 | Self { 29 | sender, 30 | set_readiness, 31 | } 32 | } 33 | 34 | /// Send data to a receiver. 35 | pub fn send(&self, val: T) -> Result<(), TrySendError>{ 36 | let _ = self.set_readiness.set_readiness(Ready::readable()); 37 | self.sender.send(val)?; 38 | Ok(()) 39 | } 40 | } 41 | 42 | impl Clone for SignalSender { 43 | fn clone(&self) -> Self { 44 | SignalSender::new( 45 | self.sender.clone(), 46 | self.set_readiness.clone(), 47 | ) 48 | } 49 | } 50 | 51 | impl Debug for SignalSender { 52 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 53 | write!(f, "{:?}", self) 54 | } 55 | } 56 | 57 | 58 | // ----------------------------------------------------------------------------- 59 | // - Signal receiver - 60 | // ----------------------------------------------------------------------------- 61 | /// Evented receiver. 62 | pub struct SignalReceiver { 63 | receiver: Receiver, 64 | registration: Registration, 65 | 66 | set_readiness: SetReadiness, 67 | sender: Sender, 68 | } 69 | 70 | impl From for SignalReceiver { 71 | fn from(cap: Capacity) -> Self { 72 | match cap { 73 | Capacity::Unbounded => Self::unbounded(), 74 | Capacity::Bounded(cap) => Self::bounded(cap) 75 | } 76 | } 77 | } 78 | 79 | impl From<&Capacity> for SignalReceiver { 80 | fn from(cap: &Capacity) -> Self { 81 | match cap { 82 | Capacity::Unbounded => Self::unbounded(), 83 | Capacity::Bounded(cap) => Self::bounded(*cap) 84 | } 85 | } 86 | } 87 | 88 | impl SignalReceiver { 89 | /// Create an unbounded receiver 90 | pub fn unbounded() -> Self { 91 | let (sender, receiver) = channel(); 92 | Self::with_sender_receiver(sender, receiver) 93 | } 94 | 95 | /// Create a bounded receiver. 96 | /// Setting the capacity to zero means no data will be held in the 97 | /// queue and the sending thread will block until the data is picked up 98 | /// by this receiver. 99 | pub fn bounded(capacity: usize) -> Self { 100 | let (sender, receiver) = bounded(capacity); 101 | Self::with_sender_receiver(sender, receiver) 102 | } 103 | 104 | fn with_sender_receiver(sender: Sender, receiver: Receiver) -> Self { 105 | let (registration, set_readiness) = Registration::new2(); 106 | Self { 107 | receiver, 108 | registration, 109 | 110 | sender, 111 | set_readiness, 112 | } 113 | } 114 | 115 | /// Try to receive a value from the underlying channel 116 | pub fn try_recv(&self) -> errors::Result { 117 | let res = self.receiver.try_recv(); 118 | Ok(res?) 119 | } 120 | 121 | /// Create an instance of a sender. 122 | /// It's possible to create several senders for the same receiver. 123 | pub fn sender(&self) -> SignalSender { 124 | SignalSender { 125 | set_readiness: self.set_readiness.clone(), 126 | sender: self.sender.clone(), 127 | } 128 | } 129 | } 130 | 131 | 132 | 133 | // ----------------------------------------------------------------------------- 134 | // - Reactive signal receiver - 135 | // ----------------------------------------------------------------------------- 136 | /// React when new data is ready to be received 137 | /// 138 | ///```no_run 139 | /// # use std::thread; 140 | /// # use sonr::prelude::*; 141 | /// # use sonr::sync::signal::{SignalReceiver, ReactiveSignalReceiver, SignalSender}; 142 | /// # use sonr::sync::Capacity; 143 | /// 144 | /// # fn main() { 145 | /// let rx: SignalReceiver = SignalReceiver::unbounded(); 146 | /// let tx = rx.sender(); 147 | /// 148 | /// let handle = thread::spawn(move || { 149 | /// let handle = System::init().unwrap(); 150 | /// let rx = ReactiveSignalReceiver::new(rx).unwrap(); 151 | /// 152 | /// let run = rx.map(|val| { 153 | /// // Received value, signaling System 154 | /// // to stop 155 | /// handle.send(SystemEvent::Stop); 156 | /// }); 157 | /// 158 | /// System::start(run); 159 | /// }); 160 | /// 161 | /// tx.send(123); 162 | /// 163 | /// handle.join(); 164 | /// # } 165 | /// ``` 166 | /// 167 | pub struct ReactiveSignalReceiver { 168 | inner: EventedReactor>, 169 | } 170 | 171 | impl ReactiveSignalReceiver { 172 | /// Create a new signal receiver 173 | pub fn new(inner: SignalReceiver) -> errors::Result { 174 | Ok(Self { 175 | inner: EventedReactor::new(inner, Ready::readable())?, 176 | }) 177 | } 178 | 179 | /// Attempt to receive data. 180 | /// Should be called after the receiver reacts to an event. 181 | pub fn try_recv(&self) -> errors::Result { 182 | Ok(self.inner.inner().try_recv()?) 183 | } 184 | 185 | /// Get an instance of the [`Token`] used to register 186 | /// the receiver with the [`System`]. 187 | /// 188 | /// [`Token`]: ../../struct.Token.html 189 | /// [`System`]: ../../system/struct.System.html 190 | pub fn token(&self) -> Token { 191 | self.inner.token() 192 | } 193 | 194 | /// Create a signal sender for the underlying receiver. 195 | pub fn sender(&self) -> SignalSender { 196 | self.inner.inner().sender() 197 | } 198 | } 199 | 200 | impl Evented for SignalReceiver { 201 | fn register(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> { 202 | self.registration.register(poll, token, interest, opts) 203 | } 204 | 205 | fn reregister(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> { 206 | self.registration.reregister(poll, token, interest, opts) 207 | } 208 | 209 | fn deregister(&self, poll: &Poll) -> io::Result<()> { 210 | poll.deregister(&self.registration) 211 | } 212 | } 213 | 214 | impl Reactor for ReactiveSignalReceiver { 215 | type Output = T; 216 | type Input = (); 217 | 218 | fn react(&mut self, reaction: Reaction) -> Reaction { 219 | if let Reaction::Event(event) = reaction { 220 | if self.inner.token() == event.token() { 221 | if let Ok(val) = self.try_recv() { 222 | return Reaction::Value(val) 223 | } 224 | } else { 225 | return Reaction::Event(event); 226 | } 227 | } 228 | 229 | if let Reaction::Continue = reaction { 230 | if let Ok(val) = self.try_recv() { 231 | return Reaction::Value(val); 232 | } 233 | } 234 | 235 | match reaction { 236 | Reaction::Event(e) => Reaction::Event(e), 237 | Reaction::Continue => Reaction::Continue, 238 | Reaction::Value(_) => Reaction::Continue, 239 | } 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /src/reactor/combinators.rs: -------------------------------------------------------------------------------- 1 | //! Combine [`Reactor`]s creating new [`Reactor`]s. 2 | //! 3 | //! See each individual combinator for more information. 4 | use std::marker::PhantomData; 5 | 6 | use super::{Reaction, Reactor}; 7 | 8 | /// Chain two [`Reactor`]s together, making the output of the first 9 | /// reactor the input of the second. 10 | /// 11 | /// [`Reactor`]: ../trait.Reactor.html 12 | pub struct Chain 13 | where 14 | F: Reactor, 15 | T: Reactor, 16 | { 17 | from: F, 18 | to: T, 19 | } 20 | 21 | impl Chain 22 | where 23 | F: Reactor, 24 | T: Reactor, 25 | { 26 | /// Create a chain of two [`Reactors`]. 27 | /// 28 | /// [`Reactor`]: ../trait.Reactor.html 29 | pub fn new(from: F, to: T) -> Self { 30 | Self { from, to } 31 | } 32 | } 33 | 34 | impl Reactor for Chain 35 | where 36 | F: Reactor, 37 | T: Reactor, 38 | { 39 | type Input = F::Input; 40 | type Output = T::Output; 41 | 42 | fn react(&mut self, reaction: Reaction) -> Reaction { 43 | let mut r1 = self.from.react(reaction); 44 | loop { 45 | match r1 { 46 | Reaction::Event(_) => break self.to.react(r1), 47 | Reaction::Value(val) => { 48 | let _ = self.to.react(Reaction::Value(val)); 49 | r1 = self.from.react(Reaction::Continue); 50 | } 51 | Reaction::Continue => { 52 | if let Reaction::Continue = self.to.react(Reaction::Continue) { 53 | break Reaction::Continue; 54 | } 55 | } 56 | } 57 | } 58 | } 59 | } 60 | 61 | // ----------------------------------------------------------------------------- 62 | // - And two reactors - 63 | // ----------------------------------------------------------------------------- 64 | /// Use `and` to run more than one (evented) reactor in parallel. 65 | /// 66 | /// Since the output of a tcp listener is a stream and a socket address, it would 67 | /// not be possible to chain two tcp listeners together. 68 | /// It is also not possible to call `System::start` twice in the same thread. 69 | /// 70 | /// To run two tcp listeners at the same time use `and`: 71 | /// 72 | /// ``` 73 | /// # use sonr::prelude::*; 74 | /// # use sonr::reactor::producers::Mono; 75 | /// # use sonr::errors::Result; 76 | /// 77 | /// fn main() -> Result<()> { 78 | /// let sys_sig = System::init()?; 79 | /// 80 | /// let reactor_a = Mono::new(1u8)?.map(|_| sys_sig.send(SystemEvent::Stop)); 81 | /// let reactor_b = Mono::new(2u8)?.map(|_| sys_sig.send(SystemEvent::Stop)); 82 | /// 83 | /// System::start(reactor_a.and(reactor_b)); 84 | /// # Ok(()) 85 | /// } 86 | /// ``` 87 | /// 88 | /// This means a `Reaction::Event(event)` from the `System` will be passed on to both 89 | /// listeners. 90 | pub struct And 91 | where 92 | T: Reactor, 93 | U: Reactor, 94 | { 95 | first: T, 96 | second: U, 97 | } 98 | 99 | impl And 100 | where 101 | T: Reactor, 102 | U: Reactor, 103 | { 104 | /// Create a new `And` from two reactors. 105 | pub fn new(first: T, second: U) -> Self { 106 | Self { first, second } 107 | } 108 | } 109 | 110 | impl Reactor for And 111 | where 112 | T: Reactor, 113 | U: Reactor, 114 | { 115 | type Output = (); 116 | type Input = (); 117 | 118 | fn react(&mut self, reaction: Reaction) -> Reaction { 119 | match reaction { 120 | Reaction::Event(event) => { 121 | self.first.react(Reaction::Event(event)); 122 | self.second.react(Reaction::Event(event)); 123 | Reaction::Event(event) 124 | } 125 | _ => Reaction::Continue, 126 | } 127 | } 128 | } 129 | 130 | // ----------------------------------------------------------------------------- 131 | // - Map - 132 | // ----------------------------------------------------------------------------- 133 | /// Map will capture the `Reaction::Value(val)` returned by `react` and apply 134 | /// the provided closure on the value. 135 | /// 136 | /// The returned value from the map is the new `Output` of the Reactor. 137 | /// 138 | ///``` 139 | /// # use std::time::Duration; 140 | /// # use std::net::SocketAddr; 141 | /// # use std::thread; 142 | /// # use std::net::TcpStream as StdStream; 143 | /// # use sonr::prelude::*; 144 | /// # use sonr::errors::Result; 145 | /// use sonr::net::tcp::{ReactiveTcpListener, TcpStream}; 146 | /// 147 | /// fn main() -> Result<()> { 148 | /// let system_signals = System::init()?; 149 | /// 150 | /// let listener = ReactiveTcpListener::bind("127.0.0.1:5557")?; 151 | /// let run = listener.map(|(strm, addr)| { 152 | /// // Return the tcp stream, ignoring the SocketAddr 153 | /// strm 154 | /// }); 155 | /// # thread::spawn(move || { 156 | /// # thread::sleep(Duration::from_millis(100)); 157 | /// # StdStream::connect("127.0.0.1:5557"); 158 | /// # system_signals.send(SystemEvent::Stop); 159 | /// # }); 160 | /// 161 | /// System::start(run)?; 162 | /// Ok(()) 163 | /// } 164 | /// ``` 165 | pub struct Map { 166 | source: S, 167 | callback: F, 168 | _p: PhantomData, 169 | } 170 | 171 | impl Map { 172 | /// Create a new map from a reactor and a closure. 173 | pub fn new(source: S, callback: F) -> Self { 174 | Self { 175 | source, 176 | callback, 177 | _p: PhantomData, 178 | } 179 | } 180 | } 181 | 182 | impl Reactor for Map 183 | where 184 | S: Reactor, 185 | F: FnMut(S::Output) -> T, 186 | { 187 | type Output = T; 188 | type Input = S::Input; 189 | 190 | fn react(&mut self, reaction: Reaction) -> Reaction { 191 | let reaction = self.source.react(reaction); 192 | match reaction { 193 | Reaction::Value(val) => Reaction::Value((self.callback)(val)), 194 | Reaction::Event(event) => Reaction::Event(event), 195 | Reaction::Continue => Reaction::Continue, 196 | } 197 | } 198 | } 199 | 200 | // ----------------------------------------------------------------------------- 201 | // - Or - 202 | // ----------------------------------------------------------------------------- 203 | ///``` 204 | /// # use sonr::prelude::*; 205 | /// # use sonr::errors::Result; 206 | /// use sonr::reactor::consumers::Consume; 207 | /// use sonr::reactor::producers::Mono; 208 | /// use sonr::reactor::Either; 209 | /// 210 | /// fn main() -> Result<()> { 211 | /// let system_sig = System::init()?; 212 | /// let producer = Mono::new(1u32)? 213 | /// .map(|val| { 214 | /// if val == 1 { 215 | /// Either::A(val) 216 | /// } else { 217 | /// Either::B(val) 218 | /// } 219 | /// }); 220 | /// 221 | /// let reactor_a = Consume::new(); 222 | /// let reactor_b = Consume::new(); 223 | /// let reactor = reactor_a.or(reactor_b) 224 | /// .map(|_| { 225 | /// system_sig.send(SystemEvent::Stop); 226 | /// }); 227 | /// 228 | /// let run = producer.chain(reactor); 229 | /// 230 | /// System::start(run)?; 231 | /// Ok(()) 232 | /// } 233 | /// ``` 234 | pub struct Or { 235 | first: T, 236 | second: U, 237 | } 238 | 239 | impl Or { 240 | pub(crate) fn new(first: T, second: U) -> Self { 241 | Self { first, second } 242 | } 243 | } 244 | 245 | impl, U: Reactor, O> Reactor for Or { 246 | type Input = Either; 247 | type Output = O; 248 | 249 | fn react(&mut self, reaction: Reaction) -> Reaction { 250 | use Reaction::*; 251 | match reaction { 252 | Value(val) => match val { 253 | Either::A(val) => self.first.react(Value(val)), 254 | Either::B(val) => self.second.react(Value(val)), 255 | }, 256 | Event(event) => { 257 | self.first.react(Event(event)); 258 | self.second.react(Event(event)); 259 | event.into() 260 | } 261 | Continue => Continue, 262 | } 263 | } 264 | } 265 | 266 | /// Either A or B 267 | /// Used as output when `a_reactor.or(another_reactor)` 268 | pub enum Either { 269 | /// A branch 270 | A(T), 271 | /// B branch 272 | B(U), 273 | } 274 | -------------------------------------------------------------------------------- /src/sync/queue.rs: -------------------------------------------------------------------------------- 1 | //! Reactive queue / dequeue 2 | use std::io; 3 | 4 | use crossbeam::deque::{Worker, Stealer, Steal}; 5 | use mio::{Poll, Evented, Ready, PollOpt, Token}; 6 | 7 | use crate::sync::signal::{SignalReceiver, SignalSender}; 8 | use crate::reactor::{Reactor, EventedReactor, Reaction}; 9 | use crate::errors::Result; 10 | 11 | use super::Capacity; 12 | 13 | // ----------------------------------------------------------------------------- 14 | // - Reactive queue - 15 | // ----------------------------------------------------------------------------- 16 | /// A reactive work stealing queue. 17 | /// 18 | /// Since the queue can be unbounded or bounded it's possible to use a bounded queue 19 | /// to create back pressure. 20 | /// 21 | /// An unbounded queue will push data as soon as it reacts with a `Reaction::Value`, 22 | /// however with a bounded queue the queue can not continue to react until the value has been 23 | /// consumed by the receiving end. 24 | /// 25 | /// ``` 26 | /// # use std::thread; 27 | /// # use std::time::Duration; 28 | /// # use std::net::TcpStream as StdStream; 29 | /// # use sonr::prelude::*; 30 | /// # use sonr::errors::Result; 31 | /// use sonr::sync::signal::SignalSender; 32 | /// use sonr::sync::queue::{ReactiveQueue, ReactiveDeque}; 33 | /// use sonr::net::tcp::{ReactiveTcpListener, TcpStream}; 34 | /// 35 | /// fn main() -> Result<()> { 36 | /// let system_tx = System::init()?; 37 | /// 38 | /// let listener = ReactiveTcpListener::bind("127.0.0.1:5556")? 39 | /// .map(|(s, _)| { 40 | /// // Put a system tx and the stream in the queue 41 | /// (system_tx.clone(), s) 42 | /// }); 43 | /// 44 | /// let mut queue = ReactiveQueue::bounded(1); 45 | /// // Note the deque created here is not a ReactiveDeque but rather 46 | /// // a Deque, as a ReactiveDeque can not be created in one thread 47 | /// // and sent to another 48 | /// let deque = queue.deque(); 49 | /// 50 | /// # thread::spawn(move || { 51 | /// # thread::sleep(Duration::from_millis(100)); 52 | /// # StdStream::connect("127.0.0.1:5556"); 53 | /// # }); 54 | /// thread::spawn(move || -> Result<()> { 55 | /// let system_tx = System::init()?; 56 | /// let run = ReactiveDeque::new(deque)? 57 | /// .map(|(tx, stream): (SignalSender, _)| { 58 | /// tx.send(SystemEvent::Stop); 59 | /// system_tx.send(SystemEvent::Stop); 60 | /// }); 61 | /// System::start(run)?; 62 | /// Ok(()) 63 | /// }); 64 | /// 65 | /// let run = listener.chain(queue); 66 | /// 67 | /// System::start(run)?; 68 | /// Ok(()) 69 | /// } 70 | /// ``` 71 | pub struct ReactiveQueue { 72 | inner: Queue, 73 | } 74 | 75 | impl ReactiveQueue { 76 | /// Create an unbounded reactive queue 77 | pub fn unbounded() -> Self { 78 | Self { 79 | inner: Queue::unbounded(), 80 | } 81 | } 82 | 83 | /// Create an bounded reactive queue. 84 | /// Setting the capacity to zero means no data will be held in the 85 | /// queue and the current thread will block until the data is picked up 86 | /// at the other end. 87 | pub fn bounded(capacity: usize) -> Self { 88 | Self { 89 | inner: Queue::bounded(capacity), 90 | } 91 | } 92 | 93 | /// Push a value onto the queue 94 | pub fn push(&self, val: T) { 95 | self.inner.push(val); 96 | } 97 | 98 | /// Create an instance of a [`Dequeue`]. 99 | /// A [`Dequeue`] is not as useful in it self but 100 | /// rather the underlying deque of a [`ReactiveDeque`]. 101 | /// 102 | /// [`Dequeu`]: struct.Deque.html 103 | /// [`ReactiveDeque`]: struct.ReactiveDeque.html 104 | pub fn deque(&mut self) -> Dequeue { 105 | self.inner.deque() 106 | } 107 | } 108 | 109 | impl Reactor for ReactiveQueue { 110 | type Output = (); 111 | type Input = T; 112 | 113 | fn react(&mut self, reaction: Reaction) -> Reaction { 114 | if let Reaction::Value(value) = reaction { 115 | self.push(value); 116 | Reaction::Value(()) 117 | } else { 118 | Reaction::Continue 119 | } 120 | } 121 | } 122 | 123 | 124 | // ----------------------------------------------------------------------------- 125 | // - Work-stealing Queue - 126 | // ----------------------------------------------------------------------------- 127 | /// An evented work stealing queue. 128 | pub struct Queue { 129 | worker: Worker, 130 | inner_stealer: Stealer, 131 | publishers: Vec>, 132 | capacity: Capacity, 133 | } 134 | 135 | impl Queue { 136 | fn new_with_capacity(capacity: Capacity) -> Self { 137 | let worker = Worker::new_lifo(); 138 | let inner_stealer = worker.stealer(); 139 | 140 | Self { 141 | worker, 142 | inner_stealer, 143 | publishers: Vec::new(), 144 | capacity, 145 | } 146 | } 147 | 148 | /// Create an unbounded queue 149 | pub fn unbounded() -> Self { 150 | Self::new_with_capacity(Capacity::Unbounded) 151 | } 152 | 153 | /// Create a bounded queue. 154 | /// Setting the capacity to zero means no data will be held in the 155 | /// queue and the current thread will block until the data is picked up 156 | /// at the other end. 157 | pub fn bounded(cap: usize) -> Self { 158 | Self::new_with_capacity(Capacity::Bounded(cap)) 159 | } 160 | 161 | /// Push a value onto the queue 162 | pub fn push(&self, val: T) { 163 | self.worker.push(val); 164 | // Notify all 165 | self.publishers.iter().for_each(|p| { 166 | let _ = p.send(()); 167 | }); 168 | } 169 | 170 | /// Create an instance of a [`Dequeu`]. 171 | /// 172 | /// [`Dequeu`]: struct.Deque.html 173 | pub fn deque(&mut self) -> Dequeue { 174 | let stealer = self.inner_stealer.clone(); 175 | let subscriber = match self.capacity { 176 | Capacity::Unbounded => Dequeue::unbounded(stealer), 177 | Capacity::Bounded(cap) => Dequeue::bounded(stealer, cap) 178 | }; 179 | self.publishers.push(subscriber.sender()); 180 | subscriber 181 | } 182 | } 183 | 184 | // ----------------------------------------------------------------------------- 185 | // - Reactive dequeue - 186 | // ----------------------------------------------------------------------------- 187 | /// A reactive dequeue. 188 | pub struct ReactiveDeque { 189 | inner: EventedReactor>, 190 | } 191 | 192 | impl ReactiveDeque { 193 | /// Create a new reactive dequeue fro man existing [`Dequeue`] 194 | /// 195 | /// [`Dequeue`]: struct.Dequeue.html 196 | pub fn new(deq: Dequeue) -> Result { 197 | Ok(Self { 198 | inner: EventedReactor::new(deq, Ready::readable())?, 199 | }) 200 | } 201 | 202 | fn steal(&self) -> Reaction { 203 | loop { 204 | match self.inner.inner().steal() { 205 | Steal::Retry => continue, 206 | Steal::Success(val) => break Reaction::Value(val), 207 | Steal::Empty => break Reaction::Continue, 208 | } 209 | } 210 | } 211 | } 212 | 213 | impl Reactor for ReactiveDeque { 214 | type Output = T; 215 | type Input = (); 216 | 217 | fn react(&mut self, reaction: Reaction) -> Reaction { 218 | match reaction { 219 | Reaction::Event(event) => { 220 | if event.token() != self.inner.token() { 221 | return Reaction::Event(event); 222 | } 223 | self.steal() 224 | } 225 | Reaction::Value(_) => Reaction::Continue, 226 | Reaction::Continue => self.steal(), 227 | } 228 | } 229 | } 230 | 231 | // ----------------------------------------------------------------------------- 232 | // - Dequeue - 233 | // ----------------------------------------------------------------------------- 234 | /// An evented work stealing dequeue 235 | pub struct Dequeue { 236 | signal: SignalReceiver<()>, 237 | stealer: Stealer, 238 | } 239 | 240 | impl Dequeue { 241 | /// Create a bounded dequeue. 242 | /// Setting the capacity to zero means no data will be held in the 243 | /// queue and the publishing thread will blocked until the data is picked up 244 | /// by the dequeue. 245 | pub fn bounded(stealer: Stealer, capacity: usize) -> Self { 246 | let signal = SignalReceiver::bounded(capacity); 247 | 248 | Self { 249 | signal, 250 | stealer, 251 | } 252 | } 253 | 254 | /// Create an unbounded dequeue 255 | pub fn unbounded(stealer: Stealer) -> Self { 256 | let signal = SignalReceiver::unbounded(); 257 | 258 | Self { 259 | signal, 260 | stealer, 261 | } 262 | } 263 | 264 | /// Get the signal sender that notifies the dequeue of 265 | /// possible new data in the queue. 266 | pub fn sender(&self) -> SignalSender<()> { 267 | self.signal.sender() 268 | } 269 | 270 | /// Attempt to steal data 271 | pub fn steal(&self) -> Steal { 272 | match self.signal.try_recv() { 273 | Ok(()) => {}, 274 | Err(_e) => { /* dbg!(e); */ } 275 | } 276 | self.stealer.steal() 277 | } 278 | } 279 | 280 | impl Evented for Dequeue { 281 | fn register(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> { 282 | poll.register( 283 | &self.signal, 284 | token, 285 | interest, 286 | opts 287 | ) 288 | } 289 | 290 | fn reregister(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> { 291 | poll.reregister( 292 | &self.signal, 293 | token, 294 | interest, 295 | opts 296 | ) 297 | } 298 | 299 | fn deregister(&self, poll: &Poll) -> io::Result<()> { 300 | poll.deregister(&self.signal) 301 | } 302 | } 303 | -------------------------------------------------------------------------------- /src/reactor/mod.rs: -------------------------------------------------------------------------------- 1 | //! Reactors are the heart of Sonr and work by pushing data down a chain of reactors. 2 | //! 3 | //!```no_run 4 | //! use std::io::Write; 5 | //! use std::thread; 6 | //! use sonr::prelude::*; 7 | //! use sonr::errors::Result; 8 | //! use sonr::sync::queue::{ReactiveQueue, ReactiveDeque}; 9 | //! use sonr::net::tcp::{ReactiveTcpListener, TcpStream, ReactiveTcpStream}; 10 | //! 11 | //! // ----------------------------------------------------------------------------- 12 | //! // - Writer - 13 | //! // Write "bye" and drop the connection 14 | //! // ----------------------------------------------------------------------------- 15 | //! struct Writer; 16 | //! 17 | //! impl Reactor for Writer { 18 | //! type Input = TcpStream; 19 | //! type Output = (); 20 | //! 21 | //! fn react(&mut self, reaction: Reaction) -> Reaction { 22 | //! use Reaction::*; 23 | //! match reaction { 24 | //! Value(mut stream) => { 25 | //! stream.write(b"bye\n"); 26 | //! Continue 27 | //! } 28 | //! Event(ev) => Continue, 29 | //! Continue => Continue, 30 | //! } 31 | //! } 32 | //! } 33 | //! 34 | //! fn main() -> Result<()> { 35 | //! System::init()?; 36 | //! 37 | //! // Listen for incoming connections 38 | //! let listener = ReactiveTcpListener::bind("127.0.0.1:8000")?.map(|(s, _)| s); 39 | //! // Connection queue for connections to be sent to another thread. 40 | //! let mut queue = ReactiveQueue::unbounded(); 41 | //! 42 | //! for _ in 0..4 { 43 | //! let deque = queue.deque(); 44 | //! thread::spawn(move || -> Result<()> { 45 | //! System::init()?; 46 | //! let deque = ReactiveDeque::new(deque)?; 47 | //! let writer = Writer; 48 | //! let run = deque.chain(writer); 49 | //! System::start(run)?; 50 | //! Ok(()) 51 | //! }); 52 | //! } 53 | //! 54 | //! let run = listener.chain(queue); 55 | //! System::start(run)?; 56 | //! Ok(()) 57 | //! } 58 | //! ``` 59 | //! 60 | //! 61 | use mio::{Event, Evented, Ready, Token}; 62 | use std::fmt::{self, Debug, Formatter}; 63 | use std::io::{self, ErrorKind::WouldBlock, Read, Write}; 64 | use std::marker::PhantomData; 65 | 66 | use super::system::System; 67 | use crate::errors::Result; 68 | 69 | mod combinators; 70 | pub mod consumers; 71 | pub mod producers; 72 | 73 | pub use combinators::{And, Chain, Either, Map, Or}; 74 | 75 | /// Input / Output of a [`Reactor`]. 76 | /// 77 | /// [`Reactor`]: trait.Reactor.html 78 | pub enum Reaction { 79 | /// Continue 80 | Continue, 81 | 82 | /// A Mio event. 83 | Event(Event), 84 | 85 | /// Value 86 | Value(T), 87 | } 88 | 89 | impl From for Reaction { 90 | fn from(event: Event) -> Reaction { 91 | Reaction::Event(event) 92 | } 93 | } 94 | 95 | impl Debug for Reaction { 96 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 97 | match &self { 98 | Reaction::Continue => write!(f, "Reaction::Continue"), 99 | Reaction::Event(event) => write!(f, "Reaction::Event({:?})", event), 100 | Reaction::Value(val) => write!(f, "Reaction::Value({:?})", val), 101 | } 102 | } 103 | } 104 | 105 | /// A reactor reacts to a [`Reaction`] and returns a [`Reaction`]. 106 | /// 107 | /// With the `Output` type of one reactor being the same type as `Input` of another it's possible to chain these 108 | /// two reactors together. 109 | /// 110 | /// [`Reaction`]: enum.Reaction.html 111 | pub trait Reactor: Sized { 112 | /// The output passed to the next reactor in the chain. 113 | type Output; 114 | 115 | /// Expected input type from the previous reactor in the chain. 116 | type Input; 117 | 118 | /// The generated output is passed as the input to the 119 | /// next reactor in the chain. 120 | /// 121 | /// `react` is called repeatedly until the reaction returns 122 | /// `Reaction::Continue` 123 | fn react(&mut self, reaction: Reaction) -> Reaction; 124 | 125 | /// Chain two reactors together. 126 | /// The output of the first reactor is the input of the second reactor. 127 | fn chain(self, to: T) -> Chain { 128 | Chain::new(self, to) 129 | } 130 | 131 | /// Run two reactors independent of each other. 132 | /// ```no_run 133 | /// # use sonr::reactor::Reactor; 134 | /// # use sonr::errors::Result; 135 | /// use sonr::system::System; 136 | /// use sonr::net::tcp::ReactiveTcpListener; 137 | /// 138 | /// fn main() -> Result<()> { 139 | /// System::init(); 140 | /// let first_listener = ReactiveTcpListener::bind("127.0.0.1:5000")?; 141 | /// let second_listener = ReactiveTcpListener::bind("127.0.0.1:5001")?; 142 | /// let server = first_listener.and(second_listener); 143 | /// System::start(server); 144 | /// # Ok(()) 145 | /// } 146 | /// ``` 147 | fn and(self, second: C) -> And { 148 | And::new(self, second) 149 | } 150 | 151 | /// Capture the output of a reactor in a closure. 152 | /// ```no_run 153 | /// // Create a listener, print the address every time 154 | /// // the listener accepts a new connection, then push that 155 | /// // connection onto a queue. 156 | /// # use sonr::net::tcp; 157 | /// # use sonr::sync::queue::ReactiveQueue; 158 | /// # use sonr::errors::Result; 159 | /// # use sonr::prelude::*; 160 | /// # fn main() -> Result<()> { 161 | /// System::init(); 162 | /// let listener = tcp::ReactiveTcpListener::bind("127.0.0.1:5000")?; 163 | /// let queue = ReactiveQueue::unbounded(); 164 | /// let server = listener.map(|(stream, addr)| { 165 | /// stream 166 | /// }).chain(queue); 167 | /// System::start(server); 168 | /// # Ok(()) 169 | /// # } 170 | /// ``` 171 | fn map(self, callback: F) -> Map { 172 | Map::new(self, callback) 173 | } 174 | 175 | /// Pass the output from a reactor into one of two 176 | /// reactors depending on the output. 177 | /// Note that both `Reactor`s in an `or` are required 178 | /// to have the same output, and it's only possible to `chain` 179 | /// two `or`ed reactors if the reactor that does the chaining outputs 180 | /// `Either`. 181 | /// 182 | ///``` 183 | /// # use sonr::prelude::*; 184 | /// # use sonr::errors::Result; 185 | /// use sonr::reactor::consumers::Consume; 186 | /// use sonr::reactor::producers::Mono; 187 | /// use sonr::reactor::Either; 188 | /// 189 | /// fn main() -> Result<()> { 190 | /// let system_sig = System::init()?; 191 | /// let producer = Mono::new(1u32)? 192 | /// .map(|val| { 193 | /// if val == 1 { 194 | /// Either::A(val) 195 | /// } else { 196 | /// Either::B(val) 197 | /// } 198 | /// }); 199 | /// 200 | /// let reactor_a = Consume::new(); 201 | /// let reactor_b = Consume::new(); 202 | /// let reactor = reactor_a.or(reactor_b) 203 | /// .map(|_| { 204 | /// system_sig.send(SystemEvent::Stop); 205 | /// }); 206 | /// 207 | /// let run = producer.chain(reactor); 208 | /// 209 | /// System::start(run)?; 210 | /// Ok(()) 211 | /// } 212 | /// ``` 213 | fn or(self, second: T) -> Or { 214 | Or::new(self, second) 215 | } 216 | } 217 | 218 | // ----------------------------------------------------------------------------- 219 | // - An evented Reactor - 220 | // ----------------------------------------------------------------------------- 221 | /// The `EventedReactor` is driven by the [`System`]. 222 | /// 223 | /// An `EventedReactor` can not be sent between threads as it's bound to the 224 | /// System it was registered with. 225 | /// 226 | /// When an `EventedReactor` is created it's automatically registered with the [`System`], 227 | /// and when it dropps the [`Token`] registered with the `EventedReactor` is freed 228 | /// to be reused with another `EventedReactor`. 229 | /// 230 | /// The `EventedReactor` does not implement [`Reactor`] by it self, 231 | /// but rather acts as a building block when creating a Reactor that should 232 | /// also be evented. 233 | /// 234 | /// The [`Stream`] is an example of this. 235 | /// 236 | /// [`Reactor`]: trait.Reactor.html 237 | /// [`Stream`]: ../net/stream/struct.Stream.html 238 | /// [`System`]: ../system/struct.System.html 239 | /// [`Token`]: ../struct.Token.html 240 | pub struct EventedReactor { 241 | inner: E, 242 | token: Token, 243 | interest: Ready, 244 | pub(crate) is_readable: bool, 245 | pub(crate) is_writable: bool, 246 | _not_send: PhantomData<*const ()>, // Make the evented reactor !Send 247 | } 248 | 249 | impl Debug for EventedReactor 250 | where 251 | E: Debug + Evented, 252 | { 253 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { 254 | f.debug_struct("EventedReactor") 255 | .field("inner", &self.inner) 256 | .field("token", &self.token) 257 | .field("interest", &self.interest) 258 | .field("is_readable", &self.is_readable) 259 | .field("is_writable", &self.is_writable) 260 | .finish() 261 | } 262 | } 263 | 264 | impl EventedReactor { 265 | /// Create a new instance of an `EventedReactor`. 266 | pub fn new(inner: E, interest: Ready) -> Result { 267 | let token = System::reserve_token()?; 268 | System::register(&inner, interest, token)?; 269 | 270 | Ok(Self { 271 | inner, 272 | token, 273 | interest, 274 | is_readable: false, 275 | is_writable: false, 276 | _not_send: PhantomData, 277 | }) 278 | } 279 | 280 | /// Reference to the underlying evented type 281 | pub fn inner(&self) -> &E { 282 | &self.inner 283 | } 284 | 285 | /// Mutable reference to the underlying evented type 286 | pub fn inner_mut(&mut self) -> &mut E { 287 | &mut self.inner 288 | } 289 | 290 | /// Return the `Token` used to register the inner type with 291 | /// poll. 292 | pub fn token(&self) -> Token { 293 | self.token 294 | } 295 | 296 | /// Return the interests of the reactor, usually readable and/or writable. 297 | pub fn interest(&self) -> Ready { 298 | self.interest 299 | } 300 | } 301 | 302 | impl Read for EventedReactor { 303 | fn read(&mut self, buf: &mut [u8]) -> io::Result { 304 | let res = self.inner_mut().read(buf); 305 | 306 | match res { 307 | Err(ref e) if e.kind() == WouldBlock => { 308 | self.is_readable = false; 309 | let res = System::reregister(&self); 310 | match res { 311 | Ok(()) => (), 312 | Err(e) => { 313 | return Err(io::Error::new( 314 | io::ErrorKind::Other, 315 | format!("failed to reregister evented: {:?}", e), 316 | )); 317 | } 318 | } 319 | } 320 | Err(_) => self.is_readable = false, 321 | Ok(0) => self.is_readable = false, 322 | _ => {} 323 | } 324 | 325 | res 326 | } 327 | } 328 | 329 | impl Write for EventedReactor { 330 | fn write(&mut self, buf: &[u8]) -> io::Result { 331 | let res = self.inner_mut().write(buf); 332 | 333 | match res { 334 | Err(ref e) if e.kind() == WouldBlock => { 335 | self.is_writable = false; 336 | let res = System::reregister(&self); 337 | match res { 338 | Ok(()) => (), 339 | Err(e) => { 340 | return Err(io::Error::new( 341 | io::ErrorKind::Other, 342 | format!("failed to reregister evented: {:?}", e), 343 | )); 344 | } 345 | } 346 | } 347 | Err(_) => self.is_writable = false, 348 | _ => {} 349 | } 350 | 351 | res 352 | } 353 | 354 | fn flush(&mut self) -> io::Result<()> { 355 | self.inner_mut().flush() 356 | } 357 | } 358 | 359 | impl Drop for EventedReactor { 360 | fn drop(&mut self) { 361 | System::free_token(self.token()); 362 | } 363 | } 364 | -------------------------------------------------------------------------------- /src/prevec.rs: -------------------------------------------------------------------------------- 1 | use std::mem::replace; 2 | use std::ops::{Index, IndexMut}; 3 | 4 | use crate::errors::{Result, Error}; 5 | 6 | enum Entry { 7 | Empty(usize), 8 | Occupied(T) 9 | } 10 | 11 | // ----------------------------------------------------------------------------- 12 | // - PreVec - 13 | // ----------------------------------------------------------------------------- 14 | /// `PreVec`: a collection that allows inserts at a specific index with an optional offsets. 15 | /// A `PreVec` can be created with either [`capacity`] or [`capacity_with_offset`]. 16 | /// 17 | /// This is useful with multiple collections where each index has to be unique, e.g having 18 | /// two collections of connections driven by the same [`Poll`] instance where the index represents 19 | /// the connection token. 20 | /// 21 | /// [`capacity`]: struct.PreVec.html#method.with_capacity 22 | /// [`capacity_with_offset`]: struct.PreVec.html#method.with_capacity_and_offset 23 | /// [`prevent_growth`]: struct.PreVec.html#method.prevent_growth 24 | /// [`poll`]: ../struct.Poll.html 25 | /// 26 | /// By default the collection can grow; To prevent overlap with another collection 27 | /// call [`prevent_growth`]. 28 | /// This will result in an error if an insert occurrs outside the allocated space. 29 | /// 30 | /// # Example 31 | /// 32 | /// Creating two PreVecs sharing a unique range: 33 | /// ``` 34 | /// use sonr::PreVec; 35 | /// 36 | /// let mut lower = PreVec::with_capacity(1000); 37 | /// let mut upper = PreVec::with_capacity_and_offset(1000, 1000); 38 | /// 39 | /// let lower_index = lower.insert("foo").unwrap(); 40 | /// let upper_index = upper.insert("bar").unwrap(); 41 | /// 42 | /// assert_eq!(lower_index, 0); 43 | /// assert_eq!(upper_index, 1000); 44 | /// ``` 45 | /// 46 | /// Note that setting the offset to `std::usize::MAX` would mean only one 47 | /// element can be stored in the PreVec, and any attempt to insert more 48 | /// would result in an error 49 | pub struct PreVec { 50 | inner: Vec>, 51 | capacity: usize, 52 | next: usize, 53 | offset: usize, 54 | length: usize, 55 | can_grow: bool, 56 | } 57 | 58 | 59 | // ----------------------------------------------------------------------------- 60 | // - Impl PreVec - 61 | // ----------------------------------------------------------------------------- 62 | impl PreVec { 63 | /// Create a `PreVec` with a set capacity. 64 | /// Inserting above capacity will either allocate more space 65 | /// or return an error depending on wheter `enable_growth` or `prevent_growth` is called, 66 | /// 67 | /// By default growth is enabled. 68 | /// 69 | /// # Example 70 | /// 71 | /// ``` 72 | /// # use sonr::PreVec; 73 | /// let v = PreVec::::with_capacity(10); 74 | /// assert_eq!(v.capacity(), 10); 75 | /// ``` 76 | pub fn with_capacity(cap: usize) -> Self { 77 | Self { 78 | inner: Vec::with_capacity(cap), 79 | capacity: cap, 80 | next: 0, 81 | offset: 0, 82 | length: 0, 83 | can_grow: true, 84 | } 85 | } 86 | 87 | /// Create a `PreVec` with a set capacity and offset. 88 | /// 89 | /// # Example 90 | /// 91 | /// ``` 92 | /// # use sonr::PreVec; 93 | /// let mut v = PreVec::::with_capacity_and_offset(10, 5); 94 | /// assert_eq!(v.offset(), 5); 95 | /// 96 | /// let index = v.insert(5).unwrap(); 97 | /// assert_eq!(index, 5); 98 | /// ``` 99 | pub fn with_capacity_and_offset(cap: usize, offset: usize) -> Self { 100 | let mut p = Self::with_capacity(cap); 101 | p.set_offset(offset); 102 | p 103 | } 104 | 105 | /// Return the capacity 106 | pub fn capacity(&self) -> usize { 107 | self.capacity 108 | } 109 | 110 | /// Return the offset 111 | pub fn offset(&self) -> usize { 112 | self.offset 113 | } 114 | 115 | /// Prevent inserting above the capacity. 116 | pub fn prevent_growth(&mut self) { 117 | self.can_grow = false; 118 | } 119 | 120 | /// Enable the collection to grow and allocate more space. 121 | pub fn enable_growth(&mut self) { 122 | self.can_grow = true; 123 | } 124 | 125 | /// Check if the index is within the range of the collection 126 | /// (between capacity and offset) 127 | pub fn in_range(&self, index: usize) -> bool { 128 | index >= self.offset && index < self.capacity 129 | } 130 | 131 | /// Set the offset of the collection. 132 | pub fn set_offset(&mut self, new_offset: usize) { 133 | self.offset = new_offset; 134 | } 135 | 136 | /// Get an entry at a specific index 137 | /// 138 | /// # Example 139 | /// 140 | /// ``` 141 | /// # use sonr::PreVec; 142 | /// let mut v = PreVec::with_capacity_and_offset(2, 10); 143 | /// v.insert(1u32); 144 | /// assert_eq!(v.get(10), Some(&1)); 145 | /// ``` 146 | pub fn get(&self, index: usize) -> Option<&T> { 147 | match self.inner.get(index - self.offset) { 148 | Some(Entry::Empty(_)) | None => None, 149 | Some(Entry::Occupied(ref v)) => Some(v) 150 | } 151 | } 152 | 153 | /// Get a mutable entry at a specific index 154 | /// 155 | /// # Example 156 | /// 157 | /// ``` 158 | /// # use sonr::PreVec; 159 | /// let mut v = PreVec::with_capacity_and_offset(2, 10); 160 | /// v.insert("original".to_string()); 161 | /// v.get_mut(10).map(|s| *s = "changed".to_string()).unwrap(); 162 | /// assert_eq!(&v[10], "changed"); 163 | /// ``` 164 | pub fn get_mut(&mut self, index: usize) -> Option<&mut T> { 165 | match self.inner.get_mut(index - self.offset) { 166 | Some(Entry::Empty(_)) | None => None, 167 | Some(Entry::Occupied(ref mut v)) => Some(v) 168 | } 169 | } 170 | 171 | fn grow_if_required(&mut self, index: usize) -> Result<()> { 172 | // Grow the inner vec up to the index 173 | if index >= self.inner.len() { 174 | // If the PreVec is not allowed to grow then 175 | // return a NoCapacity error 176 | if index >= self.capacity && !self.can_grow { 177 | return Err(Error::NoCapacity); 178 | } 179 | 180 | // If it's less than capacity 181 | // then grow to accomodate the index 182 | let len = self.inner.len(); 183 | if index < self.capacity { 184 | let mut inner: Vec> = (len..self.capacity) 185 | .map(|i| Entry::Empty(i+1)) 186 | .collect(); 187 | self.inner.append(&mut inner); 188 | } else { 189 | self.capacity *= 2; 190 | let mut inner: Vec> = (len..self.capacity) 191 | .map(|i| Entry::Empty(i+1)) 192 | .collect(); 193 | self.inner.append(&mut inner); 194 | } 195 | } 196 | 197 | Ok(()) 198 | } 199 | 200 | /// Insert a value in the next available slot and return the slot index. 201 | /// Inserting above capacity will cause reallocation if and only if the `PreVec` can grow. 202 | /// 203 | /// # Example 204 | /// 205 | /// ``` 206 | /// # use sonr::PreVec; 207 | /// let mut v = PreVec::with_capacity_and_offset(2, 10); 208 | /// let index = v.insert(1).unwrap(); 209 | /// assert_eq!(index, 10); 210 | /// ``` 211 | pub fn insert(&mut self, v: T) -> Result { 212 | let index = self.next; 213 | 214 | self.grow_if_required(index)?; 215 | 216 | let empty = replace(&mut self.inner[index], Entry::Occupied(v)); 217 | match empty { 218 | Entry::Empty(next) => { 219 | self.length += 1; 220 | self.next = next; 221 | } 222 | Entry::Occupied(_) => panic!("attempted to insert into occupied slot: {}", index), 223 | } 224 | Ok(index + self.offset) 225 | } 226 | 227 | /// Remove at index (inserting an empty entry) 228 | pub fn remove(&mut self, index: usize) -> Option { 229 | if let Entry::Empty(_) = self.inner[index - self.offset] { 230 | return None; 231 | } 232 | 233 | let prev = replace( 234 | &mut self.inner[index - self.offset], 235 | Entry::Empty(self.next) 236 | ); 237 | 238 | match prev { 239 | Entry::Occupied(v) => { 240 | self.length -= 1; 241 | self.next = index - self.offset; 242 | Some(v) 243 | } 244 | Entry::Empty(_) => None 245 | } 246 | } 247 | 248 | /// Number of occupied slots 249 | pub fn len(&self) -> usize { 250 | self.length 251 | } 252 | 253 | /// Returns `true` if the collection has no entries 254 | pub fn is_empty(&self) -> bool { 255 | self.len() == 0 256 | } 257 | 258 | /// Remove all entries 259 | pub fn clear(&mut self) { 260 | self.inner = (0..self.capacity).map(|i| Entry::Empty(i+1)).collect(); 261 | self.next = 0; 262 | self.length = 0; 263 | } 264 | } 265 | 266 | 267 | // ----------------------------------------------------------------------------- 268 | // - impl Index - 269 | // ----------------------------------------------------------------------------- 270 | impl Index for PreVec { 271 | type Output = T; 272 | 273 | fn index(&self, index: usize) -> &T { 274 | match &self.inner[index - self.offset] { 275 | Entry::Occupied(v) => v, 276 | Entry::Empty(_) => panic!("invalid index"), 277 | } 278 | } 279 | } 280 | 281 | // ----------------------------------------------------------------------------- 282 | // - impl IndexMut - 283 | // ----------------------------------------------------------------------------- 284 | impl IndexMut for PreVec { 285 | fn index_mut(&mut self, index: usize) -> &mut T { 286 | match &mut self.inner[index - self.offset] { 287 | Entry::Occupied(v) => v, 288 | Entry::Empty(_) => panic!("invalid index: {}", index), 289 | } 290 | } 291 | } 292 | 293 | #[cfg(test)] 294 | mod tests { 295 | use super::*; 296 | 297 | #[derive(Clone)] 298 | struct Foo { 299 | a: usize, 300 | b: usize, 301 | } 302 | 303 | fn values(cap: usize) -> Vec { 304 | vec![Foo { a: 1, b: 2}; cap] 305 | } 306 | 307 | #[test] 308 | fn remove_with_offset() -> Result<()> { 309 | let mut v = PreVec::with_capacity_and_offset(10, 1); 310 | assert_eq!(v.insert(0)?, 1); 311 | assert_eq!(v.insert(1)?, 2); 312 | assert_eq!(v.insert(2)?, 3); 313 | assert_eq!(v.remove(1), Some(0)); 314 | assert_eq!(v.remove(1), None); 315 | assert_eq!(v.insert(1)?, 1); 316 | Ok(()) 317 | } 318 | 319 | #[test] 320 | fn insert_get_index() { 321 | let mut v = PreVec::with_capacity(10); 322 | assert_eq!(v.insert("foo").unwrap(), 0); 323 | assert_eq!(v.insert("foo").unwrap(), 1); 324 | } 325 | 326 | #[test] 327 | fn get_mut() { 328 | let mut v = PreVec::with_capacity(1); 329 | v.insert("foo").unwrap(); 330 | let x = &mut v[0]; 331 | assert_eq!(x, &"foo"); 332 | } 333 | 334 | #[test] 335 | fn remove() { 336 | let mut v = PreVec::with_capacity(10); 337 | assert_eq!(v.insert("foo").unwrap(), 0); 338 | v.remove(0); 339 | assert_eq!(v.insert("foo").unwrap(), 0); 340 | } 341 | 342 | #[test] 343 | fn insert_many() { 344 | let cap = 10; 345 | let values = values(cap); 346 | let mut store = PreVec::with_capacity(cap); 347 | 348 | // Add twice as many elements forcing 349 | // a resize 350 | for _ in 0..cap * 2 { 351 | for v in &values { 352 | store.insert(v); 353 | } 354 | 355 | for v in &values { 356 | let _v = store[v.a]; 357 | } 358 | } 359 | 360 | // Make sure the resize works 361 | let x = store.remove(15).unwrap(); 362 | assert_eq!(store.insert(x).unwrap(), 15); 363 | } 364 | 365 | 366 | #[test] 367 | fn insert_with_offset() { 368 | let mut store = PreVec::with_capacity(2); 369 | store.set_offset(10); 370 | 371 | let index = store.insert(1u32).unwrap(); 372 | assert_eq!(index, 10); 373 | let index = store.insert(1u32).unwrap(); 374 | assert_eq!(index, 11); 375 | 376 | } 377 | 378 | #[test] 379 | fn removing_with_offset_returns_correct_value() { 380 | let mut store = PreVec::with_capacity(2); 381 | store.set_offset(10); 382 | 383 | let index = store.insert(1u32).unwrap(); 384 | assert_eq!(index, 10); 385 | let val = store.remove(index).unwrap(); 386 | assert_eq!(val, 1u32); 387 | } 388 | 389 | #[test] 390 | fn get_with_offset() { 391 | let mut store = PreVec::with_capacity(2); 392 | store.set_offset(10); 393 | 394 | store.insert(1u32); 395 | store.insert(2u32); 396 | 397 | assert_eq!(*store.get(10).unwrap(), 1); 398 | assert_eq!(*store.get(11).unwrap(), 2); 399 | } 400 | 401 | #[test] 402 | fn get_mut_with_offset() { 403 | let mut store = PreVec::with_capacity(2); 404 | store.set_offset(10); 405 | 406 | store.insert(1u32); 407 | store.insert(2u32); 408 | 409 | assert_eq!(*store.get_mut(10).unwrap(), 1); 410 | assert_eq!(*store.get_mut(11).unwrap(), 2); 411 | } 412 | 413 | #[test] 414 | fn index_with_offset() { 415 | let mut store = PreVec::with_capacity(2); 416 | store.set_offset(10); 417 | store.insert(1); 418 | store.insert(2); 419 | 420 | assert_eq!(*store.get(10).unwrap(), 1); 421 | assert_eq!(*store.get(11).unwrap(), 2); 422 | } 423 | 424 | #[test] 425 | fn max_index_with_offset() { 426 | use std::usize::MAX as MAX_USIZE; 427 | let mut store = PreVec::with_capacity_and_offset(1, MAX_USIZE); 428 | let index = store.insert(1u32).unwrap(); 429 | assert_eq!(index, MAX_USIZE); 430 | } 431 | 432 | #[test] 433 | fn in_range() { 434 | let store: PreVec = PreVec::with_capacity(100); 435 | 436 | assert!(store.in_range(0)); 437 | assert!(store.in_range(99)); 438 | assert!(!store.in_range(100)); 439 | } 440 | 441 | #[test] 442 | fn len_after_remove() { 443 | let mut store: PreVec = PreVec::with_capacity(100); 444 | store.insert(10); 445 | store.remove(0); 446 | assert_eq!(store.len(), 0); 447 | } 448 | 449 | #[test] 450 | fn allow_growth() { 451 | let mut store: PreVec = PreVec::with_capacity(1); 452 | store.insert(1); 453 | store.insert(1); 454 | 455 | assert_eq!(store.capacity, 2); 456 | } 457 | 458 | #[test] 459 | fn disable_growth() { 460 | let mut store: PreVec = PreVec::with_capacity(1); 461 | store.prevent_growth(); 462 | assert_eq!(store.insert(1).unwrap(), 0); 463 | match store.insert(1) { 464 | Err(Error::NoCapacity) => {} 465 | _ => panic!("Should return a NoCapacity error") 466 | } 467 | 468 | assert_eq!(store.capacity, 1); 469 | } 470 | } 471 | --------------------------------------------------------------------------------