component generator
This commit is contained in:
@@ -17,7 +17,7 @@ pub fn main() {
|
|||||||
|
|
||||||
let handle = thread::spawn(move || {
|
let handle = thread::spawn(move || {
|
||||||
let res = engine
|
let res = engine
|
||||||
.run(BenchmarkApp(items))
|
.run(BenchmarkApp { items })
|
||||||
.expect("Failed to run engine");
|
.expect("Failed to run engine");
|
||||||
|
|
||||||
tx.send((items, res)).expect("Failed to send result");
|
tx.send((items, res)).expect("Failed to send result");
|
||||||
@@ -41,11 +41,10 @@ pub fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BenchmarkApp(pub usize);
|
#[component]
|
||||||
|
fn BenchmarkApp(cx: &Arc<Context>, items: &usize) -> View {
|
||||||
|
let items = items.clone();
|
||||||
|
|
||||||
impl ComponentImpl for BenchmarkApp {
|
|
||||||
fn call(&self, cx: &Arc<Context>) -> View {
|
|
||||||
let items = self.0.clone();
|
|
||||||
rsx! {
|
rsx! {
|
||||||
for _ in (0..items) {
|
for _ in (0..items) {
|
||||||
"Hello, world!"
|
"Hello, world!"
|
||||||
@@ -53,4 +52,3 @@ impl ComponentImpl for BenchmarkApp {
|
|||||||
}
|
}
|
||||||
.view(cx.clone())
|
.view(cx.clone())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
@@ -4,16 +4,13 @@ use osui::prelude::*;
|
|||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
let engine = Console::new();
|
let engine = Console::new();
|
||||||
engine.run(App).expect("Failed to run engine");
|
engine.run(App {}).expect("Failed to run engine");
|
||||||
}
|
}
|
||||||
|
|
||||||
struct App;
|
#[component]
|
||||||
|
fn App(cx: &Arc<Context>) -> View {
|
||||||
impl ComponentImpl for App {
|
|
||||||
fn call(&self, cx: &Arc<Context>) -> View {
|
|
||||||
rsx! {
|
rsx! {
|
||||||
"Hello, world!"
|
"Hello World"
|
||||||
}
|
}
|
||||||
.view(cx.clone())
|
.view(cx.clone())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use osui::prelude::*;
|
|||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
let engine = Benchmark::new(Console::new());
|
let engine = Benchmark::new(Console::new());
|
||||||
let benchmark_result = engine.run(App).expect("Failed to run engine");
|
let benchmark_result = engine.run(App {}).expect("Failed to run engine");
|
||||||
println!("Avg: {} μs", benchmark_result.average);
|
println!("Avg: {} μs", benchmark_result.average);
|
||||||
println!("Min: {} μs", benchmark_result.min);
|
println!("Min: {} μs", benchmark_result.min);
|
||||||
println!("Max: {} μs", benchmark_result.max);
|
println!("Max: {} μs", benchmark_result.max);
|
||||||
@@ -12,13 +12,10 @@ pub fn main() {
|
|||||||
println!("Tot Render: {} μs", benchmark_result.total_render);
|
println!("Tot Render: {} μs", benchmark_result.total_render);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct App;
|
#[component]
|
||||||
|
fn App(cx: &Arc<Context>) -> View {
|
||||||
impl ComponentImpl for App {
|
|
||||||
fn call(&self, cx: &Arc<Context>) -> View {
|
|
||||||
rsx! {
|
rsx! {
|
||||||
"Hello, world!"
|
"Hello, world!"
|
||||||
}
|
}
|
||||||
.view(cx.clone())
|
.view(cx.clone())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
+2
-2
@@ -51,14 +51,14 @@ fn emit_node_scope(node: &RsxNode) -> TokenStream {
|
|||||||
RsxNode::Text(_) => {
|
RsxNode::Text(_) => {
|
||||||
let emit = emit_node(node);
|
let emit = emit_node(node);
|
||||||
quote! {
|
quote! {
|
||||||
r.static_scope(|scope| {#emit});
|
r.static_scope(move |scope| {#emit});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RsxNode::Component(_) => {
|
RsxNode::Component(_) => {
|
||||||
let emit = emit_node(node);
|
let emit = emit_node(node);
|
||||||
quote! {
|
quote! {
|
||||||
r.static_scope(|scope| {#emit});
|
r.static_scope(move |scope| {#emit});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+102
-1
@@ -1,10 +1,111 @@
|
|||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
|
use quote::quote;
|
||||||
|
use syn::{FnArg, ItemFn, Pat, ReturnType, Type, parse_macro_input};
|
||||||
|
|
||||||
mod emit;
|
mod emit;
|
||||||
mod parse;
|
mod parse;
|
||||||
|
|
||||||
#[proc_macro]
|
#[proc_macro]
|
||||||
pub fn rsx(input: TokenStream) -> TokenStream {
|
pub fn rsx(input: TokenStream) -> TokenStream {
|
||||||
let ast = syn::parse_macro_input!(input as parse::RsxRoot);
|
let ast = parse_macro_input!(input as parse::RsxRoot);
|
||||||
emit::emit_rsx(ast).into()
|
emit::emit_rsx(ast).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn component(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
|
let input = parse_macro_input!(item as ItemFn);
|
||||||
|
|
||||||
|
let name = &input.sig.ident;
|
||||||
|
let vis = &input.vis;
|
||||||
|
let body = &input.block;
|
||||||
|
|
||||||
|
let return_ty = match &input.sig.output {
|
||||||
|
ReturnType::Type(_, ty) => ty,
|
||||||
|
_ => {
|
||||||
|
return syn::Error::new_spanned(&input.sig, "component must return View")
|
||||||
|
.to_compile_error()
|
||||||
|
.into();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut inputs = input.sig.inputs.iter();
|
||||||
|
|
||||||
|
// ---- First param must be cx ----
|
||||||
|
let cx = match inputs.next() {
|
||||||
|
Some(FnArg::Typed(pat)) => pat,
|
||||||
|
_ => {
|
||||||
|
return syn::Error::new_spanned(&input.sig, "first argument must be cx: &Arc<Context>")
|
||||||
|
.to_compile_error()
|
||||||
|
.into();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let cx_ident = match &*cx.pat {
|
||||||
|
Pat::Ident(id) => &id.ident,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let cx_ty = &cx.ty;
|
||||||
|
|
||||||
|
// ---- Remaining params are props ----
|
||||||
|
let mut struct_fields = Vec::new();
|
||||||
|
let mut render_params = Vec::new();
|
||||||
|
let mut call_args = Vec::new();
|
||||||
|
|
||||||
|
for arg in inputs {
|
||||||
|
let FnArg::Typed(pat) = arg else { continue };
|
||||||
|
|
||||||
|
let ident = match &*pat.pat {
|
||||||
|
Pat::Ident(id) => &id.ident,
|
||||||
|
_ => {
|
||||||
|
return syn::Error::new_spanned(pat, "unsupported prop pattern")
|
||||||
|
.to_compile_error()
|
||||||
|
.into();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Strip leading &
|
||||||
|
let owned_ty = match &*pat.ty {
|
||||||
|
Type::Reference(r) => &r.elem,
|
||||||
|
ty => ty,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct_fields.push(quote! {
|
||||||
|
pub #ident: #owned_ty
|
||||||
|
});
|
||||||
|
|
||||||
|
render_params.push(quote! {
|
||||||
|
#ident: &#owned_ty
|
||||||
|
});
|
||||||
|
|
||||||
|
call_args.push(quote! {
|
||||||
|
&self.#ident
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let expanded = quote! {
|
||||||
|
#vis struct #name {
|
||||||
|
#(#struct_fields,)*
|
||||||
|
}
|
||||||
|
|
||||||
|
impl #name {
|
||||||
|
pub fn component(
|
||||||
|
#cx_ident: #cx_ty,
|
||||||
|
#(#render_params,)*
|
||||||
|
) -> #return_ty {
|
||||||
|
#body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ComponentImpl for #name {
|
||||||
|
fn call(&self, cx: &std::sync::Arc<Context>) -> #return_ty {
|
||||||
|
Self::component(
|
||||||
|
cx,
|
||||||
|
#(#call_args,)*
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
expanded.into()
|
||||||
|
}
|
||||||
|
|||||||
+1
-1
@@ -14,7 +14,7 @@ pub mod prelude {
|
|||||||
pub use crate::render::*;
|
pub use crate::render::*;
|
||||||
pub use crate::state::*;
|
pub use crate::state::*;
|
||||||
pub use crate::View;
|
pub use crate::View;
|
||||||
pub use osui_macros::rsx;
|
pub use osui_macros::{component, rsx};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type View = Arc<dyn Fn(&mut DrawContext) + Send + Sync>;
|
pub type View = Arc<dyn Fn(&mut DrawContext) + Send + Sync>;
|
||||||
|
|||||||
Reference in New Issue
Block a user