Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conditially require serialize #1195

Merged
merged 13 commits into from
May 12, 2020
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ before_cache:
- ./ci/clear_cache.sh

rust:
- 1.40.0 # min supported
- 1.42.0 # min supported
- stable
- beta

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<a href="https://crates.io/crates/yew"><img alt="Crate Info" src="https://img.shields.io/crates/v/yew.svg"/></a>
<a href="https://docs.rs/yew/"><img alt="API Docs" src="https://img.shields.io/badge/docs.rs-yew-green"/></a>
<a href="https://discord.gg/VQck8X4"><img alt="Discord Chat" src="https://img.shields.io/discord/701068342760570933"/></a>
<a href="https://blog.rust-lang.org/2019/12/19/Rust-1.40.0.html"><img alt="Rustc Version 1.40+" src="https://img.shields.io/badge/rustc-1.40+-lightgray.svg"/></a>
<a href="https://blog.rust-lang.org/2020/03/12/Rust-1.42.html"><img alt="Rustc Version 1.42+" src="https://img.shields.io/badge/rustc-1.42%2B-lightgrey.svg"/></a>
<a href="https://github.com/jetli/awesome-yew"><img alt="Yew Awesome" src="https://raw.githubusercontent.com/sindresorhus/awesome/master/media/badge.svg"/></a>
</p>

Expand Down
2 changes: 1 addition & 1 deletion examples/multi_thread/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub struct Worker {
}

