Skip to content

Commit

Permalink
models, bind update (#76)
Browse files Browse the repository at this point in the history
  • Loading branch information
schell authored Jan 6, 2021
1 parent 6a325af commit d472f0a
Show file tree
Hide file tree
Showing 10 changed files with 114 additions and 21 deletions.
2 changes: 1 addition & 1 deletion cookbook/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
mogwai = { path = "../mogwai", version = "^0.3" }
mogwai = { path = "../mogwai", version = "^0.4" }

[dependencies.web-sys]
version = "^0.3"
Expand Down
4 changes: 2 additions & 2 deletions crates/mogwai-hydrator/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "mogwai-hydrator"
version = "0.1.1"
version = "0.1.2"
authors = ["Schell Scivally <efsubenovex@gmail.com>"]
edition = "2018"
description = "View hydration for the mogwai library"
Expand All @@ -14,7 +14,7 @@ documentation = "https://docs.rs/mogwai/"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
mogwai = { path = "../../mogwai", version = "^0.3" }
mogwai = { path = "../../mogwai", version = "^0.4" }
snafu = "^0.6"
wasm-bindgen = "^0.2"

Expand Down
2 changes: 1 addition & 1 deletion examples/list-of-gizmos/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ console_error_panic_hook = { version = "0.1.6", optional = true }
wee_alloc = { version = "0.4.2", optional = true }

[dependencies.mogwai]
version = "^0.3"
version = "^0.4"
path = "../../mogwai"

[dependencies.web-sys]
Expand Down
2 changes: 1 addition & 1 deletion examples/svg/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ console_error_panic_hook = { version = "0.1.6", optional = true }
wee_alloc = { version = "0.4.2", optional = true }

[dependencies.mogwai]
version = "^0.3"
version = "^0.4"
path = "../../mogwai"

[dependencies.web-sys]
Expand Down
2 changes: 1 addition & 1 deletion mogwai/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "mogwai"
version = "0.3.6"
version = "0.4.0"
authors = ["Schell Scivally <efsubenovex@gmail.com>"]
edition = "2018"
license = "MIT"
Expand Down
19 changes: 8 additions & 11 deletions mogwai/src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,14 @@ where
/// ie HtmlElement, HtmlInputElement, etc.
type DomNode;

/// Used to perform any one-time binding from in scope [`Gizmo`]s or [`Model`]s to this component's subscribers.
///
/// This function will be called only once, after a [`Gizmo`] is converted from the
/// type implementing `Component`.
#[allow(unused_variables)]
fn bind(&self, input_sub: &Subscriber<Self::ModelMsg>, output_sub: &Subscriber<Self::ViewMsg>) {
}

/// Update this component in response to any received model messages.
/// This is essentially the component's fold function.
fn update(
Expand All @@ -189,15 +197,4 @@ where
tx: &Transmitter<Self::ModelMsg>,
rx: &Receiver<Self::ViewMsg>,
) -> ViewBuilder<Self::DomNode>;

/// Used to perform any one-time binding from in scope [`Gizmo`]s to this component's subscriber.
///
/// This should be used to bind sub-component view messages into this parent component's
/// model messages in order to receive updates from child components. The default implementation
/// is a noop.
///
/// This function will be called only once, after a [`Gizmo`] is converted from the
/// type implementing `Component`.
#[allow(unused_variables)]
fn bind(&self, sub: &Subscriber<Self::ModelMsg>) {}
}
20 changes: 16 additions & 4 deletions mogwai/src/gizmo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use crate::{
};

/// A user interface component that can spawn views.
#[derive(Clone)]
pub struct Gizmo<T: Component> {
/// This gizmo's [`Component::ModelMsg`] transmitter.
/// Sending on this [`Transmitter`] causes its [`Component::update`]
Expand All @@ -45,15 +46,17 @@ where
tx_in: Transmitter<T::ModelMsg>,
rx_out: Receiver<T::ViewMsg>,
) -> Self {
let subscriber = Subscriber::new(&tx_in);
init.bind(&subscriber);
let state = Rc::new(RefCell::new(init));
let tx_out = rx_out.new_trns();
let rx_in = tx_in.spawn_recv();
let in_subscriber = Subscriber::new(&tx_in);
let out_subscriber = Subscriber::new(&tx_out);
init.bind(&in_subscriber, &out_subscriber);

let state = Rc::new(RefCell::new(init));

let (tx_view, rx_view) = txrx();
rx_in.respond_shared(state.clone(), move |t: &mut T, msg: &T::ModelMsg| {
t.update(msg, &tx_view, &subscriber);
t.update(msg, &tx_view, &in_subscriber);
});

rx_view.respond(move |msg: &T::ViewMsg| {
Expand Down Expand Up @@ -91,6 +94,15 @@ where
self.trns.send(msg);
}

/// Visit the wrapped value with a function that produces a value.
pub fn visit<F, A>(&self, f: F) -> A
where
A: 'static,
F: FnOnce(&T) -> A,
{
f(&self.state.borrow())
}

/// Access the underlying state.
pub fn with_state<F, N>(&self, f: F) -> N
where
Expand Down
1 change: 1 addition & 0 deletions mogwai/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
pub mod an_introduction;
pub mod component;
pub mod gizmo;
pub mod model;
pub mod prelude;
#[cfg(not(target_arch = "wasm32"))]
pub mod ssr;
Expand Down
82 changes: 82 additions & 0 deletions mogwai/src/model.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
//! Data that transmits updates to subscribers automatically.
use crate::txrx::*;
use std::{cell::RefCell, rc::Rc};

/// Wraps a value `T` and transmits updates to subscribers.
#[derive(Clone)]
pub struct Model<T> {
value: Rc<RefCell<T>>,
trns: Transmitter<T>,
recv: Receiver<T>,
}

impl<T: Clone + 'static> Model<T> {
/// Create a new model from a `T`.
pub fn new(t: T) -> Model<T> {
let (trns, recv) = txrx::<T>();
Model {
value: Rc::new(RefCell::new(t)),
trns,
recv,
}
}

/// Manually transmitter the inner value of this model to subscribers.
pub fn transmit(&self) {
self.trns.send(&self.value.as_ref().borrow());
}

/// Visit the wrapped value with a function that produces a value.
pub fn visit<F, A>(&self, f: F) -> A
where
A: 'static,
F: FnOnce(&T) -> A,
{
f(&self.value.borrow())
}

/// Visit the mutable wrapped value with a function that produces a value.
pub fn visit_mut<F, A>(&self, f: F) -> A
where
A: 'static,
F: FnOnce(&mut T) -> A,
{
let a = f(&mut self.value.borrow_mut());
self.transmit();
a
}

/// Replaces the wrapped value with a new one, returning the old value, without deinitializing either one.
///
/// This function corresponds to std::mem::replace.
pub fn replace(&self, t: T) -> T {
let t = self.value.replace(t);
self.transmit();
t
}

/// Replaces the wrapped value with a new one computed from f, returning the old value, without deinitializing either one.
pub fn replace_with<F>(&self, f: F) -> T
where
F: FnOnce(&mut T) -> T,
{
let t = self.value.replace_with(f);
self.transmit();
t
}

/// Access the model's receiver.
///
/// The returned receiver can be used to subscribe to the model's updates.
pub fn recv(&self) -> &Receiver<T> {
&self.recv
}
}

impl<T: Clone + Default + 'static> Model<T> {
/// Takes the wrapped value, leaving Default::default() in its place.
pub fn take(&self) -> T {
let new_t = Default::default();
self.replace(new_t)
}
}
1 change: 1 addition & 0 deletions mogwai/src/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
pub use super::{
component::{subscriber::Subscriber, *},
gizmo::*,
model::*,
txrx::{
new_shared, recv, trns, txrx, txrx_filter_fold, txrx_filter_map, txrx_fold,
txrx_fold_shared, txrx_map, wrap_future, Receiver, Transmitter,
Expand Down

0 comments on commit d472f0a

Please sign in to comment.