1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
//! Workers are a way to offload tasks to web workers. These are run concurrently using
//! [web-workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers).
//!
//! # Types of Workers
//!
//! ## Reaches
//!
//! * Public - There will exist at most one instance of a Public Worker at any given time.
//! Bridges will spawn or connect to an already spawned worker in a web worker.
//! When no bridges are connected to this worker, the worker will disappear.
//!
//! * Private - Spawn a new worker in a web worker for every new bridge. This is good for
//! moving shared but independent behavior that communicates with the browser out of components.
//! When the the connected bridge is dropped, the worker will disappear.
//!
//! # Communicating with workers
//!
//! ## Bridges
//!
//! A bridge allows bi-directional communication between an worker and a component.
//! Bridges also allow workers to communicate with one another.
//!
//! ## Dispatchers
//!
//! A dispatcher allows uni-directional communication between a component and an worker.
//! A dispatcher allows a component to send messages to an worker.
//!
//! # Overhead
//!
//! Workers use web workers (i.e. Private and Public). They incur a serialization overhead on the
//! messages they send and receive. Workers use [bincode](https://!github.com/servo/bincode)
//! to communicate with other browser worker, so the cost is substantially higher
//! than just calling a function.
#![cfg_attr(docsrs, feature(doc_cfg))]
mod link;
mod pool;
mod worker;
pub use link::WorkerLink;
pub(crate) use link::*;
pub(crate) use pool::*;
pub use pool::{Dispatched, Dispatcher};
use std::cell::RefCell;
pub use worker::{Private, PrivateWorker, Public, PublicWorker};
use serde::{Deserialize, Serialize};
use std::fmt;
use std::ops::{Deref, DerefMut};
use std::rc::Rc;
/// Alias for `Rc<RefCell<T>>`
pub type Shared<T> = Rc<RefCell<T>>;
/// Alias for `Rc<dyn Fn(IN)>`
pub type Callback<IN> = Rc<dyn Fn(IN)>;
/// Declares the behavior of the worker.
pub trait Worker: Sized + 'static {
/// Reach capability of the worker.
type Reach: Discoverer<Worker = Self>;
/// Type of an input message.
type Message;
/// Incoming message type.
type Input;
/// Outgoing message type.
type Output;
/// Creates an instance of an worker.
fn create(link: WorkerLink<Self>) -> Self;
/// This method called on every update message.
fn update(&mut self, msg: Self::Message);
/// This method called on when a new bridge created.
fn connected(&mut self, _id: HandlerId) {}
/// This method called on every incoming message.
fn handle_input(&mut self, msg: Self::Input, id: HandlerId);
/// This method called on when a new bridge destroyed.
fn disconnected(&mut self, _id: HandlerId) {}
/// This method called when the worker is destroyed.
fn destroy(&mut self) {}
/// Represents the name of loading resource for remote workers which
/// have to live in a separate files.
fn name_of_resource() -> &'static str {
"main.js"
}
/// Indicates whether the name of the resource is relative.
///
/// The default implementation returns `false`, which will cause the result
/// returned by [`Self::name_of_resource`] to be interpreted as an absolute
/// URL. If `true` is returned, it will be interpreted as a relative URL.
fn resource_path_is_relative() -> bool {
false
}
/// Signifies if resource is a module.
/// This has pending browser support.
fn is_module() -> bool {
false
}
}
/// Id of responses handler.
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Hash, Clone, Copy)]
pub struct HandlerId(usize, bool);
impl HandlerId {
fn new(id: usize, respondable: bool) -> Self {
HandlerId(id, respondable)
}
fn raw_id(self) -> usize {
self.0
}
/// Indicates if a handler id corresponds to callback in the Worker runtime.
pub fn is_respondable(self) -> bool {
self.1
}
}
/// Determine a visibility of an worker.
#[doc(hidden)]
pub trait Discoverer {
type Worker: Worker;
/// Spawns an worker and returns `Bridge` implementation.
fn spawn_or_join(
_callback: Option<Callback<<Self::Worker as Worker>::Output>>,
) -> Box<dyn Bridge<Self::Worker>>;
}
/// Bridge to a specific kind of worker.
pub trait Bridge<W: Worker> {
/// Send a message to an worker.
fn send(&mut self, msg: W::Input);
}
/// This trait allows registering or getting the address of a worker.
pub trait Bridged: Worker + Sized + 'static {
/// Creates a messaging bridge between a worker and the component.
fn bridge(callback: Callback<Self::Output>) -> Box<dyn Bridge<Self>>;
}
impl<T> Bridged for T
where
T: Worker,
<T as Worker>::Reach: Discoverer<Worker = T>,
{
fn bridge(callback: Callback<Self::Output>) -> Box<dyn Bridge<Self>> {
Self::Reach::spawn_or_join(Some(callback))
}
}