Permalink
Browse files

Remove CTX everywhere, but scheduler

  • Loading branch information...
DenisKolodin committed Jun 4, 2018
1 parent 064dc8e commit 12bf3fd98c1aa50c04fe8e852dd4b8f17ef0fe9e
Showing with 180 additions and 203 deletions.
  1. +8 −9 src/app.rs
  2. +40 −45 src/html.rs
  3. +14 −14 src/macros.rs
  4. +7 −9 src/virtual_dom/mod.rs
  5. +27 −31 src/virtual_dom/vcomp.rs
  6. +7 −8 src/virtual_dom/vlist.rs
  7. +22 −23 src/virtual_dom/vnode.rs
  8. +12 −13 src/virtual_dom/vtag.rs
  9. +8 −11 src/virtual_dom/vtext.rs
  10. +6 −9 tests/vlist_test.rs
  11. +29 −31 tests/vtag_test.rs
@@ -6,30 +6,29 @@ use html::{Scope, Component, Renderable};
use scheduler::Scheduler;

/// An application instance.
pub struct App<CTX, COMP: Component<CTX>> {
pub struct App<COMP: Component> {
/// `Scope` holder
scope: Scope<CTX, COMP>,
scope: Scope<COMP>,
}

impl<CTX, COMP> App<CTX, COMP>
impl<COMP> App<COMP>
where
CTX: 'static,
COMP: Component<CTX> + Renderable<CTX, COMP>,
COMP: Component + Renderable<COMP>,
{
/// Creates a new `App` with a component in a context.
pub fn new(context: CTX) -> Self {
pub fn new(context: ()) -> Self {
let scheduler = Scheduler::new(context);
App::reuse(&scheduler)
}

/// Creates isolated `App` instance, but reuse the context.
pub fn reuse(scheduler: &Scheduler<CTX>) -> Self {
pub fn reuse(scheduler: &Scheduler<()>) -> Self {
let scope = Scope::new(scheduler.clone());
App { scope }
}

/// Alias to `mount("body", ...)`.
pub fn mount_to_body(self) -> Scope<CTX, COMP> {
pub fn mount_to_body(self) -> Scope<COMP> {
// Bootstrap the component for `Window` environment only (not for `Worker`)
let element = document()
.query_selector("body")
@@ -42,7 +41,7 @@ where
/// function in Elm. You should provide an initial model, `update` function
/// which will update the state of the model and a `view` function which
/// will render the model to a virtual DOM tree.
pub fn mount(self, element: Element) -> Scope<CTX, COMP> {
pub fn mount(self, element: Element) -> Scope<COMP> {
clear_element(&element);
self.scope.mount_in_place(element, None, None, None)
}
@@ -16,7 +16,7 @@ use Shared;
pub type ShouldRender = bool;

/// An interface of a UI-component. Uses `self` as a model.
pub trait Component<CTX>: Sized + 'static {
pub trait Component: Sized + 'static {
/// Control message type which `update` loop get.
type Message: 'static;
/// Properties type of component implementation.
@@ -25,7 +25,7 @@ pub trait Component<CTX>: Sized + 'static {
/// with unknown type.
type Properties: Clone + PartialEq + Default;
/// Initialization routine which could use a context.
fn create(props: Self::Properties, link: ComponentLink<CTX, Self>) -> Self;
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self;
/// Called everytime when a messages of `Msg` type received. It also takes a
/// reference to a context.
fn update(&mut self, msg: Self::Message) -> ShouldRender;
@@ -38,15 +38,15 @@ pub trait Component<CTX>: Sized + 'static {
}

/// Should be rendered relative to context and component environment.
pub trait Renderable<CTX, COMP: Component<CTX>> {
pub trait Renderable<COMP: Component> {
/// Called by rendering loop.
fn view(&self) -> Html<CTX, COMP>;
fn view(&self) -> Html<COMP>;
}

/// Update message for a `Components` instance. Used by scope sender.
pub(crate) enum ComponentUpdate<CTX, COMP: Component<CTX>> {
pub(crate) enum ComponentUpdate< COMP: Component> {
/// Creating an instance of the component
Create(ComponentLink<CTX, COMP>),
Create(ComponentLink<COMP>),
/// Wraps messages for a component.
Message(COMP::Message),
/// Wraps properties for a component.
@@ -56,17 +56,16 @@ pub(crate) enum ComponentUpdate<CTX, COMP: Component<CTX>> {
}

/// Link to component's scope for creating callbacks.
pub struct ComponentLink<CTX, COMP: Component<CTX>> {
scope: Scope<CTX, COMP>,
pub struct ComponentLink<COMP: Component> {
scope: Scope<COMP>,
}

impl<CTX, COMP> ComponentLink<CTX, COMP>
impl<COMP> ComponentLink<COMP>
where
CTX: 'static,
COMP: Component<CTX> + Renderable<CTX, COMP>,
COMP: Component + Renderable<COMP>,
{
/// Create link for a scope.
fn connect(scope: &Scope<CTX, COMP>) -> Self {
fn connect(scope: &Scope<COMP>) -> Self {
ComponentLink {
scope: scope.clone(),
}
@@ -88,12 +87,12 @@ where

/// A context which contains a bridge to send a messages to a loop.
/// Mostly services uses it.
pub struct Scope<CTX, COMP: Component<CTX>> {
shared_component: Shared<Option<ComponentRunnable<CTX, COMP>>>,
scheduler: Scheduler<CTX>,
pub struct Scope<COMP: Component> {
shared_component: Shared<Option<ComponentRunnable<COMP>>>,
scheduler: Scheduler<()>,
}

impl<CTX, COMP: Component<CTX>> Clone for Scope<CTX, COMP> {
impl<COMP: Component> Clone for Scope<COMP> {
fn clone(&self) -> Self {
Scope {
shared_component: self.shared_component.clone(),
@@ -102,13 +101,12 @@ impl<CTX, COMP: Component<CTX>> Clone for Scope<CTX, COMP> {
}
}

impl<CTX, COMP> Scope<CTX, COMP>
impl<COMP> Scope<COMP>
where
CTX: 'static,
COMP: Component<CTX> + Renderable<CTX, COMP>,
COMP: Component + Renderable<COMP>,
{
/// Send the message and schedule an update.
pub(crate) fn send(&mut self, update: ComponentUpdate<CTX, COMP>) {
pub(crate) fn send(&mut self, update: ComponentUpdate<COMP>) {
let envelope = ComponentEnvelope {
shared_component: self.shared_component.clone(),
message: Some(update),
@@ -124,25 +122,24 @@ where
}
}

impl<CTX, COMP> Scope<CTX, COMP>
impl<COMP> Scope<COMP>
where
COMP: Component<CTX>,
COMP: Component,
{
/// Return an instance of a scheduler with a same pool of the app.
pub fn scheduler(&self) -> Scheduler<CTX> {
pub fn scheduler(&self) -> Scheduler<()> {
self.scheduler.clone()
}
}

/// Holder for the element.
pub type NodeCell = Rc<RefCell<Option<Node>>>;

impl<CTX, COMP> Scope<CTX, COMP>
impl<COMP> Scope<COMP>
where
CTX: 'static,
COMP: Component<CTX> + Renderable<CTX, COMP>,
COMP: Component + Renderable<COMP>,
{
pub(crate) fn new(scheduler: Scheduler<CTX>) -> Self {
pub(crate) fn new(scheduler: Scheduler<()>) -> Self {
let shared_component = Rc::new(RefCell::new(None));
Scope { shared_component, scheduler }
}
@@ -152,10 +149,10 @@ where
pub(crate) fn mount_in_place(
self,
element: Element,
ancestor: Option<VNode<CTX, COMP>>,
ancestor: Option<VNode<COMP>>,
occupied: Option<NodeCell>,
init_props: Option<COMP::Properties>,
) -> Scope<CTX, COMP> {
) -> Scope<COMP> {
let runnable = ComponentRunnable {
env: self.clone(),
component: None,
@@ -174,31 +171,30 @@ where
}
}

struct ComponentRunnable<CTX, COMP: Component<CTX>> {
env: Scope<CTX, COMP>,
struct ComponentRunnable<COMP: Component> {
env: Scope<COMP>,
component: Option<COMP>,
last_frame: Option<VNode<CTX, COMP>>,
last_frame: Option<VNode<COMP>>,
element: Element,
ancestor: Option<VNode<CTX, COMP>>,
ancestor: Option<VNode<COMP>>,
occupied: Option<NodeCell>,
init_props: Option<COMP::Properties>,
destroyed: bool,
}

/// Wraps a component reference and a message to hide it under `Runnable` trait.
/// It's necessary to schedule a processing of a message.
struct ComponentEnvelope<CTX, COMP>
struct ComponentEnvelope<COMP>
where
COMP: Component<CTX>,
COMP: Component,
{
shared_component: Shared<Option<ComponentRunnable<CTX, COMP>>>,
message: Option<ComponentUpdate<CTX, COMP>>,
shared_component: Shared<Option<ComponentRunnable<COMP>>>,
message: Option<ComponentUpdate<COMP>>,
}

impl<CTX, COMP> Runnable for ComponentEnvelope<CTX, COMP>
impl<COMP> Runnable for ComponentEnvelope<COMP>
where
CTX: 'static,
COMP: Component<CTX> + Renderable<CTX, COMP>,
COMP: Component + Renderable<COMP>,
{
fn run<'a>(&mut self, _: &mut ()) {
let mut component = self.shared_component.borrow_mut();
@@ -258,7 +254,7 @@ where
}

/// A type which expected as a result of `view` function implementation.
pub type Html<CTX, MSG> = VNode<CTX, MSG>;
pub type Html<MSG> = VNode<MSG>;

macro_rules! impl_action {
($($action:ident($event:ident : $type:ident) -> $ret:ty => $convert:expr)*) => {$(
@@ -285,17 +281,16 @@ macro_rules! impl_action {
}
}

impl<T, CTX, COMP> Listener<CTX, COMP> for Wrapper<T>
impl<T, COMP> Listener<COMP> for Wrapper<T>
where
T: Fn($ret) -> COMP::Message + 'static,
CTX: 'static,
COMP: Component<CTX> + Renderable<CTX, COMP>,
COMP: Component + Renderable<COMP>,
{
fn kind(&self) -> &'static str {
stringify!($action)
}

fn attach(&mut self, element: &Element, mut activator: Scope<CTX, COMP>)
fn attach(&mut self, element: &Element, mut activator: Scope<COMP>)
-> EventListenerHandle {
let handler = self.0.take().expect("tried to attach listener twice");
let this = element.clone();
@@ -190,18 +190,18 @@ macro_rules! html {
}};
}

type Stack<CTX, COMP> = Vec<VNode<CTX, COMP>>;
type Stack<COMP> = Vec<VNode<COMP>>;

#[doc(hidden)]
pub fn unpack<CTX, COMP: Component<CTX>>(mut stack: Stack<CTX, COMP>) -> VNode<CTX, COMP> {
pub fn unpack<COMP: Component>(mut stack: Stack<COMP>) -> VNode<COMP> {
if stack.len() != 1 {
panic!("exactly one element have to be in html!");
}
stack.pop().expect("no html elements in the stack")
}

#[doc(hidden)]
pub fn set_value_or_attribute<CTX, COMP: Component<CTX>, T: ToString>(stack: &mut Stack<CTX, COMP>, value: T) {
pub fn set_value_or_attribute<COMP: Component, T: ToString>(stack: &mut Stack<COMP>, value: T) {
if let Some(&mut VNode::VTag(ref mut vtag)) = stack.last_mut() {
if vtag.tag().eq_ignore_ascii_case("option") {
vtag.add_attribute("value", &value)
@@ -214,7 +214,7 @@ pub fn set_value_or_attribute<CTX, COMP: Component<CTX>, T: ToString>(stack: &mu
}

#[doc(hidden)]
pub fn set_kind<CTX, COMP: Component<CTX>, T: ToString>(stack: &mut Stack<CTX, COMP>, value: T) {
pub fn set_kind<COMP: Component, T: ToString>(stack: &mut Stack<COMP>, value: T) {
if let Some(&mut VNode::VTag(ref mut vtag)) = stack.last_mut() {
vtag.set_kind(&value);
} else {
@@ -223,7 +223,7 @@ pub fn set_kind<CTX, COMP: Component<CTX>, T: ToString>(stack: &mut Stack<CTX, C
}

#[doc(hidden)]
pub fn set_checked<CTX, COMP: Component<CTX>>(stack: &mut Stack<CTX, COMP>, value: bool) {
pub fn set_checked<COMP: Component>(stack: &mut Stack<COMP>, value: bool) {
if let Some(&mut VNode::VTag(ref mut vtag)) = stack.last_mut() {
vtag.set_checked(value);
} else {
@@ -232,8 +232,8 @@ pub fn set_checked<CTX, COMP: Component<CTX>>(stack: &mut Stack<CTX, COMP>, valu
}

#[doc(hidden)]
pub fn add_attribute<CTX, COMP: Component<CTX>, T: ToString>(
stack: &mut Stack<CTX, COMP>,
pub fn add_attribute<COMP: Component, T: ToString>(
stack: &mut Stack<COMP>,
name: &str,
value: T,
) {
@@ -245,7 +245,7 @@ pub fn add_attribute<CTX, COMP: Component<CTX>, T: ToString>(
}

#[doc(hidden)]
pub fn attach_class<CTX, COMP: Component<CTX>>(stack: &mut Stack<CTX, COMP>, class: &'static str) {
pub fn attach_class<COMP: Component>(stack: &mut Stack<COMP>, class: &'static str) {
if let Some(&mut VNode::VTag(ref mut vtag)) = stack.last_mut() {
vtag.add_classes(class);
} else {
@@ -254,9 +254,9 @@ pub fn attach_class<CTX, COMP: Component<CTX>>(stack: &mut Stack<CTX, COMP>, cla
}

#[doc(hidden)]
pub fn attach_listener<CTX, COMP: Component<CTX>>(
stack: &mut Stack<CTX, COMP>,
listener: Box<Listener<CTX, COMP>>,
pub fn attach_listener<COMP: Component>(
stack: &mut Stack<COMP>,
listener: Box<Listener<COMP>>,
) {
if let Some(&mut VNode::VTag(ref mut vtag)) = stack.last_mut() {
vtag.add_listener(listener);
@@ -266,7 +266,7 @@ pub fn attach_listener<CTX, COMP: Component<CTX>>(
}

#[doc(hidden)]
pub fn add_child<CTX, COMP: Component<CTX>>(stack: &mut Stack<CTX, COMP>, child: VNode<CTX, COMP>) {
pub fn add_child<COMP: Component>(stack: &mut Stack<COMP>, child: VNode<COMP>) {
match stack.last_mut() {
Some(&mut VNode::VTag(ref mut vtag)) => {
vtag.add_child(child);
@@ -281,8 +281,8 @@ pub fn add_child<CTX, COMP: Component<CTX>>(stack: &mut Stack<CTX, COMP>, child:
}

#[doc(hidden)]
pub fn child_to_parent<CTX, COMP: Component<CTX>>(
stack: &mut Stack<CTX, COMP>,
pub fn child_to_parent<COMP: Component>(
stack: &mut Stack<COMP>,
endtag: Option<&'static str>,
) {
if let Some(mut node) = stack.pop() {
Oops, something went wrong.

0 comments on commit 12bf3fd

Please sign in to comment.