impl Agent for Worker {
type Reach = Context;
type Reach = Context<Self>;
type Message = Msg;
type Input = Request;
type Output = Response;
Expand Down
2 changes: 1 addition & 1 deletion examples/multi_thread/src/job.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub struct Worker {
}

impl Agent for Worker {
type Reach = Job;
type Reach = Job<Self>;
type Message = Msg;
type Input = Request;
type Output = Response;
Expand Down
2 changes: 1 addition & 1 deletion examples/multi_thread/src/native_worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub struct Worker {
}

impl Agent for Worker {
type Reach = Public;
type Reach = Public<Self>;
type Message = Msg;
type Input = Request;
type Output = Response;
Expand Down
2 changes: 1 addition & 1 deletion examples/pub_sub/src/event_bus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub struct EventBus {
}

impl Agent for EventBus {
type Reach = Context;
type Reach = Context<Self>;
type Message = ();
type Input = Request;
type Output = String;
Expand Down
2 changes: 1 addition & 1 deletion yew-router/src/agent/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ where
type Input = RouteRequest<STATE>;
type Message = Msg<STATE>;
type Output = Route<STATE>;
type Reach = Context;
type Reach = Context<Self>;

fn create(link: AgentLink<RouteAgent<STATE>>) -> Self {
let callback = link.callback(Msg::BrowserNavigationRouteChanged);
Expand Down
2 changes: 1 addition & 1 deletion yew-stdweb/examples/multi_thread/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub struct Worker {
}

impl Agent for Worker {
type Reach = Context;
type Reach = Context<Self>;
type Message = Msg;
type Input = Request;
type Output = Response;
Expand Down
2 changes: 1 addition & 1 deletion yew-stdweb/examples/multi_thread/src/job.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub struct Worker {
}

impl Agent for Worker {
type Reach = Job;
type Reach = Job<Self>;
type Message = Msg;
type Input = Request;
type Output = Response;
Expand Down
2 changes: 1 addition & 1 deletion yew-stdweb/examples/multi_thread/src/native_worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub struct Worker {
}

impl Agent for Worker {
type Reach = Public;
type Reach = Public<Self>;
type Message = Msg;
type Input = Request;
type Output = Response;
Expand Down
16 changes: 12 additions & 4 deletions yew/src/agent/local/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::scheduler::Shared;
use anymap::{self, AnyMap};
use slab::Slab;
use std::cell::RefCell;
use std::marker::PhantomData;
use std::rc::Rc;

thread_local! {
Expand All @@ -12,10 +13,17 @@ thread_local! {

/// Create a single instance in the current thread.
#[allow(missing_debug_implementations)]
pub struct Context;
pub struct Context<AGN> {
_agent: PhantomData<AGN>,
}

impl<AGN> Discoverer for Context<AGN>
where
AGN: Agent,
{
type Agent = AGN;

impl Discoverer for Context {
fn spawn_or_join<AGN: Agent>(callback: Option<Callback<AGN::Output>>) -> Box<dyn Bridge<AGN>> {
fn spawn_or_join(callback: Option<Callback<AGN::Output>>) -> Box<dyn Bridge<AGN>> {
let mut scope_to_init = None;
let bridge = LOCAL_AGENTS_POOL.with(|pool| {
let mut pool = pool.borrow_mut();
Expand Down Expand Up @@ -53,7 +61,7 @@ impl<AGN: Agent> Responder<AGN> for SlabResponder<AGN> {
}
}

impl Dispatchable for Context {}
impl<AGN: Agent> Dispatchable for Context<AGN> {}

struct ContextBridge<AGN: Agent> {
scope: AgentScope<AGN>,
Expand Down
14 changes: 11 additions & 3 deletions yew/src/agent/local/job.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
use super::*;
use crate::callback::Callback;
use std::marker::PhantomData;

const SINGLETON_ID: HandlerId = HandlerId(0, true);

/// Create an instance in the current thread.
#[allow(missing_debug_implementations)]
pub struct Job;
pub struct Job<AGN> {
_agent: PhantomData<AGN>,
}

impl<AGN> Discoverer for Job<AGN>
where
AGN: Agent,
{
type Agent = AGN;

impl Discoverer for Job {
fn spawn_or_join<AGN: Agent>(callback: Option<Callback<AGN::Output>>) -> Box<dyn Bridge<AGN>> {
fn spawn_or_join(callback: Option<Callback<AGN::Output>>) -> Box<dyn Bridge<AGN>> {
let callback = callback.expect("Callback required for Job");
let scope = AgentScope::<AGN>::new();
let responder = CallbackResponder { callback };
Expand Down
39 changes: 22 additions & 17 deletions yew/src/agent/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! This module contains types to support multi-threading in Yew.
//! This module contains types to support multi-threading and state management.
jstarry marked this conversation as resolved.
Show resolved Hide resolved

mod link;
mod local;
Expand All @@ -20,13 +20,13 @@ use std::ops::{Deref, DerefMut};
/// Declares the behavior of the agent.
pub trait Agent: Sized + 'static {
/// Reach capability of the agent.
type Reach: Discoverer;
type Reach: Discoverer<Agent = Self>;
/// Type of an input message.
jstarry marked this conversation as resolved.
Show resolved Hide resolved
type Message;
/// Incoming message type.
type Input: Serialize + for<'de> Deserialize<'de>;
type Input;
/// Outgoing message type.
type Output: Serialize + for<'de> Deserialize<'de>;
type Output;

/// Creates an instance of an agent.
fn create(link: AgentLink<Self>) -> Self;
Expand Down Expand Up @@ -76,6 +76,23 @@ impl HandlerId {
}
}

/// Determine a visibility of an agent.
#[doc(hidden)]
pub trait Discoverer {
type Agent: Agent;

/// Spawns an agent and returns `Bridge` implementation.
fn spawn_or_join(
_callback: Option<Callback<<Self::Agent as Agent>::Output>>,
) -> Box<dyn Bridge<Self::Agent>>;
}

/// Bridge to a specific kind of worker.
pub trait Bridge<AGN: Agent> {
/// Send a message to an agent.
fn send(&mut self, msg: AGN::Input);
}

/// This trait allows registering or getting the address of a worker.
pub trait Bridged: Agent + Sized + 'static {
/// Creates a messaging bridge between a worker and the component.
Expand All @@ -85,21 +102,9 @@ pub trait Bridged: Agent + Sized + 'static {
impl<T> Bridged for T
where
T: Agent,
<T as Agent>::Reach: Discoverer<Agent = T>,
{
fn bridge(callback: Callback<Self::Output>) -> Box<dyn Bridge<Self>> {
Self::Reach::spawn_or_join(Some(callback))
}
}

/// Determine a visibility of an agent.
#[doc(hidden)]
pub trait Discoverer {
/// Spawns an agent and returns `Bridge` implementation.
fn spawn_or_join<AGN: Agent>(_callback: Option<Callback<AGN::Output>>) -> Box<dyn Bridge<AGN>>;
}

/// Bridge to a specific kind of worker.
pub trait Bridge<AGN: Agent> {
/// Send a message to an agent.
fn send(&mut self, msg: AGN::Input);
}
3 changes: 2 additions & 1 deletion yew/src/agent/pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,10 @@ pub trait Dispatchable {}
impl<T> Dispatched for T
where
T: Agent,
<T as Agent>::Reach: Discoverer<Agent = T>,
<T as Agent>::Reach: Dispatchable,
{
fn dispatcher() -> Dispatcher<T> {
Dispatcher(Self::Reach::spawn_or_join::<T>(None))
Dispatcher(Self::Reach::spawn_or_join(None))
}
}
8 changes: 6 additions & 2 deletions yew/src/agent/worker/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,15 @@ enum FromWorker<T> {
ProcessOutput(HandlerId, T),
}

fn send_to_remote<AGN: Agent>(
fn send_to_remote<AGN>(
#[cfg(feature = "std_web")] worker: &Value,
#[cfg(feature = "web_sys")] worker: &Worker,
msg: ToWorker<AGN::Input>,
) {
) where
AGN: Agent,
<AGN as Agent>::Input: Serialize + for<'de> Deserialize<'de>,
<AGN as Agent>::Output: Serialize + for<'de> Deserialize<'de>,
{
let msg = msg.pack();
cfg_match! {
feature = "std_web" => js! {
Expand Down
45 changes: 37 additions & 8 deletions yew/src/agent/worker/private.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,19 @@ const SINGLETON_ID: HandlerId = HandlerId(0, true);

/// Create a new instance for every bridge.
#[allow(missing_debug_implementations)]
pub struct Private;
pub struct Private<AGN> {
_agent: PhantomData<AGN>,
}

impl<AGN> Discoverer for Private<AGN>
where
AGN: Agent,
<AGN as Agent>::Input: Serialize + for<'de> Deserialize<'de>,
<AGN as Agent>::Output: Serialize + for<'de> Deserialize<'de>,
{
type Agent = AGN;

impl Discoverer for Private {
fn spawn_or_join<AGN: Agent>(callback: Option<Callback<AGN::Output>>) -> Box<dyn Bridge<AGN>> {
fn spawn_or_join(callback: Option<Callback<AGN::Output>>) -> Box<dyn Bridge<AGN>> {
let callback = callback.expect("Callback required for Private agents");
let handler = move |data: Vec<u8>,
#[cfg(feature = "std_web")] worker: Value,
Expand Down Expand Up @@ -65,21 +74,36 @@ impl Discoverer for Private {
}

/// A connection manager for components interaction with workers.
pub struct PrivateBridge<T: Agent> {
pub struct PrivateBridge<AGN>
where
AGN: Agent,
<AGN as Agent>::Input: Serialize + for<'de> Deserialize<'de>,
<AGN as Agent>::Output: Serialize + for<'de> Deserialize<'de>,
{
#[cfg(feature = "std_web")]
worker: Value,
#[cfg(feature = "web_sys")]
worker: Worker,
_agent: PhantomData<T>,
_agent: PhantomData<AGN>,
}

impl<AGN: Agent> fmt::Debug for PrivateBridge<AGN> {
impl<AGN> fmt::Debug for PrivateBridge<AGN>
where
AGN: Agent,
<AGN as Agent>::Input: Serialize + for<'de> Deserialize<'de>,
<AGN as Agent>::Output: Serialize + for<'de> Deserialize<'de>,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("PrivateBridge<_>")
}
}

impl<AGN: Agent> Bridge<AGN> for PrivateBridge<AGN> {
impl<AGN> Bridge<AGN> for PrivateBridge<AGN>
where
AGN: Agent,
<AGN as Agent>::Input: Serialize + for<'de> Deserialize<'de>,
<AGN as Agent>::Output: Serialize + for<'de> Deserialize<'de>,
{
fn send(&mut self, msg: AGN::Input) {
// TODO(#937): Important! Implement.
// Use a queue to collect a messages if an instance is not ready
Expand All @@ -99,7 +123,12 @@ impl<AGN: Agent> Bridge<AGN> for PrivateBridge<AGN> {
}
}

impl<AGN: Agent> Drop for PrivateBridge<AGN> {
impl<AGN> Drop for PrivateBridge<AGN>
where
AGN: Agent,
<AGN as Agent>::Input: Serialize + for<'de> Deserialize<'de>,
<AGN as Agent>::Output: Serialize + for<'de> Deserialize<'de>,
{
fn drop(&mut self) {
let disconnected = ToWorker::Disconnected(SINGLETON_ID);
send_to_remote::<AGN>(&self.worker, disconnected);
Expand Down
Loading