WIP new api

This commit is contained in:
Evan Almloff 2022-04-08 21:17:37 -05:00
parent 3dd18b21b3
commit 92f48169e9
7 changed files with 422 additions and 1 deletions

View file

@ -29,6 +29,7 @@ dioxus-tui = { path = "./packages/tui", version = "^0.2.0", optional = true }
dioxus-liveview = { path = "./packages/liveview", optional = true }
dioxus-native-core = { path = "./packages/native-core", optional = true }
dioxus-native-core-macro = { path = "./packages/native-core-macro", optional = true }
# dioxus-mobile = { path = "./packages/mobile", version = "^0.2.0", optional = true }
# dioxus-rsx = { path = "./packages/rsx", optional = true }
@ -47,7 +48,7 @@ ayatana = ["dioxus-desktop/ayatana"]
router = ["dioxus-router"]
tui = ["dioxus-tui"]
liveview = ["dioxus-liveview"]
native-core = ["dioxus-native-core"]
native-core = ["dioxus-native-core", "dioxus-native-core-macro"]
[workspace]

View file

@ -0,0 +1,12 @@
[package]
name = "dioxus-native-core-macro"
version = "0.2.0"
edition = "2021"
[lib]
proc-macro = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
syn = { version = "1.0.11", features = ["extra-traits"] }
quote = "1.0"

View file

