diff --git a/benches/benches/benchmark.rs b/benches/benches/benchmark.rs index 6075708..4504147 100644 --- a/benches/benches/benchmark.rs +++ b/benches/benches/benchmark.rs @@ -118,7 +118,6 @@ fn horrorshow_many_dyn_attrs() -> String { } fn rscx_many_dyn_attrs() -> String { - use rscx::EscapeAttribute; let value: i32 = 42; rscx::html! {

diff --git a/rscx-macros/src/lib.rs b/rscx-macros/src/lib.rs index a70b9e4..d1a1f81 100644 --- a/rscx-macros/src/lib.rs +++ b/rscx-macros/src/lib.rs @@ -1,7 +1,6 @@ use std::collections::HashSet; use proc_macro::TokenStream; -use proc_macro2::{Literal, TokenTree}; use proc_macro2_diagnostics::Diagnostic; use quote::{quote, quote_spanned, ToTokens}; use rstml::{ @@ -75,7 +74,7 @@ fn process_nodes<'n>( #(#errors;)* // Make sure that "enum x{};" and "let _x = crate::element;" can be used in this context #(#docs;)* - format!(#html_string, #(#values),*) + format!(#html_string, #(rscx::FormatWrapper::new(#values)),*) } } } @@ -212,11 +211,7 @@ fn walk_nodes<'a>(nodes: &'a Vec) -> WalkNodesOutput<'a> { out.static_format.push_str(&text.value_string()); } Node::RawText(text) => { - out.static_format.push_str("{}"); - let tokens = text.to_string_best(); - let literal = Literal::string(&tokens); - - out.values.push(TokenTree::from(literal).into()); + out.static_format.push_str(&text.to_string_best()); } Node::Fragment(fragment) => { let other_output = walk_nodes(&fragment.children); @@ -227,8 +222,10 @@ fn walk_nodes<'a>(nodes: &'a Vec) -> WalkNodesOutput<'a> { out.values.push(comment.value.to_token_stream()); } Node::Block(block) => { + let block = block.try_block().unwrap(); + let stmts = &block.stmts; out.static_format.push_str("{}"); - out.values.push(block.to_token_stream()); + out.values.push(quote!(#(#stmts)*)); } } } @@ -277,7 +274,8 @@ fn walk_attribute(attribute: &KeyedAttribute) -> (String, Option Result<(), Box> { + let app = app().await; + println!("{}", app); + Ok(()) +} + +// simple function returning a String +// it will call the Items() function +async fn app() -> String { + let s = Some("ul { color: red; }"); + let none: Option<&str> = None; + html! { + + + + + + + { none } + // call a component with no props + + + } +} diff --git a/rscx/src/format_wrapper.rs b/rscx/src/format_wrapper.rs new file mode 100644 index 0000000..c7a3bd8 --- /dev/null +++ b/rscx/src/format_wrapper.rs @@ -0,0 +1,20 @@ +use std::fmt::{self, Display}; + +use crate::render::Render; + +pub struct FormatWrapper { + inner: T, +} + +impl FormatWrapper { + pub fn new(inner: T) -> Self { + Self { inner } + } +} + +impl Display for FormatWrapper { + #[inline(always)] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.inner.render(f) + } +} diff --git a/rscx/src/lib.rs b/rscx/src/lib.rs index 572cdd7..a699b4c 100644 --- a/rscx/src/lib.rs +++ b/rscx/src/lib.rs @@ -5,6 +5,8 @@ pub use attributes::*; #[cfg(feature = "axum")] pub mod axum; pub mod context; +pub mod format_wrapper; +pub mod render; pub extern crate rscx_macros; use std::future::Future; @@ -14,6 +16,7 @@ pub use rscx_macros::*; pub extern crate typed_builder; pub extern crate html_escape; +pub use format_wrapper::FormatWrapper; use async_trait::async_trait; use futures::future::join_all; diff --git a/rscx/src/render.rs b/rscx/src/render.rs new file mode 100644 index 0000000..06ca52c --- /dev/null +++ b/rscx/src/render.rs @@ -0,0 +1,142 @@ +use std::{ + borrow::Cow, + convert::Infallible, + env::VarError, + fmt, + io::ErrorKind, + net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}, + num::{ + NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128, + NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, + }, + rc::Rc, + sync::{ + mpsc::{RecvTimeoutError, TryRecvError}, + Arc, + }, +}; + +pub trait Render { + fn render(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result; +} + +macro_rules! impl_render_for_basic_types { + ($($t:ty)*) => ($( + impl Render for $t { + #[inline(always)] + fn render(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, f) + } + } + )*) +} + +impl_render_for_basic_types! { + Infallible + VarError + ErrorKind + IpAddr + SocketAddr + RecvTimeoutError + TryRecvError + bool + char + f32 + f64 + i8 + i16 + i32 + i64 + i128 + isize + u8 + u16 + u32 + u64 + u128 + usize + Ipv4Addr + Ipv6Addr + SocketAddrV4 + SocketAddrV6 + NonZeroI8 + NonZeroI16 + NonZeroI32 + NonZeroI64 + NonZeroI128 + NonZeroIsize + NonZeroU8 + NonZeroU16 + NonZeroU32 + NonZeroU64 + NonZeroU128 + NonZeroUsize + String + str +} + +impl Render for Cow<'_, B> +where + B: Render + ToOwned, + ::Owned: Render, +{ + fn render(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Cow::Borrowed(ref b) => Render::render(b, f), + Cow::Owned(ref o) => Render::render(o, f), + } + } +} + +impl Render for Box { + #[inline(always)] + fn render(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + Render::render(&**self, f) + } +} + +impl Render for &T { + #[inline(always)] + fn render(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + Render::render(&**self, f) + } +} + +impl Render for &mut T { + #[inline(always)] + fn render(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + Render::render(&**self, f) + } +} + +impl Render for Rc { + #[inline(always)] + fn render(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + Render::render(&**self, f) + } +} + +impl Render for Arc { + #[inline(always)] + fn render(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + Render::render(&**self, f) + } +} + +impl Render for Option { + #[inline(always)] + fn render(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Some(inner) = self { + inner.render(f) + } else { + Ok(()) + } + } +} + +impl Render for () { + #[inline(always)] + fn render(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { + Ok(()) + } +} diff --git a/website/src/main.rs b/website/src/main.rs index 77e7a6e..c251c48 100644 --- a/website/src/main.rs +++ b/website/src/main.rs @@ -5,7 +5,7 @@ use std::{ }; use csm::csm; -use rscx::{component, html, EscapeAttribute}; +use rscx::{component, html}; use rscx_mdx::mdx::{Mdx, MdxComponentProps}; #[tokio::main]