commit d2e6c51073d7db0b6fe3b055cb88bb277338e04b Author: Tyler Clarke Date: Wed Feb 12 09:47:32 2025 -0500 initial diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..5531ebb --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,86 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "borrow-or-share" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eeab4423108c5d7c744f4d234de88d18d636100093ae04caf4825134b9c3a32" + +[[package]] +name = "fluent-uri" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1918b65d96df47d3591bed19c5cca17e3fa5d0707318e4b5ef2eae01764df7e5" +dependencies = [ + "borrow-or-share", + "ref-cast", +] + +[[package]] +name = "proc-macro2" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ref-cast" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf0a6f84d5f1d581da8b41b47ec8600871962f2a528115b542b362d4b744931" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "soda" +version = "0.1.0" +dependencies = [ + "fluent-uri", + "soda_macros", +] + +[[package]] +name = "soda_macros" +version = "0.1.0" + +[[package]] +name = "syn" +version = "2.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..f969df0 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "soda" +version = "0.1.0" +edition = "2021" + +[dependencies] +fluent-uri = "0.3.2" \ No newline at end of file diff --git a/examples/hello.rs b/examples/hello.rs new file mode 100644 index 0000000..052f9d4 --- /dev/null +++ b/examples/hello.rs @@ -0,0 +1,14 @@ +// A very, very simple static composer example. + +extern crate soda; + +use soda::prelude::*; + + +#[tokio::main] +fn main() { + let app = PageBase("Test Page", + Tag::Heading1("hi!") + ); + Server::new((0.0.0.0, 3000)).unwrap().serve(app).await; +} \ No newline at end of file diff --git a/generate-composer-impls.py b/generate-composer-impls.py new file mode 100644 index 0000000..3d6ad8f --- /dev/null +++ b/generate-composer-impls.py @@ -0,0 +1,26 @@ +# generates impls for compose tuples + + +def tp(n): + return "T" + str(n + 1) + +def nprint(s): + print(s, end="") + + +print("use crate::compose::Compose;") +print("use crate::output::Output;") + +for x in range(1, 32): + nprint("impl" for n in range(0, x)])) + nprint("> Compose for (") + nprint("".join([tp(n) + "," for n in range(0, x)])) + print(") {") + print("\tfn render(&self, output : &mut impl Output, state : &mut State) {") + for n in range(0, x): + nprint("\t\tself.") + nprint(n) + print(".render(output, state);") + print("\t}") + print("}") \ No newline at end of file diff --git a/src/compose.rs b/src/compose.rs new file mode 100644 index 0000000..12586ac --- /dev/null +++ b/src/compose.rs @@ -0,0 +1,41 @@ +// Compose trait. + +use crate::output::Output; +use crate::router::{ self, RouteTerminate, Router }; + + +pub trait Compose { + fn render(&self, output : &mut impl Output, state : &mut State); + + fn route(self, r : &'static str) -> impl Router where Self : Sized { + router::route(r).then(RouteTerminate::build(self)) + } +} + + +impl Compose for () { + fn render(&self, _output : &mut impl Output, _state : &mut State) { + + } +} + + +impl Compose for &'static str { + fn render(&self, output : &mut impl Output, _state : &mut State) { + output.write(self); + } +} + + +impl Compose for String { + fn render(&self, output : &mut impl Output, _state : &mut State) { + output.write(self.as_str()); + } +} + + +impl, T : Fn(&mut St) -> S> Compose for T { + fn render(&self, output : &mut impl Output, state : &mut St) { + self(state).render(output, state); + } +} diff --git a/src/html.rs b/src/html.rs new file mode 100644 index 0000000..d372b6f --- /dev/null +++ b/src/html.rs @@ -0,0 +1,187 @@ +use crate::compose::Compose; +use crate::output::Output; +use std::marker::PhantomData; + + +pub trait HTMLTag : Compose { + fn get_tagname(&self) -> &'static str; + + fn does_self_close(&self) -> bool; + + fn render_properties(&self, _out : &mut impl Output, _state : &mut State) {} + + fn render_content(&self, _out : &mut impl Output, _state : &mut State) {} + + fn with_property(self, name : &'static str, value : &'static str) -> WithProperty where Self: Sized { + WithProperty { + name, value, lower_tag : self, _phantom : Default::default() + } + } + + fn charset(self, v : &'static str) -> WithProperty where Self: Sized { + self.with_property("charset", v) + } + + fn helpful_provided_render_function(&self, out : &mut impl Output, state : &mut State) { + out.write("<"); + out.write(self.get_tagname()); + self.render_properties(out, state); + if self.does_self_close() { + out.write("/>"); + } + else { + out.write(">"); + self.render_content(out, state); + out.write(""); + } + } +} + + +pub struct WithProperty + Sized> { + name : &'static str, + value : &'static str, + lower_tag : T, + _phantom : PhantomData +} + + +impl> HTMLTag for WithProperty { + fn get_tagname(&self) -> &'static str { + self.lower_tag.get_tagname() + } + + fn does_self_close(&self) -> bool { + self.lower_tag.does_self_close() + } + + fn render_properties(&self, out : &mut impl Output, state : &mut State) { + out.write(" "); + out.write(self.name); + out.write("=\""); + out.write(self.value); + out.write("\""); + self.lower_tag.render_properties(out, state); + } + + fn render_content(&self, out : &mut impl Output, state : &mut State) { + self.lower_tag.render_content(out, state); + } +} + + +impl + Sized, State> Compose for WithProperty { + fn render(&self, out : &mut impl Output, state : &mut State) { + self.helpful_provided_render_function(out, state); + } +} + + +impl, State> Compose for StandardTags { + fn render(&self, out : &mut impl Output, state : &mut State) { + self.helpful_provided_render_function(out, state); + } +} + + +impl Compose for SelfClosingTags { + fn render(&self, out : &mut impl Output, state : &mut State) { + self.helpful_provided_render_function(out, state); + } +} + + +pub enum StandardTags { + Html(T), + Head(T), + Body(T), + Title(T), + Paragraph(T), + Div(T), + Heading1(T) +} + + +pub enum SelfClosingTags { + Meta +} + + +impl HTMLTag for SelfClosingTags { + fn get_tagname(&self) -> &'static str { + match self { + Self::Meta => "meta" + } + } + + fn does_self_close(&self) -> bool { + true + } +} + + +impl StandardTags { + fn contents<'a>(&'a self) -> &'a T { + match self { + Self::Html(c) => c, + Self::Head(c) => c, + Self::Body(c) => c, + Self::Title(c) => c, + Self::Paragraph(c) => c, + Self::Div(c) => c, + Self::Heading1(c) => c + } + } +} + +impl> HTMLTag for StandardTags { + fn get_tagname(&self) -> &'static str { + match self { + Self::Html(_) => "html", + Self::Head(_) => "head", + Self::Body(_) => "body", + Self::Title(_) => "title", + Self::Paragraph(_) => "p", + Self::Div(_) => "div", + Self::Heading1(_) => "h1" + } + } + + fn does_self_close(&self) -> bool { + false + } + + fn render_content(&self, out : &mut impl Output, state : &mut State) { + self.contents().render(out, state); + } +} + + +#[allow(non_snake_case)] +pub mod Tag { + pub use super::StandardTags::*; + pub use super::SelfClosingTags::*; +} + + +#[allow(non_snake_case)] +pub fn Doctype() -> &'static str { + "" +} + + +#[allow(non_snake_case)] +pub fn PageBase(title : &'static str, body : impl Compose) -> impl Compose { + ( + Doctype(), + Tag::Html(( + Tag::Head(( + Tag::Meta.charset("utf-8"), + Tag::Title(title) + )), + Tag::Body(body) + )) + ) +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..a30bf46 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,97 @@ +/* Soda + by Tyler Clarke + + Soda is a convenient frontend framework... written in backend rust. + It allows you to turn a complicated webpage design into a single server-side executable that runs on any Linux system. + A core element of soda's philosophy is the idea of staying fully static: this allows the optimizing compiler to reduce potentially thousands of lines + of frontend code to a few dozen inlined socket writes, which is *enormously* fast. + Soda provides a set of powerful dynamic features atop the static rendering ones as well. + + Soda is built atop Hyper, the fastest correct HTTP server implementation in rust. +*/ + + +pub mod compose; +pub mod output; +pub mod html; +pub mod tuples; +pub mod router; +pub mod prelude; +pub mod server; + + +#[cfg(test)] +mod tests { + use super::prelude::*; + + #[test] + fn render_composer() { // simplest example: renders a composer with DummyOutput + let page = PageBase ( + "Test Webpage", + Tag::Paragraph("Hello, World!") + ); + let mut output = output::DummyOutput::new(); + page.render(&mut output, &mut ()); + assert_eq!(output.spool(), r#"Test Webpage

Hello, World!

"#); + } + + #[test] + fn routing_test() { + fn template(content : impl Compose) -> impl Compose { + PageBase ( + "My Webpage", + Tag::Div(( + Tag::Heading1("My Test Website"), + content + )) + ) + } + let page1 = template("this is the first page"); + let page2 = template("this is the second page"); + let page3 = template("this is the third page"); + let app = page1.route("page1") // route GET /page1 + .or(page2.route("page2")) // route GET /page2 + .or(router::route("page_num").then(page3.route("3"))); // route GET /page_num/3 + let mut output = output::DummyOutput::new(); + app.get("https://web.app/page1").unwrap().render(&mut output, &mut ()); + assert_eq!(output.spool(), r#"My Webpage

My Test Website

this is the first page
"#); + output = output::DummyOutput::new(); + app.get("https://web.app/page2").unwrap().render(&mut output, &mut ()); + assert_eq!(output.spool(), r#"My Webpage

My Test Website

this is the second page
"#); + output = output::DummyOutput::new(); + app.get("https://web.app/page_num/3").unwrap().render(&mut output, &mut ()); + assert_eq!(output.spool(), r#"My Webpage

My Test Website

this is the third page
"#); + } + + #[test] + fn closure_test() { + // you can use embedded blocks to procedurally generate outputs + let app = Tag::Div(("Hello, ", { + "World!" + })); + let mut output = output::DummyOutput::new(); + app.render(&mut output, &mut ()); + assert_eq!(output.spool(), r#"
Hello, World!
"#); + } + + #[test] + fn dynamic_globalstate_test() { + // composers must always be immutable. however, you can produce dynamic mutable behavior with State + // it's literally just a generic of Component + // you can pass pretty much whatever you want in there. + let app_with_state = ( + "this page has been visited ", + |state : &mut u32 | { + *state += 1; + state.to_string() + }, + " times." + ); + let mut state : u32 = 0; + for x in 0..5 { + let mut output = output::DummyOutput::new(); + app_with_state.render(&mut output, &mut state); + assert_eq!(output.spool(), format!("this page has been visited {} times.", x + 1)); + } + } +} diff --git a/src/output.rs b/src/output.rs new file mode 100644 index 0000000..56dff8d --- /dev/null +++ b/src/output.rs @@ -0,0 +1,33 @@ +// output trait and some possibilities for outputs +pub trait Output { + fn write(&mut self, data : &str); +} + + +pub struct DummyOutput { + out : String +} + + +impl Output for DummyOutput { + fn write(&mut self, data : &str) { + self.out += data; + } +} + + +impl DummyOutput { + pub fn print(&mut self) { + println!("{}", self.out); + } + + pub fn spool(self) -> String { + self.out + } + + pub fn new() -> DummyOutput { + DummyOutput { + out : String::new() + } + } +} \ No newline at end of file diff --git a/src/prelude.rs b/src/prelude.rs new file mode 100644 index 0000000..0cfa106 --- /dev/null +++ b/src/prelude.rs @@ -0,0 +1,8 @@ +// all the useful re-exports to get an app online without worrying too much about modules +pub use crate::{ + html::*, + compose::Compose, + output, + router::{ Router, self }, + server::* +}; diff --git a/src/router.rs b/src/router.rs new file mode 100644 index 0000000..6f8a99f --- /dev/null +++ b/src/router.rs @@ -0,0 +1,157 @@ +// router definitions +use crate::compose::Compose; +use fluent_uri::{ Uri }; +use std::marker::PhantomData; + + +pub trait Router> { // routers match paths and return a + fn or>(self, other : T) -> OrRouter where Self : Sized { // route EITHER this router or another router, tries this router first + OrRouter { + one : self, + two : other, + _phantom : Default::default() + } + } + + fn then, T : Router>(self, other : T) -> ThenRouter, T> where Self : Sized { // route this router, THEN route another router if routing this router succeeded (ignores any output this router produces) + ThenRouter { + one : self.unitize(), + two : other, + _phantom : Default::default() + } + } + + fn unitize(self) -> impl Router; // convert this router into a unit router + + fn route<'a, T : AsRef>(&'a self, path : &mut (impl Iterator + Clone)) -> Option<&'a Out>; // should return None on route failure + + fn get<'a>(&'a self, uri : &str) -> Option<&'a Out> { + let mut path = Uri::parse(uri).unwrap().path().split('/').peekable(); + while let Some(p) = path.peek() { // strip off the empty strings at the start of the iterator [why is this a thing?] + if p.len() != 0 { + break; + } + path.next(); + } + self.route(&mut path) + } +} + + +pub struct PathRouter { + path : &'static str +} + + +impl Router for PathRouter { + fn unitize(self) -> impl Router { + self + } + + fn route<'a, T : AsRef>(&'a self, path : &mut (impl Iterator + Clone)) -> Option<&'a ()> { + if let Some(p) = path.next() { + if p.as_ref() == self.path { + return Some(&()); + } + } + return None; + } +} + + +pub struct ThenRouter, FirstRouter : Router, SecondRouter : Router> { + one : FirstRouter, + two : SecondRouter, + _phantom : PhantomData<(Out, State)> +} + + +impl, FirstRouter : Router, SecondRouter : Router> Router for ThenRouter { + fn unitize(self) -> impl Router { + ThenRouter { + one : self.one, + two : self.two.unitize(), + _phantom : Default::default() + } + } + + fn route<'a, T : AsRef>(&'a self, path : &mut (impl Iterator + Clone)) -> Option<&'a Out> { + if let Some(()) = self.one.route(path) { + self.two.route(path) + } + else { + None + } + } +} + + +pub struct OrRouter, FirstRouter : Router, SecondRouter : Router> { + one : FirstRouter, + two : SecondRouter, + _phantom : PhantomData<(State, Out)> +} + + +impl, FirstRouter : Router, SecondRouter : Router> Router for OrRouter { + fn unitize(self) -> impl Router { + OrRouter { + one : self.one.unitize(), + two : self.two.unitize(), + _phantom : Default::default() + } + } + + fn route<'a, T : AsRef>(&'a self, path : &mut (impl Iterator + Clone)) -> Option<&'a Out> { + let mut cl = path.clone(); // TODO: debug the performance characteristics of this (in theory it should be nearly costless, but we need to check!) + if let Some(v) = self.one.route(&mut cl) { + Some(v) + } + else { + cl = path.clone(); + if let Some(v) = self.two.route(&mut cl) { + Some(v) + } + else { + None + } + } + } +} + + +pub struct RouteTerminate> { // terminate a route in a composer. cannot fail; this is not a filter. + output : Out, + _phantom : PhantomData +} + + +impl + Sized> RouteTerminate { + pub fn build(thing : Out) -> RouteTerminate { + RouteTerminate { + output : thing, + _phantom : Default::default() + } + } +} + + +impl + Sized> Router for RouteTerminate { + fn unitize(self) -> impl Router { + RouteTerminate:: { + output : (), + _phantom : Default::default() + } + } + + fn route<'a, T : AsRef>(&'a self, _path : &mut (impl Iterator + Clone)) -> Option<&'a Out> { + Some(&self.output) + } +} + + +pub fn route(path : &'static str) -> PathRouter { + PathRouter { + path + } +} \ No newline at end of file diff --git a/src/server.rs b/src/server.rs new file mode 100644 index 0000000..58be68d --- /dev/null +++ b/src/server.rs @@ -0,0 +1,53 @@ +// webserver that forwards requests to Routes +// based on Hyper + +use std::convert::Infallible; +use std::net::SocketAddr; + +use http_body_util::Full; +use hyper::body::Bytes; +use hyper::server::conn::http1; +use hyper::service::service_fn; +use hyper::{Request, Response}; +use hyper_util::rt::TokioIo; +use tokio::net::TcpListener; + +use std::sync::{ Arc, Mutex }; + +use crate::router::Router; + + +struct Server { + addr : SocketAddr, + listener : TcpListener +} + + +impl Server { + pub fn new(addr : ([u8; 4], u16)) -> Result> { + let addr = SocketAddr::from(addr); + Ok(Server { + addr, + listener : TcpListener::bind(addr).await? + }) + } + + pub async fn serve(&self, rt : impl Router, state : T) -> Result<(), Box> { + let state = Arc::new(Mutex::new(state)); + loop { + let (stream, _) = self.listener.accept().await?; + let io = TokioIo::new(stream); + let state = state.clone(); + let service = service_fn(move |req| { + async move { + + } + }); + tokio::task::spawn(async move { + if let Err(e) = http1::Builder::new().serve_connection(io, service).await { + eprintln!("Error serving connection: {:?}", e); + } + }); + } + } +} \ No newline at end of file diff --git a/src/tuples.rs b/src/tuples.rs new file mode 100644 index 0000000..0a2075d --- /dev/null +++ b/src/tuples.rs @@ -0,0 +1,622 @@ +use crate::compose::Compose; +use crate::output::Output; +impl> Compose for (T1,) { + fn render(&self, output : &mut impl Output, state : &mut State) { + self.0.render(output, state); + } +} +impl, T2 : Compose> Compose for (T1,T2,) { + fn render(&self, output : &mut impl Output, state : &mut State) { + self.0.render(output, state); + self.1.render(output, state); + } +} +impl, T2 : Compose, T3 : Compose> Compose for (T1,T2,T3,) { + fn render(&self, output : &mut impl Output, state : &mut State) { + self.0.render(output, state); + self.1.render(output, state); + self.2.render(output, state); + } +} +impl, T2 : Compose, T3 : Compose, T4 : Compose> Compose for (T1,T2,T3,T4,) { + fn render(&self, output : &mut impl Output, state : &mut State) { + self.0.render(output, state); + self.1.render(output, state); + self.2.render(output, state); + self.3.render(output, state); + } +} +impl, T2 : Compose, T3 : Compose, T4 : Compose, T5 : Compose> Compose for (T1,T2,T3,T4,T5,) { + fn render(&self, output : &mut impl Output, state : &mut State) { + self.0.render(output, state); + self.1.render(output, state); + self.2.render(output, state); + self.3.render(output, state); + self.4.render(output, state); + } +} +impl, T2 : Compose, T3 : Compose, T4 : Compose, T5 : Compose, T6 : Compose> Compose for (T1,T2,T3,T4,T5,T6,) { + fn render(&self, output : &mut impl Output, state : &mut State) { + self.0.render(output, state); + self.1.render(output, state); + self.2.render(output, state); + self.3.render(output, state); + self.4.render(output, state); + self.5.render(output, state); + } +} +impl, T2 : Compose, T3 : Compose, T4 : Compose, T5 : Compose, T6 : Compose, T7 : Compose> Compose for (T1,T2,T3,T4,T5,T6,T7,) { + fn render(&self, output : &mut impl Output, state : &mut State) { + self.0.render(output, state); + self.1.render(output, state); + self.2.render(output, state); + self.3.render(output, state); + self.4.render(output, state); + self.5.render(output, state); + self.6.render(output, state); + } +} +impl, T2 : Compose, T3 : Compose, T4 : Compose, T5 : Compose, T6 : Compose, T7 : Compose, T8 : Compose> Compose for (T1,T2,T3,T4,T5,T6,T7,T8,) { + fn render(&self, output : &mut impl Output, state : &mut State) { + self.0.render(output, state); + self.1.render(output, state); + self.2.render(output, state); + self.3.render(output, state); + self.4.render(output, state); + self.5.render(output, state); + self.6.render(output, state); + self.7.render(output, state); + } +} +impl, T2 : Compose, T3 : Compose, T4 : Compose, T5 : Compose, T6 : Compose, T7 : Compose, T8 : Compose, T9 : Compose> Compose for (T1,T2,T3,T4,T5,T6,T7,T8,T9,) { + fn render(&self, output : &mut impl Output, state : &mut State) { + self.0.render(output, state); + self.1.render(output, state); + self.2.render(output, state); + self.3.render(output, state); + self.4.render(output, state); + self.5.render(output, state); + self.6.render(output, state); + self.7.render(output, state); + self.8.render(output, state); + } +} +impl, T2 : Compose, T3 : Compose, T4 : Compose, T5 : Compose, T6 : Compose, T7 : Compose, T8 : Compose, T9 : Compose, T10 : Compose> Compose for (T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,) { + fn render(&self, output : &mut impl Output, state : &mut State) { + self.0.render(output, state); + self.1.render(output, state); + self.2.render(output, state); + self.3.render(output, state); + self.4.render(output, state); + self.5.render(output, state); + self.6.render(output, state); + self.7.render(output, state); + self.8.render(output, state); + self.9.render(output, state); + } +} +impl, T2 : Compose, T3 : Compose, T4 : Compose, T5 : Compose, T6 : Compose, T7 : Compose, T8 : Compose, T9 : Compose, T10 : Compose, T11 : Compose> Compose for (T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,) { + fn render(&self, output : &mut impl Output, state : &mut State) { + self.0.render(output, state); + self.1.render(output, state); + self.2.render(output, state); + self.3.render(output, state); + self.4.render(output, state); + self.5.render(output, state); + self.6.render(output, state); + self.7.render(output, state); + self.8.render(output, state); + self.9.render(output, state); + self.10.render(output, state); + } +} +impl, T2 : Compose, T3 : Compose, T4 : Compose, T5 : Compose, T6 : Compose, T7 : Compose, T8 : Compose, T9 : Compose, T10 : Compose, T11 : Compose, T12 : Compose> Compose for (T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,) { + fn render(&self, output : &mut impl Output, state : &mut State) { + self.0.render(output, state); + self.1.render(output, state); + self.2.render(output, state); + self.3.render(output, state); + self.4.render(output, state); + self.5.render(output, state); + self.6.render(output, state); + self.7.render(output, state); + self.8.render(output, state); + self.9.render(output, state); + self.10.render(output, state); + self.11.render(output, state); + } +} +impl, T2 : Compose, T3 : Compose, T4 : Compose, T5 : Compose, T6 : Compose, T7 : Compose, T8 : Compose, T9 : Compose, T10 : Compose, T11 : Compose, T12 : Compose, T13 : Compose> Compose for (T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,) { + fn render(&self, output : &mut impl Output, state : &mut State) { + self.0.render(output, state); + self.1.render(output, state); + self.2.render(output, state); + self.3.render(output, state); + self.4.render(output, state); + self.5.render(output, state); + self.6.render(output, state); + self.7.render(output, state); + self.8.render(output, state); + self.9.render(output, state); + self.10.render(output, state); + self.11.render(output, state); + self.12.render(output, state); + } +} +impl, T2 : Compose, T3 : Compose, T4 : Compose, T5 : Compose, T6 : Compose, T7 : Compose, T8 : Compose, T9 : Compose, T10 : Compose, T11 : Compose, T12 : Compose, T13 : Compose, T14 : Compose> Compose for (T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,) { + fn render(&self, output : &mut impl Output, state : &mut State) { + self.0.render(output, state); + self.1.render(output, state); + self.2.render(output, state); + self.3.render(output, state); + self.4.render(output, state); + self.5.render(output, state); + self.6.render(output, state); + self.7.render(output, state); + self.8.render(output, state); + self.9.render(output, state); + self.10.render(output, state); + self.11.render(output, state); + self.12.render(output, state); + self.13.render(output, state); + } +} +impl, T2 : Compose, T3 : Compose, T4 : Compose, T5 : Compose, T6 : Compose, T7 : Compose, T8 : Compose, T9 : Compose, T10 : Compose, T11 : Compose, T12 : Compose, T13 : Compose, T14 : Compose, T15 : Compose> Compose for (T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,) { + fn render(&self, output : &mut impl Output, state : &mut State) { + self.0.render(output, state); + self.1.render(output, state); + self.2.render(output, state); + self.3.render(output, state); + self.4.render(output, state); + self.5.render(output, state); + self.6.render(output, state); + self.7.render(output, state); + self.8.render(output, state); + self.9.render(output, state); + self.10.render(output, state); + self.11.render(output, state); + self.12.render(output, state); + self.13.render(output, state); + self.14.render(output, state); + } +} +impl, T2 : Compose, T3 : Compose, T4 : Compose, T5 : Compose, T6 : Compose, T7 : Compose, T8 : Compose, T9 : Compose, T10 : Compose, T11 : Compose, T12 : Compose, T13 : Compose, T14 : Compose, T15 : Compose, T16 : Compose> Compose for (T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,) { + fn render(&self, output : &mut impl Output, state : &mut State) { + self.0.render(output, state); + self.1.render(output, state); + self.2.render(output, state); + self.3.render(output, state); + self.4.render(output, state); + self.5.render(output, state); + self.6.render(output, state); + self.7.render(output, state); + self.8.render(output, state); + self.9.render(output, state); + self.10.render(output, state); + self.11.render(output, state); + self.12.render(output, state); + self.13.render(output, state); + self.14.render(output, state); + self.15.render(output, state); + } +} +impl, T2 : Compose, T3 : Compose, T4 : Compose, T5 : Compose, T6 : Compose, T7 : Compose, T8 : Compose, T9 : Compose, T10 : Compose, T11 : Compose, T12 : Compose, T13 : Compose, T14 : Compose, T15 : Compose, T16 : Compose, T17 : Compose> Compose for (T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,) { + fn render(&self, output : &mut impl Output, state : &mut State) { + self.0.render(output, state); + self.1.render(output, state); + self.2.render(output, state); + self.3.render(output, state); + self.4.render(output, state); + self.5.render(output, state); + self.6.render(output, state); + self.7.render(output, state); + self.8.render(output, state); + self.9.render(output, state); + self.10.render(output, state); + self.11.render(output, state); + self.12.render(output, state); + self.13.render(output, state); + self.14.render(output, state); + self.15.render(output, state); + self.16.render(output, state); + } +} +impl, T2 : Compose, T3 : Compose, T4 : Compose, T5 : Compose, T6 : Compose, T7 : Compose, T8 : Compose, T9 : Compose, T10 : Compose, T11 : Compose, T12 : Compose, T13 : Compose, T14 : Compose, T15 : Compose, T16 : Compose, T17 : Compose, T18 : Compose> Compose for (T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,) { + fn render(&self, output : &mut impl Output, state : &mut State) { + self.0.render(output, state); + self.1.render(output, state); + self.2.render(output, state); + self.3.render(output, state); + self.4.render(output, state); + self.5.render(output, state); + self.6.render(output, state); + self.7.render(output, state); + self.8.render(output, state); + self.9.render(output, state); + self.10.render(output, state); + self.11.render(output, state); + self.12.render(output, state); + self.13.render(output, state); + self.14.render(output, state); + self.15.render(output, state); + self.16.render(output, state); + self.17.render(output, state); + } +} +impl, T2 : Compose, T3 : Compose, T4 : Compose, T5 : Compose, T6 : Compose, T7 : Compose, T8 : Compose, T9 : Compose, T10 : Compose, T11 : Compose, T12 : Compose, T13 : Compose, T14 : Compose, T15 : Compose, T16 : Compose, T17 : Compose, T18 : Compose, T19 : Compose> Compose for (T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,) { + fn render(&self, output : &mut impl Output, state : &mut State) { + self.0.render(output, state); + self.1.render(output, state); + self.2.render(output, state); + self.3.render(output, state); + self.4.render(output, state); + self.5.render(output, state); + self.6.render(output, state); + self.7.render(output, state); + self.8.render(output, state); + self.9.render(output, state); + self.10.render(output, state); + self.11.render(output, state); + self.12.render(output, state); + self.13.render(output, state); + self.14.render(output, state); + self.15.render(output, state); + self.16.render(output, state); + self.17.render(output, state); + self.18.render(output, state); + } +} +impl, T2 : Compose, T3 : Compose, T4 : Compose, T5 : Compose, T6 : Compose, T7 : Compose, T8 : Compose, T9 : Compose, T10 : Compose, T11 : Compose, T12 : Compose, T13 : Compose, T14 : Compose, T15 : Compose, T16 : Compose, T17 : Compose, T18 : Compose, T19 : Compose, T20 : Compose> Compose for (T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,) { + fn render(&self, output : &mut impl Output, state : &mut State) { + self.0.render(output, state); + self.1.render(output, state); + self.2.render(output, state); + self.3.render(output, state); + self.4.render(output, state); + self.5.render(output, state); + self.6.render(output, state); + self.7.render(output, state); + self.8.render(output, state); + self.9.render(output, state); + self.10.render(output, state); + self.11.render(output, state); + self.12.render(output, state); + self.13.render(output, state); + self.14.render(output, state); + self.15.render(output, state); + self.16.render(output, state); + self.17.render(output, state); + self.18.render(output, state); + self.19.render(output, state); + } +} +impl, T2 : Compose, T3 : Compose, T4 : Compose, T5 : Compose, T6 : Compose, T7 : Compose, T8 : Compose, T9 : Compose, T10 : Compose, T11 : Compose, T12 : Compose, T13 : Compose, T14 : Compose, T15 : Compose, T16 : Compose, T17 : Compose, T18 : Compose, T19 : Compose, T20 : Compose, T21 : Compose> Compose for (T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,) { + fn render(&self, output : &mut impl Output, state : &mut State) { + self.0.render(output, state); + self.1.render(output, state); + self.2.render(output, state); + self.3.render(output, state); + self.4.render(output, state); + self.5.render(output, state); + self.6.render(output, state); + self.7.render(output, state); + self.8.render(output, state); + self.9.render(output, state); + self.10.render(output, state); + self.11.render(output, state); + self.12.render(output, state); + self.13.render(output, state); + self.14.render(output, state); + self.15.render(output, state); + self.16.render(output, state); + self.17.render(output, state); + self.18.render(output, state); + self.19.render(output, state); + self.20.render(output, state); + } +} +impl, T2 : Compose, T3 : Compose, T4 : Compose, T5 : Compose, T6 : Compose, T7 : Compose, T8 : Compose, T9 : Compose, T10 : Compose, T11 : Compose, T12 : Compose, T13 : Compose, T14 : Compose, T15 : Compose, T16 : Compose, T17 : Compose, T18 : Compose, T19 : Compose, T20 : Compose, T21 : Compose, T22 : Compose> Compose for (T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,) { + fn render(&self, output : &mut impl Output, state : &mut State) { + self.0.render(output, state); + self.1.render(output, state); + self.2.render(output, state); + self.3.render(output, state); + self.4.render(output, state); + self.5.render(output, state); + self.6.render(output, state); + self.7.render(output, state); + self.8.render(output, state); + self.9.render(output, state); + self.10.render(output, state); + self.11.render(output, state); + self.12.render(output, state); + self.13.render(output, state); + self.14.render(output, state); + self.15.render(output, state); + self.16.render(output, state); + self.17.render(output, state); + self.18.render(output, state); + self.19.render(output, state); + self.20.render(output, state); + self.21.render(output, state); + } +} +impl, T2 : Compose, T3 : Compose, T4 : Compose, T5 : Compose, T6 : Compose, T7 : Compose, T8 : Compose, T9 : Compose, T10 : Compose, T11 : Compose, T12 : Compose, T13 : Compose, T14 : Compose, T15 : Compose, T16 : Compose, T17 : Compose, T18 : Compose, T19 : Compose, T20 : Compose, T21 : Compose, T22 : Compose, T23 : Compose> Compose for (T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,) { + fn render(&self, output : &mut impl Output, state : &mut State) { + self.0.render(output, state); + self.1.render(output, state); + self.2.render(output, state); + self.3.render(output, state); + self.4.render(output, state); + self.5.render(output, state); + self.6.render(output, state); + self.7.render(output, state); + self.8.render(output, state); + self.9.render(output, state); + self.10.render(output, state); + self.11.render(output, state); + self.12.render(output, state); + self.13.render(output, state); + self.14.render(output, state); + self.15.render(output, state); + self.16.render(output, state); + self.17.render(output, state); + self.18.render(output, state); + self.19.render(output, state); + self.20.render(output, state); + self.21.render(output, state); + self.22.render(output, state); + } +} +impl, T2 : Compose, T3 : Compose, T4 : Compose, T5 : Compose, T6 : Compose, T7 : Compose, T8 : Compose, T9 : Compose, T10 : Compose, T11 : Compose, T12 : Compose, T13 : Compose, T14 : Compose, T15 : Compose, T16 : Compose, T17 : Compose, T18 : Compose, T19 : Compose, T20 : Compose, T21 : Compose, T22 : Compose, T23 : Compose, T24 : Compose> Compose for (T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,) { + fn render(&self, output : &mut impl Output, state : &mut State) { + self.0.render(output, state); + self.1.render(output, state); + self.2.render(output, state); + self.3.render(output, state); + self.4.render(output, state); + self.5.render(output, state); + self.6.render(output, state); + self.7.render(output, state); + self.8.render(output, state); + self.9.render(output, state); + self.10.render(output, state); + self.11.render(output, state); + self.12.render(output, state); + self.13.render(output, state); + self.14.render(output, state); + self.15.render(output, state); + self.16.render(output, state); + self.17.render(output, state); + self.18.render(output, state); + self.19.render(output, state); + self.20.render(output, state); + self.21.render(output, state); + self.22.render(output, state); + self.23.render(output, state); + } +} +impl, T2 : Compose, T3 : Compose, T4 : Compose, T5 : Compose, T6 : Compose, T7 : Compose, T8 : Compose, T9 : Compose, T10 : Compose, T11 : Compose, T12 : Compose, T13 : Compose, T14 : Compose, T15 : Compose, T16 : Compose, T17 : Compose, T18 : Compose, T19 : Compose, T20 : Compose, T21 : Compose, T22 : Compose, T23 : Compose, T24 : Compose, T25 : Compose> Compose for (T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,) { + fn render(&self, output : &mut impl Output, state : &mut State) { + self.0.render(output, state); + self.1.render(output, state); + self.2.render(output, state); + self.3.render(output, state); + self.4.render(output, state); + self.5.render(output, state); + self.6.render(output, state); + self.7.render(output, state); + self.8.render(output, state); + self.9.render(output, state); + self.10.render(output, state); + self.11.render(output, state); + self.12.render(output, state); + self.13.render(output, state); + self.14.render(output, state); + self.15.render(output, state); + self.16.render(output, state); + self.17.render(output, state); + self.18.render(output, state); + self.19.render(output, state); + self.20.render(output, state); + self.21.render(output, state); + self.22.render(output, state); + self.23.render(output, state); + self.24.render(output, state); + } +} +impl, T2 : Compose, T3 : Compose, T4 : Compose, T5 : Compose, T6 : Compose, T7 : Compose, T8 : Compose, T9 : Compose, T10 : Compose, T11 : Compose, T12 : Compose, T13 : Compose, T14 : Compose, T15 : Compose, T16 : Compose, T17 : Compose, T18 : Compose, T19 : Compose, T20 : Compose, T21 : Compose, T22 : Compose, T23 : Compose, T24 : Compose, T25 : Compose, T26 : Compose> Compose for (T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,) { + fn render(&self, output : &mut impl Output, state : &mut State) { + self.0.render(output, state); + self.1.render(output, state); + self.2.render(output, state); + self.3.render(output, state); + self.4.render(output, state); + self.5.render(output, state); + self.6.render(output, state); + self.7.render(output, state); + self.8.render(output, state); + self.9.render(output, state); + self.10.render(output, state); + self.11.render(output, state); + self.12.render(output, state); + self.13.render(output, state); + self.14.render(output, state); + self.15.render(output, state); + self.16.render(output, state); + self.17.render(output, state); + self.18.render(output, state); + self.19.render(output, state); + self.20.render(output, state); + self.21.render(output, state); + self.22.render(output, state); + self.23.render(output, state); + self.24.render(output, state); + self.25.render(output, state); + } +} +impl, T2 : Compose, T3 : Compose, T4 : Compose, T5 : Compose, T6 : Compose, T7 : Compose, T8 : Compose, T9 : Compose, T10 : Compose, T11 : Compose, T12 : Compose, T13 : Compose, T14 : Compose, T15 : Compose, T16 : Compose, T17 : Compose, T18 : Compose, T19 : Compose, T20 : Compose, T21 : Compose, T22 : Compose, T23 : Compose, T24 : Compose, T25 : Compose, T26 : Compose, T27 : Compose> Compose for (T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,) { + fn render(&self, output : &mut impl Output, state : &mut State) { + self.0.render(output, state); + self.1.render(output, state); + self.2.render(output, state); + self.3.render(output, state); + self.4.render(output, state); + self.5.render(output, state); + self.6.render(output, state); + self.7.render(output, state); + self.8.render(output, state); + self.9.render(output, state); + self.10.render(output, state); + self.11.render(output, state); + self.12.render(output, state); + self.13.render(output, state); + self.14.render(output, state); + self.15.render(output, state); + self.16.render(output, state); + self.17.render(output, state); + self.18.render(output, state); + self.19.render(output, state); + self.20.render(output, state); + self.21.render(output, state); + self.22.render(output, state); + self.23.render(output, state); + self.24.render(output, state); + self.25.render(output, state); + self.26.render(output, state); + } +} +impl, T2 : Compose, T3 : Compose, T4 : Compose, T5 : Compose, T6 : Compose, T7 : Compose, T8 : Compose, T9 : Compose, T10 : Compose, T11 : Compose, T12 : Compose, T13 : Compose, T14 : Compose, T15 : Compose, T16 : Compose, T17 : Compose, T18 : Compose, T19 : Compose, T20 : Compose, T21 : Compose, T22 : Compose, T23 : Compose, T24 : Compose, T25 : Compose, T26 : Compose, T27 : Compose, T28 : Compose> Compose for (T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,) { + fn render(&self, output : &mut impl Output, state : &mut State) { + self.0.render(output, state); + self.1.render(output, state); + self.2.render(output, state); + self.3.render(output, state); + self.4.render(output, state); + self.5.render(output, state); + self.6.render(output, state); + self.7.render(output, state); + self.8.render(output, state); + self.9.render(output, state); + self.10.render(output, state); + self.11.render(output, state); + self.12.render(output, state); + self.13.render(output, state); + self.14.render(output, state); + self.15.render(output, state); + self.16.render(output, state); + self.17.render(output, state); + self.18.render(output, state); + self.19.render(output, state); + self.20.render(output, state); + self.21.render(output, state); + self.22.render(output, state); + self.23.render(output, state); + self.24.render(output, state); + self.25.render(output, state); + self.26.render(output, state); + self.27.render(output, state); + } +} +impl, T2 : Compose, T3 : Compose, T4 : Compose, T5 : Compose, T6 : Compose, T7 : Compose, T8 : Compose, T9 : Compose, T10 : Compose, T11 : Compose, T12 : Compose, T13 : Compose, T14 : Compose, T15 : Compose, T16 : Compose, T17 : Compose, T18 : Compose, T19 : Compose, T20 : Compose, T21 : Compose, T22 : Compose, T23 : Compose, T24 : Compose, T25 : Compose, T26 : Compose, T27 : Compose, T28 : Compose, T29 : Compose> Compose for (T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,) { + fn render(&self, output : &mut impl Output, state : &mut State) { + self.0.render(output, state); + self.1.render(output, state); + self.2.render(output, state); + self.3.render(output, state); + self.4.render(output, state); + self.5.render(output, state); + self.6.render(output, state); + self.7.render(output, state); + self.8.render(output, state); + self.9.render(output, state); + self.10.render(output, state); + self.11.render(output, state); + self.12.render(output, state); + self.13.render(output, state); + self.14.render(output, state); + self.15.render(output, state); + self.16.render(output, state); + self.17.render(output, state); + self.18.render(output, state); + self.19.render(output, state); + self.20.render(output, state); + self.21.render(output, state); + self.22.render(output, state); + self.23.render(output, state); + self.24.render(output, state); + self.25.render(output, state); + self.26.render(output, state); + self.27.render(output, state); + self.28.render(output, state); + } +} +impl, T2 : Compose, T3 : Compose, T4 : Compose, T5 : Compose, T6 : Compose, T7 : Compose, T8 : Compose, T9 : Compose, T10 : Compose, T11 : Compose, T12 : Compose, T13 : Compose, T14 : Compose, T15 : Compose, T16 : Compose, T17 : Compose, T18 : Compose, T19 : Compose, T20 : Compose, T21 : Compose, T22 : Compose, T23 : Compose, T24 : Compose, T25 : Compose, T26 : Compose, T27 : Compose, T28 : Compose, T29 : Compose, T30 : Compose> Compose for (T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,) { + fn render(&self, output : &mut impl Output, state : &mut State) { + self.0.render(output, state); + self.1.render(output, state); + self.2.render(output, state); + self.3.render(output, state); + self.4.render(output, state); + self.5.render(output, state); + self.6.render(output, state); + self.7.render(output, state); + self.8.render(output, state); + self.9.render(output, state); + self.10.render(output, state); + self.11.render(output, state); + self.12.render(output, state); + self.13.render(output, state); + self.14.render(output, state); + self.15.render(output, state); + self.16.render(output, state); + self.17.render(output, state); + self.18.render(output, state); + self.19.render(output, state); + self.20.render(output, state); + self.21.render(output, state); + self.22.render(output, state); + self.23.render(output, state); + self.24.render(output, state); + self.25.render(output, state); + self.26.render(output, state); + self.27.render(output, state); + self.28.render(output, state); + self.29.render(output, state); + } +} +impl, T2 : Compose, T3 : Compose, T4 : Compose, T5 : Compose, T6 : Compose, T7 : Compose, T8 : Compose, T9 : Compose, T10 : Compose, T11 : Compose, T12 : Compose, T13 : Compose, T14 : Compose, T15 : Compose, T16 : Compose, T17 : Compose, T18 : Compose, T19 : Compose, T20 : Compose, T21 : Compose, T22 : Compose, T23 : Compose, T24 : Compose, T25 : Compose, T26 : Compose, T27 : Compose, T28 : Compose, T29 : Compose, T30 : Compose, T31 : Compose> Compose for (T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,) { + fn render(&self, output : &mut impl Output, state : &mut State) { + self.0.render(output, state); + self.1.render(output, state); + self.2.render(output, state); + self.3.render(output, state); + self.4.render(output, state); + self.5.render(output, state); + self.6.render(output, state); + self.7.render(output, state); + self.8.render(output, state); + self.9.render(output, state); + self.10.render(output, state); + self.11.render(output, state); + self.12.render(output, state); + self.13.render(output, state); + self.14.render(output, state); + self.15.render(output, state); + self.16.render(output, state); + self.17.render(output, state); + self.18.render(output, state); + self.19.render(output, state); + self.20.render(output, state); + self.21.render(output, state); + self.22.render(output, state); + self.23.render(output, state); + self.24.render(output, state); + self.25.render(output, state); + self.26.render(output, state); + self.27.render(output, state); + self.28.render(output, state); + self.29.render(output, state); + self.30.render(output, state); + } +}