@ -0,0 +1,285 @@
extern crate proc_macro;
use proc_macro::TokenStream;
use quote::{quote, ToTokens};
use syn::{
self,
parse::{Parse, ParseStream},
Field, Ident, Token, Type,
};
#[derive(PartialEq)]
enum DepKind {
NodeDepState,
ChildDepState,
ParentDepState,
}
// macro that streams data from the State for any attributes that end with _
#[proc_macro_derive(State, attributes(node_dep_state, child_dep_state, parent_dep_state))]
pub fn state_macro_derive(input: TokenStream) -> TokenStream {
let ast = syn::parse(input).unwrap();
impl_derive_macro(&ast)
}
fn impl_derive_macro(ast: &syn::DeriveInput) -> TokenStream {
let type_name = &ast.ident;
let fields: Vec<_> = match &ast.data {
syn::Data::Struct(data) => match &data.fields {
syn::Fields::Named(e) => &e.named,
syn::Fields::Unnamed(_) => todo!("unnamed fields"),
syn::Fields::Unit => todo!("unit fields"),
}
.iter()
.collect(),
_ => unimplemented!(),
};
let strct = Struct::parse(&fields);
let state_strct = StateStruct::parse(&fields, &strct);
let node_dep_state_fields = quote::__private::TokenStream::from_iter(
state_strct
.state_members
.iter()
.filter(|f| f.dep_kind == DepKind::NodeDepState)
.map(|f| {
let ty_id = &f.type_id();
let reduce = &f.reduce_self();
quote! {
else if ty == #ty_id {
#reduce
}
}
}),
);
let child_dep_state_fields = quote::__private::TokenStream::from_iter(
state_strct
.state_members
.iter()
.filter(|f| f.dep_kind == DepKind::ChildDepState)
.map(|f| {
let ty_id = &f.type_id();
let reduce = &f.reduce_self();
quote! {
else if ty == #ty_id {
#reduce
}
}
}),
);
let parent_dep_state_fields = quote::__private::TokenStream::from_iter(
state_strct
.state_members
.iter()
.filter(|f| f.dep_kind == DepKind::ParentDepState)
.map(|f| {
let ty_id = &f.type_id();
let reduce = &f.reduce_self();
quote! {
else if ty == #ty_id {
#reduce
}
}
}),
);
let node_types = state_strct
.state_members
.iter()
.filter(|f| f.dep_kind == DepKind::NodeDepState)
.map(|f| f.type_id());
let child_types = state_strct
.state_members
.iter()
.filter(|f| f.dep_kind == DepKind::ChildDepState)
.map(|f| f.type_id());
let parent_types = state_strct
.state_members
.iter()
.filter(|f| f.dep_kind == DepKind::ParentDepState)
.map(|f| f.type_id());
let type_name_str = type_name.to_string();
let gen = quote! {
impl State for #type_name{
fn update_node_dep_state(&mut self, ty: std::any::TypeId, node: dioxus_native_core::real_dom_new_api::NodeRef, ctx: &anymap::AnyMap){
use dioxus_native_core::real_dom_new_api::NodeDepState;
if false {}
#node_dep_state_fields
else{
panic!("{:?} not in {}", ty, #type_name_str);
}
}
fn update_parent_dep_state(&mut self, ty: std::any::TypeId, node: dioxus_native_core::real_dom_new_api::NodeRef, parent: &Self, ctx: &anymap::AnyMap){
use dioxus_native_core::real_dom_new_api::ParentDepState;
if false {}
#parent_dep_state_fields
else{
panic!("{:?} not in {}", ty, #type_name_str);
}
}
fn update_child_dep_state(&mut self, ty: std::any::TypeId, node: dioxus_native_core::real_dom_new_api::NodeRef, children: Vec<&Self>, ctx: &anymap::AnyMap){
use dioxus_native_core::real_dom_new_api::ChildDepState;
if false {}
#child_dep_state_fields
else{
panic!("{:?} not in {}", ty, #type_name_str);
}
}
fn child_dep_types(&self) -> Vec<std::any::TypeId>{
// todo: order should depend on order of dependencies
vec![
#(#child_types,)*
]
}
fn parent_dep_types(&self) -> Vec<std::any::TypeId>{
// todo: order should depend on order of dependencies
vec![
#(#parent_types,)*
]
}
fn node_dep_types(&self) -> Vec<std::any::TypeId>{
vec![
#(#node_types,)*
]
}
}
};
gen.into()
}
struct Struct {
members: Vec<Member>,
}
impl Struct {
fn parse(fields: &[&Field]) -> Self {
let members = fields.iter().filter_map(|f| Member::parse(f)).collect();
Self { members }
}
}
struct StateStruct<'a> {
state_members: Vec<StateMember<'a>>,
}
impl<'a> StateStruct<'a> {
fn parse(fields: &[&'a Field], strct: &'a Struct) -> Self {
let state_members = strct
.members
.iter()
.zip(fields.iter())
.filter_map(|(m, f)| StateMember::parse(f, m, &strct))
.collect();
Self { state_members }
}
}
struct DepTypes {
ctx_ty: Option<Type>,
dep_ty: Option<Type>,
}
impl Parse for DepTypes {
fn parse(input: ParseStream) -> Result<DepTypes, syn::Error> {
let ctx_ty = input.parse::<Type>().ok();
let comma = input.parse::<Token![,]>().ok();
let dep_ty = input.parse::<Type>().ok();
let dep_ty = comma.and(dep_ty);
Ok(DepTypes { ctx_ty, dep_ty })
}
}
struct Member {
ty: Type,
ident: Ident,
}
impl Member {
fn parse(field: &Field) -> Option<Self> {
Some(Self {
ty: field.ty.clone(),
ident: field.ident.as_ref()?.clone(),
})
}
}
struct StateMember<'a> {
mem: &'a Member,
dep_kind: DepKind,
dep_mem: Option<&'a Member>,
ctx_ty: Option<Type>,
}
impl<'a> StateMember<'a> {
fn parse(field: &Field, mem: &'a Member, parent: &'a Struct) -> Option<StateMember<'a>> {
field.attrs.iter().find_map(|a| {
let dep_kind = a
.path
.get_ident()
.map(|i| match i.to_string().as_str() {
"node_dep_state" => Some(DepKind::NodeDepState),
"child_dep_state" => Some(DepKind::ChildDepState),
"parent_dep_state" => Some(DepKind::ParentDepState),
_ => None,
})
.flatten()?;
let deps: DepTypes = a.parse_args().ok()?;
Some(Self {
mem,
dep_kind,
dep_mem: deps
.dep_ty
.map(|ty| parent.members.iter().find(|m| m.ty == ty))
.flatten(),
ctx_ty: deps.ctx_ty,
})
})
}
fn reduce_self(&self) -> quote::__private::TokenStream {
let ident = &self.mem.ident;
let get_ctx = if let Some(ctx_ty) = &self.ctx_ty {
let msg = ctx_ty.to_token_stream().to_string() + " not found in context";
quote! {ctx.get().expect(#msg)}
} else {
quote! {&()}
};
if let Some(dep_ident) = &self.dep_mem.map(|m| &m.ident) {
match self.dep_kind {
DepKind::NodeDepState => {
quote!(self.#ident.reduce(node, #get_ctx);)
}
DepKind::ChildDepState => {
quote!(self.#ident.reduce(node, children.iter().map(|s| &s.#dep_ident).collect(), #get_ctx);)
}
DepKind::ParentDepState => {
quote!(self.#ident.reduce(node, &parent.#dep_ident, #get_ctx);)
}
}
} else {
match self.dep_kind {
DepKind::NodeDepState => {
quote!(self.#ident.reduce(node, #get_ctx);)
}
DepKind::ChildDepState => {
quote!(self.#ident.reduce(node, &(), #get_ctx);)
}
DepKind::ParentDepState => {
quote!(self.#ident.reduce(node, &(), #get_ctx);)
}
}
}
}
fn type_id(&self) -> quote::__private::TokenStream {
let ty = &self.mem.ty;
quote!(std::any::TypeId::of::<#ty>())
}
}

View file

@ -10,10 +10,12 @@ homepage = "https://dioxuslabs.com"
dioxus-core = { path = "../core", version = "^0.2.0" }
dioxus-html = { path = "../html", version = "^0.2.0" }
dioxus-core-macro = { path = "../core-macro", version = "^0.2.0" }
dioxus-native-core-macro = { path = "../native-core-macro", version = "^0.2.0" }
stretch2 = { git = "https://github.com/DioxusLabs/stretch" }
smallvec = "1.6"
fxhash = "0.2"
anymap = "0.12.1"
[dev-dependencies]
rand = "0.8.5"

View file

@ -1,2 +1,3 @@
pub mod layout_attributes;
pub mod real_dom;
pub mod real_dom_new_api;

View file

@ -0,0 +1,58 @@
use std::any::TypeId;
use anymap::AnyMap;
use dioxus_core::{Attribute, VElement};
#[repr(transparent)]
pub struct NodeRef<'a>(&'a VElement<'a>);
impl<'a> NodeRef<'a> {
pub fn new(velement: &'a VElement<'a>) -> Self {
Self(velement)
}
pub fn tag(&self) -> &'a str {
self.0.tag
}
pub fn namespace(&self) -> Option<&'a str> {
self.0.namespace
}
pub fn attributes(&self) -> &'a [Attribute<'a>] {
self.0.attributes
}
}
pub trait ChildDepState: PartialEq {
type Ctx;
type DepState: ChildDepState;
fn reduce(&mut self, node: NodeRef, children: Vec<&Self::DepState>, ctx: &Self::Ctx);
}
pub trait ParentDepState: PartialEq {
type Ctx;
type DepState: ParentDepState;
fn reduce(&mut self, node: NodeRef, parent: &Self::DepState, ctx: &Self::Ctx);
}
pub trait NodeDepState: PartialEq {
type Ctx;
fn reduce(&mut self, node: NodeRef, ctx: &Self::Ctx);
}
pub trait State {
fn update_node_dep_state(&mut self, ty: TypeId, node: NodeRef, ctx: &AnyMap);
fn child_dep_types(&self) -> Vec<TypeId>;
fn update_parent_dep_state(&mut self, ty: TypeId, node: NodeRef, parent: &Self, ctx: &AnyMap);
fn parent_dep_types(&self) -> Vec<TypeId>;
fn update_child_dep_state(
&mut self,
ty: TypeId,
node: NodeRef,
children: Vec<&Self>,
ctx: &AnyMap,
);
fn node_dep_types(&self) -> Vec<TypeId>;
}

View file

@ -0,0 +1,62 @@
use dioxus_native_core::real_dom_new_api::*;
use dioxus_native_core_macro::*;
#[derive(State)]
struct Z {
// depends on just attributes and no context
#[node_dep_state()]
x: A,
// depends on attributes, the B component of children and i32 context
#[child_dep_state(i32, B)]
y: B,
// depends on attributes, the C component of it's parent and a u8 context
#[parent_dep_state(u8, C)]
z: C,
}
// struct Z {
// x: A,
// y: B,
// z: C,
// }
use dioxus_native_core::real_dom_new_api::NodeDepState;
#[derive(PartialEq)]
struct A;
impl NodeDepState for A {
type Ctx = ();
fn reduce(&mut self, _: NodeRef, _: &()) {
todo!()
}
}
#[derive(PartialEq)]
struct B;
impl ChildDepState for B {
type Ctx = i32;
type DepState = Self;
fn reduce(
&mut self,
_: dioxus_native_core::real_dom_new_api::NodeRef,
_: Vec<&Self::DepState>,
_: &i32,
) {
todo!()
}
}
#[derive(PartialEq)]
struct C;
impl ParentDepState for C {
type Ctx = u8;
type DepState = Self;
fn reduce(
&mut self,
_: dioxus_native_core::real_dom_new_api::NodeRef,
_: &Self::DepState,
_: &u8,
) {
todo!()
}
}