before ptr
This commit is contained in:
parent
0e95823708
commit
ded42bef64
10 changed files with 141 additions and 62 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,2 +1,5 @@
|
||||||
/target
|
/target
|
||||||
**/*.rs.bk
|
**/*.rs.bk
|
||||||
|
|
||||||
|
graph.*
|
||||||
|
ouais.rs
|
|
@ -1,2 +1,3 @@
|
||||||
syn-serde
|
syn-serde
|
||||||
symbol
|
symbol
|
||||||
|
/ouais.rs
|
||||||
|
|
|
@ -24,7 +24,6 @@ pub fn build(component: &Component) -> TokenStream {
|
||||||
let mut visitor = Visitor::new();
|
let mut visitor = Visitor::new();
|
||||||
visitor.load_model(&component.model);
|
visitor.load_model(&component.model);
|
||||||
let tagged_dom = visitor.make_graph(&component.view);
|
let tagged_dom = visitor.make_graph(&component.view);
|
||||||
println!("New DOM: {:?}", tagged_dom);
|
|
||||||
let toplevel_names = visitor.gen_code(&tagged_dom);
|
let toplevel_names = visitor.gen_code(&tagged_dom);
|
||||||
|
|
||||||
// output the "model"
|
// output the "model"
|
||||||
|
@ -60,15 +59,16 @@ pub fn build(component: &Component) -> TokenStream {
|
||||||
for fn_name in toplevel_names.iter() {
|
for fn_name in toplevel_names.iter() {
|
||||||
let fn_name = format_ident!("{}", fn_name);
|
let fn_name = format_ident!("{}", fn_name);
|
||||||
init_el_code.extend(quote! {
|
init_el_code.extend(quote! {
|
||||||
{
|
let sub = self.#fn_name();
|
||||||
use enterprise::stdweb::web::INode;
|
el.append_child(&sub);
|
||||||
let sub = self.#fn_name();
|
|
||||||
el.append_child(&sub);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
|
use enterprise::std::List;
|
||||||
|
use enterprise::stdweb::web::{INode, IElement, Node, IEventTarget};
|
||||||
|
use crate::enterprise::stdweb::unstable::TryFrom;
|
||||||
|
|
||||||
pub struct #name<B> {
|
pub struct #name<B> {
|
||||||
_b: std::marker::PhantomData<B>,
|
_b: std::marker::PhantomData<B>,
|
||||||
#model
|
#model
|
||||||
|
@ -86,8 +86,10 @@ pub fn build(component: &Component) -> TokenStream {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B: enterprise::Backend> enterprise::Component<B> for #name<B> {
|
impl<B: enterprise::Backend> enterprise::Component<B> for #name<B> {
|
||||||
fn create(&self, el: &enterprise::stdweb::web::Element) {
|
fn render(&self) -> Node {
|
||||||
|
let el = enterprise::stdweb::web::document().create_element("div").unwrap();
|
||||||
#init_el_code
|
#init_el_code
|
||||||
|
el.as_node().clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -158,10 +158,24 @@ impl<T: ToTokens> ToTokens for Elem<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type Context = BTreeMap<Id, ContextVar>;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub enum ContextVar {
|
||||||
|
Model(ModelValue),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub enum ModelValue {
|
||||||
|
Index(Box<ModelValue>, Symbol),
|
||||||
|
Leaf(Symbol),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// "Rust + XML", taken from JSX: This represents a node in a DOM tree
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub enum Rsx {
|
pub enum Rsx {
|
||||||
Elem(Elem<Rsx>),
|
Elem(Elem<Rsx>),
|
||||||
Code(Expr),
|
Code(Context, Expr),
|
||||||
Text(String),
|
Text(String),
|
||||||
ForLoop(Pat, Expr, Vec<Rsx>),
|
ForLoop(Pat, Expr, Vec<Rsx>),
|
||||||
|
|
||||||
|
@ -173,7 +187,8 @@ impl PartialEq<Rsx> for Rsx {
|
||||||
fn eq(&self, other: &Rsx) -> bool {
|
fn eq(&self, other: &Rsx) -> bool {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(Rsx::Elem(this), Rsx::Elem(other)) => this == other,
|
(Rsx::Elem(this), Rsx::Elem(other)) => this == other,
|
||||||
(Rsx::Code(expr), Rsx::Code(other)) => {
|
(Rsx::Code(ctx, expr), Rsx::Code(ctx2, other)) => {
|
||||||
|
ctx == ctx2 &&
|
||||||
syn::Expr::from_adapter(expr) == syn::Expr::from_adapter(other)
|
syn::Expr::from_adapter(expr) == syn::Expr::from_adapter(other)
|
||||||
}
|
}
|
||||||
(Rsx::Text(this), Rsx::Text(other)) => this == other,
|
(Rsx::Text(this), Rsx::Text(other)) => this == other,
|
||||||
|
@ -190,7 +205,7 @@ impl ToTokens for Rsx {
|
||||||
Rsx::Elem(elem) => {
|
Rsx::Elem(elem) => {
|
||||||
stream.extend(quote!(#elem));
|
stream.extend(quote!(#elem));
|
||||||
}
|
}
|
||||||
Rsx::Code(expr) => {
|
Rsx::Code(_, expr) => {
|
||||||
let expr = syn::Expr::from_adapter(expr);
|
let expr = syn::Expr::from_adapter(expr);
|
||||||
stream.extend(quote!({ #expr }));
|
stream.extend(quote!({ #expr }));
|
||||||
}
|
}
|
||||||
|
@ -212,10 +227,11 @@ impl ToTokens for Rsx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The same as RSX, except at this point every node has been assigned an ID.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum TaggedRsx {
|
pub enum TaggedRsx {
|
||||||
Elem(Id, Elem<TaggedRsx>),
|
Elem(Id, Elem<TaggedRsx>),
|
||||||
Code(Id, Box<Expr>),
|
Code(Id, Context, Box<Expr>),
|
||||||
Text(Id, String),
|
Text(Id, String),
|
||||||
ForLoop(Id, Pat, Expr, Vec<TaggedRsx>),
|
ForLoop(Id, Pat, Expr, Vec<TaggedRsx>),
|
||||||
|
|
||||||
|
@ -227,10 +243,38 @@ impl TaggedRsx {
|
||||||
pub fn get_id(&self) -> Id {
|
pub fn get_id(&self) -> Id {
|
||||||
match self {
|
match self {
|
||||||
TaggedRsx::Elem(id, _)
|
TaggedRsx::Elem(id, _)
|
||||||
| TaggedRsx::Code(id, _)
|
| TaggedRsx::Code(id, _, _)
|
||||||
| TaggedRsx::Text(id, _)
|
| TaggedRsx::Text(id, _)
|
||||||
| TaggedRsx::ForLoop(id, _, _, _) => *id,
|
| TaggedRsx::ForLoop(id, _, _, _) => *id,
|
||||||
_ => unimplemented!("tagged rsx"),
|
_ => unimplemented!("tagged rsx"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ToTokens for TaggedRsx {
|
||||||
|
fn to_tokens(&self, stream: &mut TokenStream) {
|
||||||
|
match self {
|
||||||
|
TaggedRsx::Elem(_, elem) => {
|
||||||
|
stream.extend(quote!(#elem));
|
||||||
|
}
|
||||||
|
TaggedRsx::Code(_, _, expr) => {
|
||||||
|
let expr = syn::Expr::from_adapter(expr);
|
||||||
|
stream.extend(quote!({ #expr }));
|
||||||
|
}
|
||||||
|
TaggedRsx::Text(_, string) => {
|
||||||
|
let string = syn::Lit::Str(syn::LitStr::new(string.as_ref(), Span::call_site()));
|
||||||
|
stream.extend(quote!(#string));
|
||||||
|
}
|
||||||
|
TaggedRsx::ForLoop(_, pat, expr, inner) => {
|
||||||
|
let expr = syn::Expr::from_adapter(expr);
|
||||||
|
let pat = syn::Pat::from_adapter(pat);
|
||||||
|
let mut inner_stream = TokenStream::new();
|
||||||
|
for rsx in inner {
|
||||||
|
inner_stream.extend(rsx.to_token_stream());
|
||||||
|
}
|
||||||
|
stream.extend(quote!([ for #pat in #expr ] #inner_stream [ / for ]));
|
||||||
|
}
|
||||||
|
TaggedRsx::_Nonexhaustive => unreachable!("should never be constructed"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -35,6 +35,7 @@ prop_compose! {
|
||||||
pub fn arbitrary_view() -> impl Strategy<Value = Rsx> {
|
pub fn arbitrary_view() -> impl Strategy<Value = Rsx> {
|
||||||
let leaf = prop_oneof![
|
let leaf = prop_oneof![
|
||||||
Just(Rsx::Code(
|
Just(Rsx::Code(
|
||||||
|
BTreeMap::new(),
|
||||||
syn::parse_str::<Expr>("()").unwrap().to_adapter()
|
syn::parse_str::<Expr>("()").unwrap().to_adapter()
|
||||||
)),
|
)),
|
||||||
string_regex(r"[:print:]+").unwrap().prop_map(Rsx::Text),
|
string_regex(r"[:print:]+").unwrap().prop_map(Rsx::Text),
|
||||||
|
|
|
@ -8,9 +8,9 @@ use quote::ToTokens;
|
||||||
use syn::{Expr, Type};
|
use syn::{Expr, Type};
|
||||||
use syn_serde::Syn;
|
use syn_serde::Syn;
|
||||||
|
|
||||||
use crate::model::{Elem, Id, ModelMap, Rsx, TagLhs, TagRhs, TaggedRsx};
|
use crate::model::{Elem, Id, ModelValue, ModelMap, Rsx, ContextVar, TagLhs, TagRhs, TaggedRsx};
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
use crate::Symbol;
|
use crate::{Symbol};
|
||||||
|
|
||||||
/// A node within the dependency graph.
|
/// A node within the dependency graph.
|
||||||
#[derive(Copy, Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]
|
||||||
|
@ -40,12 +40,6 @@ pub enum DepAction {
|
||||||
SubmitEvt,
|
SubmitEvt,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]
|
|
||||||
pub enum ModelValue {
|
|
||||||
Index(Symbol, Symbol),
|
|
||||||
Leaf(Symbol),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DepNode {
|
impl DepNode {
|
||||||
// Generates code for when this updates
|
// Generates code for when this updates
|
||||||
fn gen_update_code(&self, updates: &mut TokenStream, update_func: &mut TokenStream) {
|
fn gen_update_code(&self, updates: &mut TokenStream, update_func: &mut TokenStream) {
|
||||||
|
@ -57,20 +51,14 @@ impl DepNode {
|
||||||
let #inner_lock = self.#sym_name.clone();
|
let #inner_lock = self.#sym_name.clone();
|
||||||
});
|
});
|
||||||
update_func.extend(quote! {
|
update_func.extend(quote! {
|
||||||
{
|
enterprise::ValueUpdatable::update(#inner_lock, new_value);
|
||||||
let mut locked = #inner_lock.lock();
|
|
||||||
*locked = new_value.clone();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
DepNode::RsxSpan(id) => {
|
DepNode::RsxSpan(id) => {
|
||||||
let id_str = id.as_str();
|
let id_str = id.as_str();
|
||||||
update_func.extend(quote! {
|
update_func.extend(quote! {
|
||||||
{
|
if let Some(target) = enterprise::stdweb::web::document().get_element_by_id(#id_str) {
|
||||||
use enterprise::stdweb::web::{INonElementParentNode, INode};
|
target.set_text_content(&new_value.clone());
|
||||||
if let Some(target) = enterprise::stdweb::web::document().get_element_by_id(#id_str) {
|
|
||||||
target.set_text_content(&new_value.clone());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -85,7 +73,7 @@ impl DepNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type DependencyGraph = DiGraphMap<DepNode, DepAction>;
|
type DependencyGraph = DiGraphMap<Ptr<DepNode>, DepAction>;
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub struct Visitor {
|
pub struct Visitor {
|
||||||
|
@ -138,7 +126,6 @@ impl Visitor {
|
||||||
.add_edge(attr_node, model_node, DepAction::ValueChange);
|
.add_edge(attr_node, model_node, DepAction::ValueChange);
|
||||||
self.deps
|
self.deps
|
||||||
.add_edge(model_node, attr_node, DepAction::ValueChange);
|
.add_edge(model_node, attr_node, DepAction::ValueChange);
|
||||||
println!("Added elem attr to graph {:?} {:?}", attr_node, model_node);
|
|
||||||
if let Some(set) = self.elem_attr_map.get_mut(&node_id) {
|
if let Some(set) = self.elem_attr_map.get_mut(&node_id) {
|
||||||
set.insert(Symbol::from(attr));
|
set.insert(Symbol::from(attr));
|
||||||
} else {
|
} else {
|
||||||
|
@ -169,7 +156,12 @@ impl Visitor {
|
||||||
let actual_expr = if let syn::Expr::Closure(syn::ExprClosure { inputs, body, .. }) = expr {
|
let actual_expr = if let syn::Expr::Closure(syn::ExprClosure { inputs, body, .. }) = expr {
|
||||||
let mut has_io = false;
|
let mut has_io = false;
|
||||||
for arg in inputs.iter() {
|
for arg in inputs.iter() {
|
||||||
if let syn::Pat::Ident(syn::PatIdent { ident, subpat: Some((_, subpat)), ..} ) = arg {
|
if let syn::Pat::Ident(syn::PatIdent {
|
||||||
|
ident,
|
||||||
|
subpat: Some((_, subpat)),
|
||||||
|
..
|
||||||
|
}) = arg
|
||||||
|
{
|
||||||
let bind = ident.to_string();
|
let bind = ident.to_string();
|
||||||
match (bind.as_ref(), &(**subpat)) {
|
match (bind.as_ref(), &(**subpat)) {
|
||||||
("i", syn::Pat::Ident(syn::PatIdent { ident, .. })) => {
|
("i", syn::Pat::Ident(syn::PatIdent { ident, .. })) => {
|
||||||
|
@ -203,7 +195,7 @@ impl Visitor {
|
||||||
expr.clone()
|
expr.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
self.code_segments.insert(code_node_id, expr.clone());
|
self.code_segments.insert(code_node_id, actual_expr.clone());
|
||||||
|
|
||||||
// look for model references in the code segment
|
// look for model references in the code segment
|
||||||
// let names = self.get_model_names();
|
// let names = self.get_model_names();
|
||||||
|
@ -239,7 +231,7 @@ impl Visitor {
|
||||||
}
|
}
|
||||||
// Code changes are dependent on variables within the code segment in the model
|
// Code changes are dependent on variables within the code segment in the model
|
||||||
// Every time the model changes, the code segment must re-evaluate
|
// Every time the model changes, the code segment must re-evaluate
|
||||||
Rsx::Code(expr) => {
|
Rsx::Code(ctx, expr) => {
|
||||||
let syn_expr = Syn::from_adapter(&*expr);
|
let syn_expr = Syn::from_adapter(&*expr);
|
||||||
let names = self.get_model_names();
|
let names = self.get_model_names();
|
||||||
let deps = self.extract_model_dependencies_from_expr(&syn_expr, &names);
|
let deps = self.extract_model_dependencies_from_expr(&syn_expr, &names);
|
||||||
|
@ -249,7 +241,7 @@ impl Visitor {
|
||||||
self.deps.add_edge(from, to, DepAction::ValueChange);
|
self.deps.add_edge(from, to, DepAction::ValueChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
TaggedRsx::Code(node_id, Box::new(syn_expr.clone().to_adapter()))
|
TaggedRsx::Code(node_id, ctx.clone(), Box::new(syn_expr.clone().to_adapter()))
|
||||||
}
|
}
|
||||||
Rsx::Text(literal) => TaggedRsx::Text(node_id, literal.clone()),
|
Rsx::Text(literal) => TaggedRsx::Text(node_id, literal.clone()),
|
||||||
// Process a for-loop
|
// Process a for-loop
|
||||||
|
@ -284,7 +276,6 @@ impl Visitor {
|
||||||
// - Using the List iterator, there's an update method that uses keys
|
// - Using the List iterator, there's an update method that uses keys
|
||||||
for child in inner {
|
for child in inner {
|
||||||
let deps = self.extract_rsx_dependents(&child, &names);
|
let deps = self.extract_rsx_dependents(&child, &names);
|
||||||
println!("children: {:?} {:?} => {:?}", names, child, deps);
|
|
||||||
let from = DepNode::Iterator(node_id);
|
let from = DepNode::Iterator(node_id);
|
||||||
for dep in deps {
|
for dep in deps {
|
||||||
self.deps.add_edge(from, dep, DepAction::ValueChange);
|
self.deps.add_edge(from, dep, DepAction::ValueChange);
|
||||||
|
@ -315,15 +306,11 @@ impl Visitor {
|
||||||
let mut update_func = TokenStream::new();
|
let mut update_func = TokenStream::new();
|
||||||
while let Some(nx) = dfs.next(&self.deps) {
|
while let Some(nx) = dfs.next(&self.deps) {
|
||||||
if nx != starting {
|
if nx != starting {
|
||||||
nx.gen_update_code(
|
nx.gen_update_code(&mut updates, &mut update_func);
|
||||||
&mut updates,
|
|
||||||
&mut update_func,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updates.extend(quote! {
|
updates.extend(quote! {
|
||||||
{
|
{
|
||||||
use enterprise::stdweb::{web::IEventTarget, unstable::TryFrom};
|
|
||||||
let inner_el = el.clone();
|
let inner_el = el.clone();
|
||||||
el.add_event_listener(move |evt: enterprise::stdweb::web::event::InputEvent| {
|
el.add_event_listener(move |evt: enterprise::stdweb::web::event::InputEvent| {
|
||||||
let new_value = enterprise::stdweb::web::html_element::InputElement::try_from(inner_el.clone()).unwrap().raw_value();
|
let new_value = enterprise::stdweb::web::html_element::InputElement::try_from(inner_el.clone()).unwrap().raw_value();
|
||||||
|
@ -333,14 +320,14 @@ impl Visitor {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let elem_as_str = format!("{}", node.to_token_stream());
|
||||||
self.impl_code.extend(quote! {
|
self.impl_code.extend(quote! {
|
||||||
/// Rsx::Elem
|
#[doc = #elem_as_str]
|
||||||
fn #make_node_id(&self) -> enterprise::stdweb::web::Node {
|
fn #make_node_id(&self) -> enterprise::stdweb::web::Node {
|
||||||
use enterprise::stdweb::web::IElement;
|
|
||||||
let el = enterprise::stdweb::web::document().create_element(#tag).unwrap();
|
let el = enterprise::stdweb::web::document().create_element(#tag).unwrap();
|
||||||
el.set_attribute("id", #node_str).unwrap();
|
el.set_attribute("id", #node_str).unwrap();
|
||||||
#updates
|
#updates
|
||||||
el.as_node()
|
el.as_node().clone()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if let Some(inner) = inner {
|
if let Some(inner) = inner {
|
||||||
|
@ -348,9 +335,34 @@ impl Visitor {
|
||||||
}
|
}
|
||||||
names.push(format!("{}", make_node_id));
|
names.push(format!("{}", make_node_id));
|
||||||
}
|
}
|
||||||
TaggedRsx::Code(_, expr) => {
|
TaggedRsx::Code(_, ctx, expr) => {
|
||||||
let expr = syn::Expr::from_adapter(expr);
|
let expr = syn::Expr::from_adapter(expr);
|
||||||
let code_id = format_ident!("code_{}", node_str);
|
let code_id = format_ident!("code_{}", node_str);
|
||||||
|
|
||||||
|
let mut init_code = TokenStream::new();
|
||||||
|
for (id, ctxvar) in ctx.iter() {
|
||||||
|
let id = format_ident!("{}", id.to_string());
|
||||||
|
init_code.extend(quote!(let #id =));
|
||||||
|
match ctxvar {
|
||||||
|
ContextVar::Model(model_value) => {
|
||||||
|
// let line = Indexable::index(self.todos, key)
|
||||||
|
fn generate_model_value_code(val: &ModelValue) -> TokenStream {
|
||||||
|
match val {
|
||||||
|
ModelValue::Leaf(sym) => {
|
||||||
|
let name = format_ident!("{}", sym.to_string());
|
||||||
|
quote!(self . #name)
|
||||||
|
}
|
||||||
|
ModelValue::Index(val, idx) => {
|
||||||
|
let idx = format_ident!("{}", idx.to_string());
|
||||||
|
let val = generate_model_value_code(val);
|
||||||
|
quote!(Indexable :: index ( #val , #idx ))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.impl_code.extend(quote! {
|
self.impl_code.extend(quote! {
|
||||||
/// Actual code
|
/// Actual code
|
||||||
fn #code_id(&self) -> impl std::string::ToString {
|
fn #code_id(&self) -> impl std::string::ToString {
|
||||||
|
@ -359,10 +371,9 @@ impl Visitor {
|
||||||
|
|
||||||
/// Code
|
/// Code
|
||||||
fn #make_node_id(&self) -> enterprise::stdweb::web::Node {
|
fn #make_node_id(&self) -> enterprise::stdweb::web::Node {
|
||||||
use enterprise::stdweb::web::IElement;
|
|
||||||
let el = enterprise::stdweb::web::document().create_element("span").expect("shouldn't fail");
|
let el = enterprise::stdweb::web::document().create_element("span").expect("shouldn't fail");
|
||||||
el.set_attribute("id", #node_str).unwrap();
|
el.set_attribute("id", #node_str).unwrap();
|
||||||
el.as_node()
|
el.as_node().clone()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
names.push(format!("{}", make_node_id));
|
names.push(format!("{}", make_node_id));
|
||||||
|
@ -387,20 +398,20 @@ impl Visitor {
|
||||||
let name = format_ident!("{}", name);
|
let name = format_ident!("{}", name);
|
||||||
func_calls.extend(quote! {
|
func_calls.extend(quote! {
|
||||||
let sub = self.#name();
|
let sub = self.#name();
|
||||||
el.append_child(sub);
|
el.append_child(&sub);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
self.impl_code.extend(quote! {
|
self.impl_code.extend(quote! {
|
||||||
/// Initialize for-loop
|
/// Initialize for-loop
|
||||||
fn #init_loop_id(&self) -> enterprise::stdweb::web::Node {
|
fn #init_loop_id(&self) -> enterprise::stdweb::web::Node {
|
||||||
let el = enterprise::stdweb::web::document().create_element("div").expect("shouldn't fail");
|
let el = enterprise::stdweb::web::document().create_element("div").expect("shouldn't fail");
|
||||||
#func_calls
|
#func_calls
|
||||||
el.as_node()
|
el.as_node().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update for-loop
|
/// Update for-loop
|
||||||
fn #update_loop_id(&self) {
|
fn #update_loop_id(&self) {
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
names.push(format!("{}", init_loop_id));
|
names.push(format!("{}", init_loop_id));
|
||||||
|
@ -417,7 +428,6 @@ impl Visitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_rsx_dependents(&self, rsx: &Rsx, names: &HashSet<Symbol>) -> HashSet<DepNode> {
|
fn extract_rsx_dependents(&self, rsx: &Rsx, names: &HashSet<Symbol>) -> HashSet<DepNode> {
|
||||||
println!(">>>>>>>>>>>>Extract rsx from {:?}", rsx);
|
|
||||||
let mut result = HashSet::new();
|
let mut result = HashSet::new();
|
||||||
match rsx {
|
match rsx {
|
||||||
Rsx::Elem(elem) => {
|
Rsx::Elem(elem) => {
|
||||||
|
@ -427,7 +437,7 @@ impl Visitor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Rsx::Code(code) => {
|
Rsx::Code(_, code) => {
|
||||||
let code = syn::Expr::from_adapter(code);
|
let code = syn::Expr::from_adapter(code);
|
||||||
let code_deps = self
|
let code_deps = self
|
||||||
.extract_model_dependencies_from_expr(&code, names)
|
.extract_model_dependencies_from_expr(&code, names)
|
||||||
|
@ -443,7 +453,6 @@ impl Visitor {
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
println!("<<<<<<<<<<<<{:?}", result);
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -453,7 +462,6 @@ impl Visitor {
|
||||||
expr: &Expr,
|
expr: &Expr,
|
||||||
names: &HashSet<Symbol>,
|
names: &HashSet<Symbol>,
|
||||||
) -> HashSet<Symbol> {
|
) -> HashSet<Symbol> {
|
||||||
println!("Extracting {}", expr.to_token_stream());
|
|
||||||
let tokens = expr.to_token_stream();
|
let tokens = expr.to_token_stream();
|
||||||
let mut result = HashSet::new();
|
let mut result = HashSet::new();
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ component! {
|
||||||
}
|
}
|
||||||
|
|
||||||
view {
|
view {
|
||||||
<input bind:value="value" on:submit={|i@value, o@todos| { todos.push(value); }} />
|
<input bind:value="value" on:submit={|o@todos| { todos.push(value); value = ""; }} />
|
||||||
<ul>
|
<ul>
|
||||||
[for (key, line) in todos]
|
[for (key, line) in todos]
|
||||||
<li>{line} <a on:click={|o@todos| { todos.remove(key); }}>"[x]"</a></li>
|
<li>{line} <a on:click={|o@todos| { todos.remove(key); }}>"[x]"</a></li>
|
||||||
|
@ -26,6 +26,10 @@ component! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pub mod enterprise {
|
||||||
|
// include!("../../ouais.rs");
|
||||||
|
// }
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let component: Component = serde_json::from_str(TodoMVC.as_ref()).unwrap();
|
let component: Component = serde_json::from_str(TodoMVC.as_ref()).unwrap();
|
||||||
|
|
||||||
|
|
|
@ -9,10 +9,10 @@ component! {
|
||||||
}
|
}
|
||||||
|
|
||||||
view {
|
view {
|
||||||
<input bind:value="value" on:submit={|| { todos.push(todo); }} />
|
<input bind:value="value" on:submit={|o@todos| { todos.push(value); value = ""; }} />
|
||||||
<ul>
|
<ul>
|
||||||
[for (key, todo) in todos]
|
[for (key, line) in todos]
|
||||||
<li>{todo} <a on:click={|_| { todos.remove(key); }}>"[x]"</a></li>
|
<li>{line} <a on:click={|o@todos| { todos.remove(key); }}>"[x]"</a></li>
|
||||||
[/for]
|
[/for]
|
||||||
</ul>
|
</ul>
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::backend::Node;
|
use crate::backend::Node;
|
||||||
use stdweb::web::{document, INonElementParentNode, Node as WebNode};
|
use stdweb::web::{document, INode, INonElementParentNode, Node as WebNode};
|
||||||
|
|
||||||
use crate::backend::Backend;
|
use crate::backend::Backend;
|
||||||
use crate::Component;
|
use crate::Component;
|
||||||
|
@ -13,8 +13,8 @@ impl Backend for Web {
|
||||||
fn initialize<C: Component<Self>>(&self, component: C, params: Self::InitParams) {
|
fn initialize<C: Component<Self>>(&self, component: C, params: Self::InitParams) {
|
||||||
let id = params.as_ref();
|
let id = params.as_ref();
|
||||||
if let Some(el) = document().get_element_by_id(id) {
|
if let Some(el) = document().get_element_by_id(id) {
|
||||||
// component.render(&el);
|
let sub = component.render();
|
||||||
component.render();
|
el.append_child(&sub);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
18
src/lib.rs
18
src/lib.rs
|
@ -1,6 +1,7 @@
|
||||||
//! Enterprise is a backend-agnostic framework for developing server-client GUI applications.
|
//! Enterprise is a backend-agnostic framework for developing server-client GUI applications.
|
||||||
|
|
||||||
pub extern crate enterprise_compiler;
|
pub extern crate enterprise_compiler;
|
||||||
|
extern crate std as rust_std;
|
||||||
|
|
||||||
// re-exports
|
// re-exports
|
||||||
pub extern crate parking_lot;
|
pub extern crate parking_lot;
|
||||||
|
@ -11,6 +12,11 @@ pub mod std;
|
||||||
|
|
||||||
mod forloop;
|
mod forloop;
|
||||||
|
|
||||||
|
use rust_std::sync::Arc;
|
||||||
|
|
||||||
|
use parking_lot::Mutex;
|
||||||
|
use stdweb::web::Node;
|
||||||
|
|
||||||
pub use crate::backend::{Backend, Web};
|
pub use crate::backend::{Backend, Web};
|
||||||
|
|
||||||
/// Components are the building-blocks of enterprise applications.
|
/// Components are the building-blocks of enterprise applications.
|
||||||
|
@ -18,7 +24,7 @@ pub trait Component<B: Backend> {
|
||||||
/// TODO: replace this with a real init function.
|
/// TODO: replace this with a real init function.
|
||||||
// fn create(&self, el: &crate::stdweb::web::Element);
|
// fn create(&self, el: &crate::stdweb::web::Element);
|
||||||
|
|
||||||
fn render(&self) -> B::NodeType;
|
fn render(&self) -> Node;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Declares a mod
|
/// Declares a mod
|
||||||
|
@ -30,3 +36,13 @@ macro_rules! enterprise_mod {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait ValueUpdatable {
|
||||||
|
fn update(_: Arc<Mutex<Self>>, _: String);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ValueUpdatable for String {
|
||||||
|
fn update(value_ref: Arc<Mutex<Self>>, new_value: String) {
|
||||||
|
*value_ref.lock() = new_value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue