├── .gitignore ├── .prettierrc.json ├── examples ├── basic │ ├── templates │ │ ├── splash.html.jinja2 │ │ ├── hello.html.jinja2 │ │ ├── navbar.html.jinja2 │ │ └── index.html.jinja2 │ ├── Cargo.toml │ ├── style │ │ ├── .main.css │ │ └── header.css │ └── src │ │ └── main.rs ├── crud │ ├── migrations │ │ └── 20230807135240_todos.sql │ ├── assets │ │ ├── trash.svg │ │ └── edit.svg │ ├── README.md │ ├── Cargo.toml │ ├── templates │ │ ├── todo-edit.html.j2 │ │ ├── todo.html.j2 │ │ └── index.html.j2 │ └── src │ │ └── main.rs └── basic-trillium │ ├── Cargo.toml │ ├── templates │ └── index.html.j2 │ └── src │ └── main.rs ├── benches ├── templates │ ├── form_and_context.html.jinja2 │ └── plain.html.jinja2 └── render.rs ├── .cargo └── config.toml ├── src ├── runtime │ ├── mod.rs │ ├── runtime_tokio.rs │ └── runtime_smol.rs ├── log.rs ├── framework │ ├── mod.rs │ ├── framework_trillium.rs │ └── framework_axum.rs ├── config.rs ├── hmr.js ├── style.rs ├── template.rs ├── lib.rs ├── render.rs └── hmr.rs ├── assets ├── hyro-dark.svg └── hyro-light.svg ├── .vscode └── settings.json ├── README.md ├── Cargo.toml ├── CHANGELOG.md └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.db 3 | perf.data* 4 | flamegraph.svg -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 2, 3 | "useTabs": true 4 | } 5 | -------------------------------------------------------------------------------- /examples/basic/templates/splash.html.jinja2: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/basic/templates/hello.html.jinja2: -------------------------------------------------------------------------------- 1 |

Hello, {{ form.name }}! This is HMR!

-------------------------------------------------------------------------------- /benches/templates/form_and_context.html.jinja2: -------------------------------------------------------------------------------- 1 |

2 | {{greeting}}, {{ form.name }}! 3 |

-------------------------------------------------------------------------------- /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [target.x86_64-unknown-linux-gnu] 2 | linker = "/usr/bin/clang" 3 | rustflags = ["-Clink-arg=-fuse-ld=lld", "-Clink-arg=-Wl,--no-rosegment"] 4 | -------------------------------------------------------------------------------- /examples/crud/migrations/20230807135240_todos.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS todos ( 2 | id INTEGER PRIMARY KEY NOT NULL, 3 | description TEXT NOT NULL, 4 | created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, 5 | updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, 6 | done BOOLEAN NOT NULL DEFAULT 0 7 | ); -------------------------------------------------------------------------------- /src/runtime/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(debug_assertions)] 2 | cfg_if::cfg_if! { 3 | if #[cfg(feature = "runtime-tokio")] { 4 | mod runtime_tokio; 5 | pub use runtime_tokio::*; 6 | } else if #[cfg(feature = "runtime-smol")] { 7 | mod runtime_smol; 8 | pub use runtime_smol::*; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/basic-trillium/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "example-basic-trillium" 3 | version = "0.1.0" 4 | edition = "2021" 5 | publish = false 6 | 7 | [dependencies] 8 | hyro = { path = "../../", features = ["framework-trillium", "runtime-smol"] } 9 | trillium = "0.2" 10 | trillium-router = "0.4" 11 | trillium-smol = "0.4" 12 | -------------------------------------------------------------------------------- /examples/basic/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "example-basic" 3 | version = "0.1.0" 4 | edition = "2021" 5 | publish = false 6 | 7 | [dependencies] 8 | axum = "0.7" 9 | tokio = { version = "1", features = ["full"] } 10 | hyro = { path = "../../", features = ["framework-axum"] } 11 | tower-http = { version = "0.5", default-features = false, features = ["fs"] } 12 | -------------------------------------------------------------------------------- /examples/basic/style/.main.css: -------------------------------------------------------------------------------- 1 | @import "header.css"; 2 | 3 | :root:not([data-theme]) { 4 | --background-color: #1e293b !important; 5 | --color: white; 6 | --fake-blur: contrast(0.05) brightness(0.5) sepia() hue-rotate(180deg) 7 | contrast(1.6) saturate(0.8); 8 | --primary: #9faff4; 9 | background-image: url("/assets/topography.svg"); 10 | background-size: cover; 11 | } 12 | 13 | .flex { 14 | display: flex; 15 | } 16 | -------------------------------------------------------------------------------- /examples/basic-trillium/templates/index.html.j2: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | HYRO Trillium Example 8 | 9 | 10 | 11 | {% if form %} 12 |

Hello, {{form.name}}!

13 | {% else %} 14 |

Add ?name=<your name here> to the URL!

15 | {% endif %} 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /examples/crud/assets/trash.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | -------------------------------------------------------------------------------- /examples/crud/assets/edit.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | -------------------------------------------------------------------------------- /examples/basic/templates/navbar.html.jinja2: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |
6 | carteris.online 7 |
8 | {{ module("splash") }} 9 |
10 |
11 |
12 | 16 |
17 |
18 |
-------------------------------------------------------------------------------- /src/log.rs: -------------------------------------------------------------------------------- 1 | macro_rules! error { 2 | ($($arg:tt)*) => { 3 | eprintln!("\x1b[31;1m{}\x1b[0m", format_args!($($arg)*)) 4 | }; 5 | } 6 | 7 | #[cfg(debug_assertions)] 8 | macro_rules! background { 9 | ($($arg:tt)*) => { 10 | eprintln!("\x1b[90m{}\x1b[0m", format_args!($($arg)*)) 11 | }; 12 | } 13 | 14 | macro_rules! data { 15 | ($($arg:tt)*) => { 16 | eprintln!("\x1b[33m{}\x1b[0m", format_args!($($arg)*)) 17 | }; 18 | } 19 | macro_rules! info { 20 | ($($arg:tt)*) => { 21 | eprintln!("\x1b[32;1m{}\x1b[0m", format_args!($($arg)*)) 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /examples/basic-trillium/src/main.rs: -------------------------------------------------------------------------------- 1 | use hyro::{context, prelude::*}; 2 | use trillium::Conn; 3 | use trillium_router::Router; 4 | 5 | fn main() { 6 | hyro::config::set_template_file_extension("html.j2").unwrap(); 7 | 8 | trillium_smol::config() 9 | .with_host("0.0.0.0") 10 | .with_port(1380) 11 | .with_nodelay() 12 | .without_signals() 13 | .run(Router::new().get("/", index).with_hmr()) 14 | } 15 | 16 | async fn index(mut conn: Conn) -> Conn { 17 | let template = conn.template().await; 18 | conn.with_body(template.render(context!()).to_string()) 19 | } 20 | -------------------------------------------------------------------------------- /examples/crud/README.md: -------------------------------------------------------------------------------- 1 | # Example - CRUD 2 | 3 | A basic CRUD (Create, Read, Update, Delete) application for managing TODOs. Uses SQLite globally to persist state. 4 | 5 | ## Additional Libraries Used 6 | 7 | - [SQLx](https://github.com/launchbadge/sqlx) for querying SQLite. 8 | - [hyperscript](https://hyperscript.org/) for updating client-side templates. The attribute `_=` 9 | is used to define hyperscript behavior for UI elements. 10 | - [Pico.css](https://picocss.com/) for the page's global semantic style. 11 | - [basicGrid](https://basicgrid.electerious.com/) for simple flexbox-based row/column layouts. 12 | -------------------------------------------------------------------------------- /examples/crud/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "example-crud" 3 | version = "0.1.0" 4 | edition = "2021" 5 | publish = false 6 | 7 | [dependencies] 8 | axum = "0.7" 9 | tokio = { version = "1", features = ["full"] } 10 | hyro = { path = "../../", features = ["framework-axum"] } 11 | tower-http = { version = "0.5", default-features = false, features = ["fs"] } 12 | sqlx = { version = "0.7", features = [ 13 | "runtime-tokio-native-tls", 14 | "sqlite", 15 | "chrono", 16 | ] } 17 | eyre = "0.6" 18 | serde = { version = "1", features = ["derive"] } 19 | chrono = { version = "0.4.26", features = ["serde"] } 20 | -------------------------------------------------------------------------------- /examples/crud/templates/todo-edit.html.j2: -------------------------------------------------------------------------------- 1 |
2 | {% if form %} 3 | 4 | {% endif %} 5 |
6 | 8 |
9 | 13 |
-------------------------------------------------------------------------------- /assets/hyro-dark.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 8 | -------------------------------------------------------------------------------- /assets/hyro-light.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 8 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "emmet.includeLanguages": { 3 | "jinja-html": "html" 4 | }, 5 | 6 | // go away yucky 7 | "files.exclude": { 8 | "target": true, 9 | "Cargo.lock": true 10 | }, 11 | 12 | // If you've enabled autosave, then this settings lets you witness 13 | // the incredible speed of HYRO's HMR 14 | "files.autoSaveDelay": 0, 15 | "rust-analyzer.cargo.features": ["framework-trillium", "runtime-smol"], 16 | "rust-analyzer.cargo.extraEnv": { 17 | "DATABASE_URL": "sqlite:/tmp/hyro.db" 18 | }, 19 | "sqltools.useNodeRuntime": true, 20 | "sqltools.connections": [ 21 | { 22 | "previewLimit": 50, 23 | "driver": "SQLite", 24 | "name": "hyro", 25 | "database": "/tmp/hyro.db" 26 | } 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /src/runtime/runtime_tokio.rs: -------------------------------------------------------------------------------- 1 | pub use futures::channel::mpsc::channel as mpsc_channel; 2 | pub use futures::channel::mpsc::Receiver as MpscReceiver; 3 | pub use futures::executor::block_on; 4 | pub use futures::{SinkExt, StreamExt}; 5 | 6 | pub use tokio::spawn; 7 | pub use tokio::sync::broadcast::channel as broadcast_channel; 8 | pub use tokio::sync::broadcast::Receiver as BroadcastReceiver; 9 | pub use tokio::sync::broadcast::Sender as BroadcastSender; 10 | 11 | #[cfg(debug_assertions)] 12 | pub fn instant_now() -> tokio::time::Instant { 13 | tokio::time::Instant::now() 14 | } 15 | 16 | pub fn broadcast_subscribe( 17 | broadcast: &(BroadcastSender, BroadcastReceiver), 18 | ) -> BroadcastReceiver { 19 | broadcast.0.subscribe() 20 | } 21 | -------------------------------------------------------------------------------- /src/runtime/runtime_smol.rs: -------------------------------------------------------------------------------- 1 | 2 | pub use async_channel::bounded as mpsc_channel; 3 | pub use async_channel::bounded as broadcast_channel; 4 | pub use async_channel::Receiver as MpscReceiver; 5 | pub use async_channel::Receiver as BroadcastReceiver; 6 | pub use async_channel::Sender as BroadcastSender; 7 | pub use async_io::block_on; 8 | pub use futures_lite::StreamExt; 9 | 10 | #[cfg(debug_assertions)] 11 | pub fn spawn(future: F) 12 | where 13 | F::Output: Send + 'static, 14 | { 15 | async_global_executor::spawn(future).detach(); 16 | } 17 | 18 | #[cfg(debug_assertions)] 19 | pub fn broadcast_subscribe( 20 | broadcast: &(BroadcastSender, BroadcastReceiver), 21 | ) -> &BroadcastReceiver { 22 | &broadcast.1 23 | } 24 | 25 | #[cfg(debug_assertions)] 26 | pub fn instant_now() -> std::time::Instant { 27 | std::time::Instant::now() 28 | } 29 | -------------------------------------------------------------------------------- /src/framework/mod.rs: -------------------------------------------------------------------------------- 1 | cfg_if::cfg_if! { 2 | if #[cfg(feature = "framework-axum")] { 3 | mod framework_axum; 4 | pub use framework_axum::*; 5 | pub mod prelude { 6 | pub use super::framework_axum::RouterExt; 7 | } 8 | } else if #[cfg(feature = "framework-trillium")] { 9 | mod framework_trillium; 10 | #[cfg(debug_assertions)] 11 | pub use framework_trillium::*; 12 | pub mod prelude { 13 | pub use super::framework_trillium::RouterExt; 14 | pub use super::framework_trillium::ConnExt; 15 | } 16 | } else { 17 | pub mod prelude {} 18 | } 19 | } 20 | 21 | #[cfg(not(feature = "framework-axum"))] 22 | pub type RenderedTemplate = std::borrow::Cow<'static, str>; 23 | 24 | #[cfg(not(feature = "framework-axum"))] 25 | pub fn into_rendered_template(cow: std::borrow::Cow<'static, str>) -> RenderedTemplate { 26 | cow 27 | } 28 | -------------------------------------------------------------------------------- /benches/render.rs: -------------------------------------------------------------------------------- 1 | use std::collections::BTreeMap; 2 | 3 | use criterion::*; 4 | use hyro::{context, Template}; 5 | use tap::Tap; 6 | 7 | pub fn render_benchmark(c: &mut Criterion) { 8 | hyro::config::set_template_dir("benches/templates").unwrap(); 9 | 10 | c.bench_function("render_form_and_context", |b| { 11 | b.iter(|| { 12 | Template { 13 | path: "/form_and_context".into(), 14 | form: BTreeMap::new().tap_mut(|h| { 15 | h.insert("name".to_string(), "world".to_string()); 16 | }), 17 | } 18 | .render(context! { 19 | greeting => "Hello" 20 | }) 21 | }); 22 | }); 23 | 24 | c.bench_function("render_plain", |b| { 25 | b.iter(|| { 26 | Template { 27 | path: "/plain".into(), 28 | form: BTreeMap::new(), 29 | } 30 | .render(context!()) 31 | }); 32 | }); 33 | } 34 | 35 | criterion_group!(benches, render_benchmark); 36 | criterion_main!(benches); 37 | -------------------------------------------------------------------------------- /examples/crud/templates/todo.html.j2: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 11 |
12 |

14 | {{ form.description }} 15 |

16 |
17 | 19 | 21 |
22 |
-------------------------------------------------------------------------------- /src/config.rs: -------------------------------------------------------------------------------- 1 | use parking_lot::MutexGuard; 2 | use std::path::{Path, PathBuf}; 3 | 4 | use crate::render::ENVIRONMENT; 5 | use crate::{TEMPLATE_DIR, TEMPLATE_EXTENSION}; 6 | pub use lightningcss::stylesheet::ParserOptions; 7 | pub use lightningcss::targets::Targets; 8 | 9 | pub fn set_template_dir>(dir: T) -> Result<(), PathBuf> { 10 | let dir = dir.as_ref().to_path_buf(); 11 | if !dir.exists() { 12 | error!("Template directory does not exist: {}", dir.display()); 13 | } else if dir.is_file() { 14 | error!("Template directory is a file: {}", dir.display()); 15 | } 16 | 17 | TEMPLATE_DIR.set(dir) 18 | } 19 | 20 | pub fn set_template_file_extension>(extension: S) -> Result<(), String> { 21 | let extension = extension.as_ref().trim_start_matches('.'); 22 | TEMPLATE_EXTENSION.set(format!(".{}", extension)) 23 | } 24 | 25 | pub fn set_style_options(options: ParserOptions<'static, 'static>) { 26 | crate::style::STYLE_OPTIONS.set(options).unwrap(); 27 | } 28 | 29 | pub fn set_style_targets(targets: Targets) { 30 | crate::style::STYLE_TARGETS.set(targets).unwrap(); 31 | } 32 | 33 | pub fn modify_template_env>)>( 34 | func: F, 35 | ) { 36 | func(&mut ENVIRONMENT.lock()); 37 | } 38 | -------------------------------------------------------------------------------- /examples/basic/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::borrow::Cow; 2 | 3 | use axum::response::Html; 4 | use axum::routing::get; 5 | 6 | use hyro::prelude::*; 7 | use hyro::{context, Template}; 8 | use tower_http::services::ServeDir; 9 | 10 | #[tokio::main] 11 | async fn main() -> Result<(), std::io::Error> { 12 | let router = axum::Router::new() 13 | .route("/", get(index)) 14 | .route("/hello", get(hello)) 15 | .route("/navbar", get(navbar)) 16 | .route("/splash", get(splash)) 17 | .with_bundled_css("/main.css", "style/.main.css") 18 | .nest_service("/assets", ServeDir::new("assets")) 19 | .into_service_with_hmr(); 20 | 21 | axum::Server::from_tcp(hyro::bind("0.0.0.0:1380")) 22 | .unwrap() 23 | .serve(router) 24 | .await 25 | .unwrap(); 26 | 27 | Ok(()) 28 | } 29 | 30 | async fn index(template: Template) -> Html> { 31 | template.render(context! { 32 | title => "Home", 33 | }) 34 | } 35 | 36 | async fn navbar(template: Template) -> Html> { 37 | template.render(context!()) 38 | } 39 | 40 | async fn hello(template: Template) -> Html> { 41 | template.render(context!()) 42 | } 43 | 44 | async fn splash(template: Template) -> Html> { 45 | template.render(context!()) 46 | } 47 | -------------------------------------------------------------------------------- /examples/crud/templates/index.html.j2: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | HYRO Todo Example 8 | 9 | 10 | 11 | 12 | 13 | 23 | 24 | 25 | 26 |
27 |
28 |
29 |

30 |

31 |
32 | 33 | {% for todo_data in todos %} 34 | {{ module("todo", todo_data) }} 35 | {% endfor %} 36 |
37 |
38 |

+ New

40 |
41 |
42 | 43 | 44 | -------------------------------------------------------------------------------- /examples/basic/style/header.css: -------------------------------------------------------------------------------- 1 | body > header { 2 | border-radius: 4px; 3 | position: fixed; 4 | padding: 0; 5 | margin: 1em; 6 | width: auto; 7 | 8 | & aside { 9 | color: var(--primary); 10 | font-size: small; 11 | margin-top: -4px; 12 | } 13 | 14 | & > details[role="list"] { 15 | margin-bottom: 0em; 16 | 17 | & hgroup[role="img"] { 18 | margin: 0; 19 | 20 | & > span { 21 | font-weight: 600; 22 | color: #93a1b6; 23 | } 24 | } 25 | 26 | & > summary:not([role]) { 27 | width: fit-content; 28 | border: none; 29 | border-radius: 4px; 30 | color: white !important; 31 | background-color: #fff1 !important; 32 | backdrop-filter: var(--fake-blur); 33 | padding: 2em 2em 2.25em 2em; 34 | 35 | & > * { 36 | top: -1em; 37 | position: relative; 38 | } 39 | 40 | &:hover { 41 | cursor: pointer; 42 | } 43 | 44 | &:focus { 45 | outline: 1px solid var(--primary); 46 | } 47 | } 48 | 49 | & > summary::after { 50 | content: url("/assets/chevron.svg"); 51 | top: -1em; 52 | position: relative; 53 | background: none; 54 | margin-left: 1em; 55 | width: 2em; 56 | transition: transform 0.1s; 57 | } 58 | 59 | & > [role="listbox"] { 60 | border-radius: 4px; 61 | margin-top: 0.5em; 62 | background: linear-gradient(to bottom right, #3a4d69, #2b384b); 63 | display: grid; 64 | grid-template-columns: 1fr; 65 | grid-template-rows: repeat(8, 1fr); 66 | grid-column-gap: 3px; 67 | grid-row-gap: 3px; 68 | 69 | & > button[role="link"].product-card { 70 | color: white; 71 | padding: 1em 1.5em; 72 | display: flex; 73 | flex-direction: column; 74 | row-gap: 0.5em; 75 | background: linear-gradient( 76 | to bottom right, 77 | #fff0, 78 | var(--primary) 300% 79 | ); 80 | grid-row: span 3; 81 | } 82 | } 83 | } 84 | 85 | &:hover > details[role="list"] > summary::after, 86 | & > details[role="list"] > summary:focus::after { 87 | transform: rotate(90deg) translateX(0.25em) translateY(-0.25em); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/hmr.js: -------------------------------------------------------------------------------- 1 | const socket = new WebSocket(`ws://${location.host}/hmr`); 2 | 3 | // i apologize for the rest of this file 4 | 5 | socket.addEventListener("message", async (event) => { 6 | if (typeof event.data === "string") { 7 | if (event.data !== "you up?") { 8 | const elements = document.querySelectorAll(`[hmr-path="${event.data}"]`); 9 | const indexes = new Uint32Array(elements.length); 10 | let i = 0; 11 | for (const element of elements) { 12 | if (element.tagName === "HTML") { 13 | socket.send("r"); 14 | location.reload(); 15 | } 16 | 17 | indexes[i] = parseInt(element.getAttribute("hmr-index"), 10); 18 | i++; 19 | } 20 | 21 | socket.send("c"); 22 | socket.send(indexes); 23 | for (const element of elements) { 24 | const response = await fetch(event.data).then((res) => res.text()); 25 | element.outerHTML = response; 26 | if (response.includes("hx-")) { 27 | // @ts-ignore 28 | htmx.process(document.body); 29 | } 30 | } 31 | 32 | let j = 0; 33 | document 34 | .querySelectorAll(`[hmr-path="${event.data}"]:not([hmr-index])`) 35 | .forEach((element) => { 36 | element.setAttribute("hmr-index", indexes[j].toString()); 37 | j++; 38 | }); 39 | } 40 | } else if (event.data.size === 1) { 41 | document.querySelector( 42 | "head > :is(link[href='/main.css'], style#hmr)" 43 | ).outerHTML = ``; 46 | } 47 | }); 48 | 49 | let hmrIndexes = {}; 50 | document.addEventListener("DOMContentLoaded", () => { 51 | document.body.addEventListener("htmx:load", (event) => { 52 | let hmrPath; 53 | // @ts-ignore 54 | if (event.detail.elt.attributes.getNamedItem("hmr-path") !== null) { 55 | // @ts-ignore 56 | hmrPath = event.detail.elt.attributes.getNamedItem("hmr-path"); 57 | } else { 58 | hmrPath = 59 | // @ts-ignore 60 | event.detail.elt.parentElement.attributes.getNamedItem("hmr-path"); 61 | } 62 | if (!hmrIndexes[hmrPath.value]) { 63 | hmrIndexes[hmrPath.value] = 0; 64 | } 65 | 66 | document 67 | .querySelectorAll(`[hmr-path="${hmrPath.value}"]:not([hmr-index])`) 68 | .forEach((element) => { 69 | element.setAttribute( 70 | "hmr-index", 71 | (hmrIndexes[hmrPath.value]++).toString() 72 | ); 73 | }); 74 | }); 75 | }); 76 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | HYRO logo 2 | HYRO logo 3 | 4 | ### HYRO 5 | 6 | noun 7 | /ˈhɪr.oʊ/ 8 | 9 | 1. A : acronym for "Hypermedia Rust Orchestration" 10 | B : a crate that extends existing frameworks like [Axum](https://github.com/tokio-rs/axum/) with new functionality, like 11 | rendering [Jinja Templates](https://github.com/mitsuhiko/minijinja) on the server, 12 | [bundling css](https://github.com/parcel-bundler/lightningcss), and a better developer experience. 13 | C : a powerful HMR framework for [hypermedia systems](https://hypermedia.systems/) like [HTMX](https://htmx.org/). 14 | D : the equivalent of [Rails](https://rubyonrails.org/) for nerds 15 | 16 | ## Usage and Examples 17 | 18 | - More in-depth examples can be found in the [examples folder](examples/). Make sure you `cd` to the path containing 19 | the templates and style folders before running or _you will get a file-not-found error!_ 20 | 21 | Let's start with dependencies. We'll be using axum as our framework, and tokio as our runtime: 22 | 23 | ```sh 24 | cargo new hyro-getting-started 25 | 26 | cargo add hyro -F framework-axum 27 | cargo add axum 28 | cargo add tokio -F full 29 | mkdir templates 30 | ``` 31 | 32 | HYRO templates use Jinja2. Let's start with a basic one: 33 | 34 | `templates/hello.html.jinja2` 35 | 36 | ```html 37 |

Hello, {{ name }}!

38 | ``` 39 | 40 | Then we can set up our boilerplate: 41 | 42 | `src/main.rs` 43 | 44 | ```rust 45 | use std::borrow::Cow; 46 | 47 | use axum::response::Html; 48 | use axum::{routing, Router, Server}; 49 | use hyro::prelude::*; 50 | use hyro::{context, Template}; 51 | 52 | #[tokio::main] 53 | async fn main() { 54 | let router = Router::new() 55 | .route("/hello", routing::get(hello)) 56 | .into_service_with_hmr(); 57 | 58 | Server::from_tcp(hyro::bind("0.0.0.0:1380"))).unwrap() 59 | .serve(router) 60 | .await 61 | .unwrap(); 62 | } 63 | 64 | async fn hello(template: Template) -> Html> { 65 | template.render(context! { 66 | name => "World", 67 | }) 68 | } 69 | ``` 70 | 71 | Now if we navigate to 'localhost:1380/hello', we can read our message! If you're running in 72 | debug mode, you can edit `templates/hello.html.jinja2` and the HMR should kick in. 73 | -------------------------------------------------------------------------------- /src/style.rs: -------------------------------------------------------------------------------- 1 | use std::path::{Path, PathBuf}; 2 | 3 | pub use lightningcss; 4 | pub use lightningcss::css_modules::{Config, Pattern}; 5 | pub use lightningcss::stylesheet::{ParserFlags, ParserOptions}; 6 | pub use lightningcss::targets::{Browsers, Features, Targets}; 7 | 8 | use lightningcss::bundler::{Bundler, FileProvider}; 9 | use lightningcss::stylesheet::PrinterOptions; 10 | use once_cell::sync::{Lazy, OnceCell}; 11 | 12 | static DEFAULT_STYLE_OPTIONS: Lazy = Lazy::new(|| ParserOptions { 13 | flags: ParserFlags::NESTING | ParserFlags::CUSTOM_MEDIA, 14 | ..Default::default() 15 | }); 16 | 17 | static DEFAULT_STYLE_TARGETS: Lazy = Lazy::new(|| Targets { 18 | browsers: Some(Browsers { 19 | android: None, 20 | chrome: Some(6160384), 21 | edge: Some(6291456), 22 | firefox: Some(6160384), 23 | ie: Some(720896), 24 | ios_saf: Some(786944), 25 | opera: Some(5308416), 26 | safari: Some(852224), 27 | samsung: None, 28 | }), 29 | ..Default::default() 30 | }); 31 | 32 | pub(crate) static STYLE_FILE_PROVIDER: Lazy = Lazy::new(FileProvider::new); 33 | #[cfg(not(debug_assertions))] 34 | pub(crate) static MAIN_CSS: OnceCell = OnceCell::new(); 35 | #[cfg(debug_assertions)] 36 | pub(crate) static STYLE_MAIN_FILE: OnceCell = OnceCell::new(); 37 | pub(crate) static STYLE_OPTIONS: OnceCell = OnceCell::new(); 38 | pub(crate) static STYLE_TARGETS: OnceCell = OnceCell::new(); 39 | 40 | #[derive(Debug)] 41 | pub(crate) enum TransformCSSError<'a> { 42 | BundleError(lightningcss::bundler::BundleErrorKind<'a, std::io::Error>), 43 | PrinterError(lightningcss::error::PrinterErrorKind), 44 | } 45 | 46 | /// Utility function for bundling and minifying CSS. 47 | pub(crate) fn transform_css<'a>(path: &PathBuf) -> Result> { 48 | // 1: Initialize the bundler state 49 | let mut bundler = Bundler::new( 50 | &*STYLE_FILE_PROVIDER, 51 | None, 52 | STYLE_OPTIONS 53 | .get() 54 | .unwrap_or(&DEFAULT_STYLE_OPTIONS) 55 | .clone(), 56 | ); 57 | 58 | // 2: Bundle the CSS by following @import statements 59 | match bundler.bundle(Path::new(&path)) { 60 | Ok(stylesheet) => { 61 | // 3: Since step 2 produced a rust-native stylesheet structure, we convert it back to CSS. 62 | let printed = stylesheet.to_css(PrinterOptions { 63 | minify: true, 64 | targets: *STYLE_TARGETS.get().unwrap_or(&DEFAULT_STYLE_TARGETS), 65 | ..Default::default() 66 | }); 67 | 68 | // 4: Only return the serialized CSS in the .code field 69 | match printed { 70 | Ok(printed) => Ok(printed.code), 71 | Err(e) => Err(TransformCSSError::PrinterError(e.kind)), 72 | } 73 | } 74 | Err(e) => Err(TransformCSSError::BundleError(e.kind)), 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hyro" 3 | version = "0.5.0" 4 | edition = "2021" 5 | description = "Hypermedia Rust Orchestration - a refreshing web framework" 6 | authors = ["Carter Reeb "] 7 | repository = "https://github.com/carterisonline/hyro" 8 | homepage = "https://github.com/carterisonline/hyro" 9 | license = "MIT" 10 | documentation = "https://docs.rs/hyro" 11 | readme = "README.md" 12 | categories = ["http-server", "web-programming", "template-engine"] 13 | 14 | [dev-dependencies] 15 | criterion = "0.5" 16 | 17 | [profile.bench] 18 | debug = true 19 | 20 | [[bench]] 21 | name = "render" 22 | harness = false 23 | 24 | [workspace] 25 | members = ["examples/basic-trillium"] 26 | 27 | [features] 28 | framework-axum = ["runtime-tokio", "dep:axum", "dep:tower-http"] 29 | framework-trillium = [ 30 | "dep:trillium", 31 | "dep:trillium-router", 32 | "dep:trillium-websockets", 33 | ] 34 | runtime-tokio = ["dep:tokio", "dep:futures"] 35 | runtime-smol = [ 36 | "dep:async-channel", 37 | "dep:async-global-executor", 38 | "dep:async-io", 39 | "dep:futures-lite", 40 | ] 41 | 42 | # Base Dependencies ----------------------------------------------------------- 43 | 44 | [dependencies] 45 | cfg-if = "1" 46 | if-addrs = "0.12" 47 | notify = "6" 48 | parking_lot = "0.12" 49 | once_cell = { version = "1", features = ["parking_lot"] } 50 | serde_urlencoded = "0.7" 51 | tap = "1" 52 | walkdir = "2" 53 | litemap = "0.7.2" 54 | 55 | [dependencies.lightningcss] 56 | version = "1.0.0-alpha.55" 57 | default-features = false 58 | features = ["bundler", "grid"] 59 | 60 | [dependencies.minijinja] 61 | version = "2.0.0-alpha.0" 62 | default-features = false 63 | features = [ 64 | "unstable_machinery", 65 | "builtins", 66 | "debug", 67 | "deserialization", 68 | "macros", 69 | ] 70 | 71 | # framework: axum ------------------------------------------------------------- 72 | 73 | [dependencies.axum] 74 | version = "0.7" 75 | optional = true 76 | default-features = false 77 | features = ["ws", "form", "matched-path"] 78 | 79 | [dependencies.tower-http] 80 | version = "0.5" 81 | optional = true 82 | default-features = false 83 | features = ["trace"] 84 | 85 | # framework: trillium --------------------------------------------------------- 86 | 87 | [dependencies.trillium] 88 | version = "0.2" 89 | optional = true 90 | 91 | [dependencies.trillium-router] 92 | version = "0.4" 93 | optional = true 94 | 95 | [dependencies.trillium-websockets] 96 | version = "0.6" 97 | optional = true 98 | 99 | # runtime: tokio -------------------------------------------------------------- 100 | 101 | [dependencies.tokio] 102 | version = "1" 103 | optional = true 104 | default-features = false 105 | 106 | [dependencies.futures] 107 | version = "0.3" 108 | optional = true 109 | 110 | # runtime: smol --------------------------------------------------------------- 111 | 112 | [dependencies.async-channel] 113 | version = "2" 114 | optional = true 115 | 116 | [dependencies.async-global-executor] 117 | version = "2" 118 | optional = true 119 | 120 | [dependencies.async-io] 121 | version = "2" 122 | optional = true 123 | 124 | [dependencies.futures-lite] 125 | version = "2" 126 | optional = true 127 | -------------------------------------------------------------------------------- /benches/templates/plain.html.jinja2: -------------------------------------------------------------------------------- 1 |
2 |

3 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce nec lacus in dui interdum interdum et 4 | vitae 5 | lorem. Curabitur eu quam faucibus, tristique ipsum quis, pellentesque mauris. Aenean id urna eget quam 6 | porttitor 7 | tincidunt. Aliquam at leo eu velit sagittis condimentum. Mauris lacus nibh, varius eu purus id, 8 | tincidunt 9 | viverra nisl. Nunc non enim nec ligula gravida efficitur. Proin vitae porta sem, eget finibus neque. 10 | Aliquam 11 | consectetur massa leo, ac vehicula metus lacinia eu. Donec sollicitudin dui leo. Mauris ut nisl nec 12 | lectus 13 | placerat eleifend. Quisque metus magna, vestibulum eget sapien at, pretium laoreet nibh. Duis rhoncus, 14 | dolor ut 15 | sodales lacinia, arcu dui auctor enim, vitae fermentum magna nulla ac nisi. Donec lobortis ante vel 16 | massa congue 17 | pharetra. Vestibulum vestibulum luctus lectus et ultricies. Etiam finibus accumsan faucibus. Duis 18 | sollicitudin 19 | sapien vel lectus pharetra, sit amet volutpat arcu malesuada. 20 |

21 |

22 | Phasellus augue elit, fermentum in metus eget, aliquet ultricies leo. Suspendisse tincidunt porta dui ut 23 | ultrices. Ut tortor urna, semper et elementum vel, pellentesque a nibh. In imperdiet consequat elit, 24 | eget mollis 25 | quam lacinia ac. Pellentesque vulputate cursus facilisis. Vestibulum pretium turpis eu massa mattis 26 | tempor. 27 | Vestibulum mollis euismod risus. Nunc rhoncus sapien a nisl tincidunt laoreet. Ut placerat consectetur 28 | bibendum. 29 | Nullam porttitor velit erat, id vehicula nisi aliquam at. Vivamus nec congue lectus. 30 |

31 |

32 | Sed suscipit, dui eu aliquet dignissim, sapien dui fringilla quam, id suscipit diam velit vitae ligula. 33 | Mauris 34 | bibendum cursus consequat. Quisque ac turpis elit. Nulla lacinia vulputate elit at eleifend. Aenean 35 | risus 36 | mauris, accumsan at bibendum non, semper nec erat. Fusce hendrerit condimentum felis, vel pretium dolor. 37 | Nullam 38 | fermentum tempor ipsum quis eleifend. 39 |

40 |

41 | Integer tempus lacus tortor, at tempor dui finibus vitae. Nunc tincidunt elit a velit aliquet, vitae 42 | scelerisque 43 | leo venenatis. Curabitur nunc diam, eleifend pretium massa nec, vehicula blandit nibh. Curabitur 44 | elementum 45 | fringilla erat, vitae mollis est blandit et. Nunc aliquet ligula ex, ut fermentum nulla volutpat in. Nam 46 | faucibus fermentum vestibulum. Curabitur vitae augue tortor. Maecenas egestas sapien at lacus tincidunt, 47 | in 48 | finibus felis egestas. Sed egestas posuere venenatis. Nullam in nisl at risus aliquam condimentum. Morbi 49 | tincidunt nulla id felis volutpat feugiat. 50 |

51 |

52 | Praesent feugiat ligula eros, eu vehicula quam ultricies non. Donec vulputate lobortis mi, eget faucibus 53 | est 54 | fermentum a. Vestibulum eu hendrerit quam, condimentum aliquam dolor. Phasellus sodales, augue at 55 | imperdiet 56 | porttitor, tellus mi lacinia velit, sed semper nisi diam id nisi. Suspendisse vel euismod ipsum. Etiam 57 | velit 58 | dolor, viverra nec ullamcorper quis, molestie in massa. Ut eget quam non nibh blandit posuere nec sit 59 | amet leo. 60 | Donec sem odio, mollis ac ex id, tempus venenatis lorem. 61 |

62 |
-------------------------------------------------------------------------------- /src/template.rs: -------------------------------------------------------------------------------- 1 | use minijinja::value::Value; 2 | use once_cell::sync::OnceCell; 3 | 4 | use std::collections::BTreeMap; 5 | 6 | use crate::context; 7 | use crate::framework::*; 8 | 9 | pub(crate) static TEMPLATE_EXTENSION: OnceCell = OnceCell::new(); 10 | 11 | pub(crate) fn template_extension() -> &'static str { 12 | match TEMPLATE_EXTENSION.get() { 13 | Some(s) => s, 14 | None => ".html.jinja2", 15 | } 16 | } 17 | 18 | #[derive(Debug, Clone)] 19 | pub struct Template { 20 | pub path: String, 21 | pub form: BTreeMap, 22 | } 23 | 24 | impl Template { 25 | pub fn render(self, context: Value) -> RenderedTemplate { 26 | if context.is_undefined() { 27 | if self.form.is_empty() { 28 | crate::render::render(self.path, context) 29 | } else { 30 | crate::render::render(self.path, context!(form => self.form)) 31 | } 32 | } else { 33 | let mut context = context 34 | .try_iter() 35 | .unwrap() 36 | .fold(BTreeMap::new(), |mut h, k| { 37 | h.insert( 38 | k.as_str().unwrap().to_string(), 39 | context.get_item(&k).unwrap(), 40 | ); 41 | h 42 | }); 43 | 44 | if !context.contains_key("form") { 45 | context.insert("form".into(), Value::from_object(self.form)); 46 | } 47 | 48 | crate::render::render(self.path, context.into()) 49 | } 50 | } 51 | } 52 | 53 | #[cfg(debug_assertions)] 54 | pub(crate) fn template_hydrate( 55 | ip: std::net::IpAddr, 56 | this_endpoint: String, 57 | form_from_request: BTreeMap, 58 | ) -> Template { 59 | let mut forms = crate::TEMPLATES.forms.lock(); 60 | // 1: If this IP hasn't recorded any forms *at all*, create an empty history table. 61 | if forms.contains_key(&ip) { 62 | forms.insert(ip, Default::default()); 63 | } 64 | 65 | let mut ip_endpoint_history = forms.get(&ip).unwrap().lock(); 66 | 67 | // 2: If this IP has not recorded a form for *this endpoint*, create an empty history for this endpoint. 68 | if !ip_endpoint_history.contains_key(&this_endpoint) { 69 | ip_endpoint_history.insert(this_endpoint.to_string(), Default::default()); 70 | } 71 | 72 | let form_history = ip_endpoint_history.get_mut(&this_endpoint).unwrap(); 73 | 74 | // 3: The clientside HMR will assign an index for each element created. 75 | // when we request a reload, the client will give us the indexes for each element 76 | // that's still loaded. We can get something like [1, 3, 4] (elements 0 and 2 have been deleted), 77 | // and since the client updates each element in order, we can pop off the front of the indexes. 78 | match form_history.indexes.pop_front() { 79 | Some(oldest_outdated_element_id) => { 80 | // 4: If there's an existing index, that means we're re-rendering an existing element with HMR magic. 81 | // Hypermedia relies on form data, so we'll reuse the existing form data so we don't have to re-submit it. 82 | Template { 83 | path: this_endpoint, 84 | form: form_history.contents[oldest_outdated_element_id as usize] 85 | .clone() 86 | .into_iter() 87 | .collect(), 88 | } 89 | } 90 | 91 | None => { 92 | // 5: If there's nothing else in the queue, then we're rendering a new element! 93 | // We'll save the requested form data instead and return the requested form. 94 | form_history.contents.push(form_from_request.clone()); 95 | 96 | Template { 97 | path: this_endpoint, 98 | form: form_from_request.into_iter().collect(), 99 | } 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /examples/basic/templates/index.html.jinja2: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {{title}} 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | {{ module("navbar") }} 17 |
18 |
19 | 22 | 23 |
24 |
25 | 28 | 29 |
30 | {{ module("hello", {"name": "world"}) }} 31 |
32 |

33 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce nec lacus in dui interdum interdum et 34 | vitae 35 | lorem. Curabitur eu quam faucibus, tristique ipsum quis, pellentesque mauris. Aenean id urna eget quam 36 | porttitor 37 | tincidunt. Aliquam at leo eu velit sagittis condimentum. Mauris lacus nibh, varius eu purus id, 38 | tincidunt 39 | viverra nisl. Nunc non enim nec ligula gravida efficitur. Proin vitae porta sem, eget finibus neque. 40 | Aliquam 41 | consectetur massa leo, ac vehicula metus lacinia eu. Donec sollicitudin dui leo. Mauris ut nisl nec 42 | lectus 43 | placerat eleifend. Quisque metus magna, vestibulum eget sapien at, pretium laoreet nibh. Duis rhoncus, 44 | dolor ut 45 | sodales lacinia, arcu dui auctor enim, vitae fermentum magna nulla ac nisi. Donec lobortis ante vel 46 | massa congue 47 | pharetra. Vestibulum vestibulum luctus lectus et ultricies. Etiam finibus accumsan faucibus. Duis 48 | sollicitudin 49 | sapien vel lectus pharetra, sit amet volutpat arcu malesuada. 50 |

51 |

52 | Phasellus augue elit, fermentum in metus eget, aliquet ultricies leo. Suspendisse tincidunt porta dui ut 53 | ultrices. Ut tortor urna, semper et elementum vel, pellentesque a nibh. In imperdiet consequat elit, 54 | eget mollis 55 | quam lacinia ac. Pellentesque vulputate cursus facilisis. Vestibulum pretium turpis eu massa mattis 56 | tempor. 57 | Vestibulum mollis euismod risus. Nunc rhoncus sapien a nisl tincidunt laoreet. Ut placerat consectetur 58 | bibendum. 59 | Nullam porttitor velit erat, id vehicula nisi aliquam at. Vivamus nec congue lectus. 60 |

61 |

62 | Sed suscipit, dui eu aliquet dignissim, sapien dui fringilla quam, id suscipit diam velit vitae ligula. 63 | Mauris 64 | bibendum cursus consequat. Quisque ac turpis elit. Nulla lacinia vulputate elit at eleifend. Aenean 65 | risus 66 | mauris, accumsan at bibendum non, semper nec erat. Fusce hendrerit condimentum felis, vel pretium dolor. 67 | Nullam 68 | fermentum tempor ipsum quis eleifend. 69 |

70 |

71 | Integer tempus lacus tortor, at tempor dui finibus vitae. Nunc tincidunt elit a velit aliquet, vitae 72 | scelerisque 73 | leo venenatis. Curabitur nunc diam, eleifend pretium massa nec, vehicula blandit nibh. Curabitur 74 | elementum 75 | fringilla erat, vitae mollis est blandit et. Nunc aliquet ligula ex, ut fermentum nulla volutpat in. Nam 76 | faucibus fermentum vestibulum. Curabitur vitae augue tortor. Maecenas egestas sapien at lacus tincidunt, 77 | in 78 | finibus felis egestas. Sed egestas posuere venenatis. Nullam in nisl at risus aliquam condimentum. Morbi 79 | tincidunt nulla id felis volutpat feugiat. 80 |

81 |

82 | Praesent feugiat ligula eros, eu vehicula quam ultricies non. Donec vulputate lobortis mi, eget faucibus 83 | est 84 | fermentum a. Vestibulum eu hendrerit quam, condimentum aliquam dolor. Phasellus sodales, augue at 85 | imperdiet 86 | porttitor, tellus mi lacinia velit, sed semper nisi diam id nisi. Suspendisse vel euismod ipsum. Etiam 87 | velit 88 | dolor, viverra nec ullamcorper quis, molestie in massa. Ut eget quam non nibh blandit posuere nec sit 89 | amet leo. 90 | Donec sem odio, mollis ac ex id, tempus venenatis lorem. 91 |

92 |
93 |
94 | 95 | 96 | -------------------------------------------------------------------------------- /src/framework/framework_trillium.rs: -------------------------------------------------------------------------------- 1 | use crate::template::Template; 2 | use std::collections::BTreeMap; 3 | use std::path::Path; 4 | 5 | #[cfg(debug_assertions)] 6 | pub use trillium_websockets::WebSocketConn as WebSocket; 7 | 8 | #[cfg(debug_assertions)] 9 | pub async fn hmr_websocket(conn: WebSocket) { 10 | let ip = conn.peer_ip().unwrap(); 11 | crate::hmr::hmr_handler(conn, ip).await; 12 | } 13 | 14 | #[cfg(debug_assertions)] 15 | pub async fn websocket_recv( 16 | socket: &mut WebSocket, 17 | ) -> Option> { 18 | use futures_lite::StreamExt; 19 | 20 | socket 21 | .next() 22 | .await 23 | .map(|o| o.map_err(trillium_websockets::Error::from)) 24 | } 25 | 26 | #[cfg(debug_assertions)] 27 | pub async fn websocket_unwrap(socket: async_channel::Send<'_, T>) { 28 | socket.await.unwrap(); 29 | } 30 | 31 | #[cfg(debug_assertions)] 32 | pub fn websocket_message_text(text: String) -> trillium_websockets::tungstenite::Message { 33 | trillium_websockets::tungstenite::Message::Text(text) 34 | } 35 | 36 | #[cfg(debug_assertions)] 37 | pub fn websocket_message_binary(data: Vec) -> trillium_websockets::tungstenite::Message { 38 | trillium_websockets::tungstenite::Message::Binary(data) 39 | } 40 | 41 | #[cfg(debug_assertions)] 42 | pub fn websocket_try_as_text(message: trillium_websockets::tungstenite::Message) -> Option { 43 | match message { 44 | trillium_websockets::tungstenite::Message::Text(t) => Some(t), 45 | _ => None, 46 | } 47 | } 48 | 49 | #[cfg(debug_assertions)] 50 | pub fn websocket_try_as_binary( 51 | message: trillium_websockets::tungstenite::Message, 52 | ) -> Option> { 53 | match message { 54 | trillium_websockets::tungstenite::Message::Binary(b) => Some(b), 55 | _ => None, 56 | } 57 | } 58 | 59 | pub trait RouterExt { 60 | fn with_hmr(self) -> Self; 61 | fn with_bundled_css>(self, endpoint: &str, main_css_path: P) -> Self; 62 | } 63 | 64 | impl RouterExt for trillium_router::Router { 65 | #[cfg(debug_assertions)] 66 | fn with_hmr(self) -> Self { 67 | crate::hmr::watch_templates(); 68 | self.get("/hmr", trillium_websockets::websocket(hmr_websocket)) 69 | } 70 | 71 | #[cfg(not(debug_assertions))] 72 | fn with_hmr(self) -> Self { 73 | self 74 | } 75 | 76 | #[cfg(debug_assertions)] 77 | fn with_bundled_css>(self, endpoint: &str, main_css_path: P) -> Self { 78 | crate::style::STYLE_MAIN_FILE 79 | .set(main_css_path.as_ref().to_path_buf()) 80 | .unwrap(); 81 | 82 | crate::hmr::watch_style(); 83 | 84 | self.get(endpoint, main_css) 85 | } 86 | 87 | #[cfg(not(debug_assertions))] 88 | fn with_bundled_css>(self, endpoint: &str, main_css_path: P) -> Self { 89 | crate::style::MAIN_CSS 90 | .set(crate::style::transform_css(&main_css_path.as_ref().to_path_buf()).unwrap()) 91 | .unwrap(); 92 | 93 | self.get(endpoint, main_css) 94 | } 95 | } 96 | 97 | #[cfg(debug_assertions)] 98 | async fn main_css(conn: trillium::Conn) -> trillium::Conn { 99 | conn.with_response_header("Content-Type", "text/css") 100 | .with_body( 101 | crate::style::transform_css(crate::style::STYLE_MAIN_FILE.get().unwrap()).unwrap(), 102 | ) 103 | } 104 | 105 | #[cfg(not(debug_assertions))] 106 | async fn main_css(conn: trillium::Conn) -> trillium::Conn { 107 | conn.with_response_header("Content-Type", "text/css") 108 | .with_body(crate::style::MAIN_CSS.get().unwrap().as_str()) 109 | } 110 | 111 | #[trillium::async_trait] 112 | pub trait ConnExt { 113 | async fn template(&mut self) -> Template; 114 | } 115 | 116 | #[trillium::async_trait] 117 | impl ConnExt for trillium::Conn { 118 | #[cfg(not(debug_assertions))] 119 | async fn template(&mut self) -> Template { 120 | let path = self.path().to_owned(); 121 | let form: BTreeMap = 122 | serde_urlencoded::from_str::>(self.querystring()) 123 | .unwrap_or_default(); 124 | 125 | Template { path, form } 126 | } 127 | 128 | #[cfg(debug_assertions)] 129 | async fn template(&mut self) -> Template { 130 | let path = self.path().to_owned(); 131 | let ip = self.peer_ip().unwrap(); 132 | 133 | let form: BTreeMap = 134 | serde_urlencoded::from_str::>(self.querystring()) 135 | .unwrap_or_default(); 136 | 137 | crate::template::template_hydrate(ip, path, form) 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /examples/crud/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::borrow::Cow; 2 | use std::collections::HashMap; 3 | use std::fs::File; 4 | 5 | use axum::http::StatusCode; 6 | use axum::response::Html; 7 | use axum::routing::{delete, get, post}; 8 | use axum::{Extension, Form, Router, Server}; 9 | use chrono::NaiveDateTime; 10 | use eyre::{ContextCompat, Result}; 11 | use hyro::prelude::*; 12 | use hyro::{context, Template}; 13 | use serde::{Deserialize, Serialize}; 14 | use sqlx::{FromRow, SqlitePool}; 15 | use tower_http::services::ServeDir; 16 | 17 | type Hypermedia = Html>; 18 | type Error = (StatusCode, String); 19 | type MaybeHypermedia = std::result::Result; 20 | 21 | #[derive(Serialize, Deserialize, FromRow, Debug)] 22 | struct Todo { 23 | id: i32, 24 | description: String, 25 | done: bool, 26 | created: NaiveDateTime, 27 | updated: NaiveDateTime, 28 | } 29 | 30 | #[tokio::main] 31 | async fn main() -> Result<()> { 32 | hyro::config::set_template_file_extension("html.j2").unwrap(); 33 | 34 | let db_path = std::env::temp_dir().join("hyro.db"); 35 | if !db_path.exists() { 36 | File::create(&db_path)?; 37 | } 38 | 39 | let pool = SqlitePool::connect(db_path.to_str().unwrap()).await?; 40 | 41 | sqlx::migrate!("./migrations").run(&pool).await?; 42 | 43 | let router = Router::new() 44 | .route("/", get(index)) 45 | .route("/todo", get(todo)) 46 | .route("/todo", post(create_todo)) 47 | .route("/todo", delete(delete_todo)) 48 | .route("/todo-done", get(todo_done)) 49 | .route("/todo-edit", get(todo_edit)) 50 | .nest_service("/assets", ServeDir::new("assets")) 51 | .layer(Extension(pool)) 52 | .into_service_with_hmr(); 53 | 54 | Server::from_tcp(hyro::bind("0.0.0.0:1380"))? 55 | .serve(router) 56 | .await?; 57 | 58 | Ok(()) 59 | } 60 | 61 | async fn index(Extension(pool): Extension, template: Template) -> MaybeHypermedia { 62 | let todos: Vec = sqlx::query_as("SELECT * FROM todos") 63 | .fetch_all(&pool) 64 | .await 65 | .map_err(internal_error)?; 66 | 67 | let num_done = todos 68 | .iter() 69 | .fold(0, |acc, todo| if todo.done { acc + 1 } else { acc }); 70 | 71 | Ok(template.render(context!(todos, num_done))) 72 | } 73 | 74 | async fn todo(template: Template) -> Hypermedia { 75 | template.render(context!()) 76 | } 77 | 78 | async fn todo_edit(template: Template) -> Hypermedia { 79 | template.render(context!()) 80 | } 81 | 82 | async fn todo_done( 83 | Extension(pool): Extension, 84 | Form(form): Form>, 85 | ) -> Result<(), Error> { 86 | sqlx::query("UPDATE todos SET done = $1 WHERE id = $2") 87 | .bind( 88 | form.get("done") 89 | .context("please provide done") 90 | .map_err(bad_request)? 91 | == "false", 92 | ) 93 | .bind( 94 | form.get("id") 95 | .context("please provide an id") 96 | .map_err(bad_request)?, 97 | ) 98 | .execute(&pool) 99 | .await 100 | .map_err(internal_error)?; 101 | 102 | Ok(()) 103 | } 104 | 105 | async fn create_todo( 106 | Extension(pool): Extension, 107 | template: Template, 108 | ) -> MaybeHypermedia { 109 | let id = if let (Some(description), Some(local_id)) = 110 | (template.form.get("description"), template.form.get("id")) 111 | { 112 | sqlx::query("UPDATE todos SET description = $1 WHERE id = $2") 113 | .bind(description) 114 | .bind(local_id) 115 | .execute(&pool) 116 | .await 117 | .map_err(internal_error)?; 118 | local_id.parse().map_err(internal_error)? 119 | } else { 120 | sqlx::query("INSERT INTO todos (description) VALUES ($1) RETURNING id") 121 | .bind(template.form.get("description").unwrap()) 122 | .execute(&pool) 123 | .await 124 | .map_err(internal_error)? 125 | .last_insert_rowid() 126 | }; 127 | 128 | let todo: Todo = sqlx::query_as("SELECT * FROM todos WHERE id = $1") 129 | .bind(id) 130 | .fetch_one(&pool) 131 | .await 132 | .map_err(internal_error)?; 133 | 134 | Ok(template.render(context!(form => todo))) 135 | } 136 | 137 | async fn delete_todo( 138 | Extension(pool): Extension, 139 | Form(form): Form>, 140 | ) -> Result<(), Error> { 141 | sqlx::query("DELETE FROM todos WHERE id = $1") 142 | .bind( 143 | form.get("id") 144 | .context("please provide an id") 145 | .map_err(bad_request)?, 146 | ) 147 | .execute(&pool) 148 | .await 149 | .map_err(internal_error)?; 150 | 151 | Ok(()) 152 | } 153 | 154 | fn bad_request(err: eyre::Error) -> (StatusCode, String) { 155 | (StatusCode::BAD_REQUEST, err.to_string()) 156 | } 157 | 158 | fn internal_error(err: E) -> (StatusCode, String) { 159 | (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()) 160 | } 161 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![forbid(unsafe_code)] 2 | 3 | #[macro_use] 4 | mod log; 5 | 6 | #[cfg(debug_assertions)] 7 | mod hmr; 8 | 9 | pub mod config; 10 | mod framework; 11 | mod render; 12 | mod runtime; 13 | pub mod style; 14 | mod template; 15 | pub use framework::prelude; 16 | 17 | #[cfg(debug_assertions)] 18 | use std::collections::VecDeque; 19 | 20 | #[cfg(debug_assertions)] 21 | use parking_lot::Mutex; 22 | #[cfg(debug_assertions)] 23 | use std::collections::BTreeMap; 24 | use std::net::IpAddr; 25 | use std::path::{Path, PathBuf}; 26 | 27 | pub use minijinja::context as _ctx; 28 | use once_cell::sync::{Lazy, OnceCell}; 29 | use std::net::TcpListener; 30 | pub use template::*; 31 | 32 | pub mod reexports { 33 | pub use lightningcss; 34 | pub use minijinja; 35 | } 36 | 37 | #[doc(hidden)] 38 | pub fn _empty_context() -> minijinja::value::Value { 39 | minijinja::value::Value::UNDEFINED 40 | } 41 | 42 | #[macro_export] 43 | macro_rules! context { 44 | () => { 45 | $crate::_empty_context() 46 | }; 47 | 48 | ($($key:ident $(=> $value:expr)?),* $(,)?) => { 49 | $crate::_ctx!($($key $(=> $value)?),*) 50 | }; 51 | } 52 | 53 | static TEMPLATE_DIR: OnceCell = OnceCell::new(); 54 | 55 | pub(crate) fn template_dir() -> PathBuf { 56 | TEMPLATE_DIR 57 | .get() 58 | .cloned() 59 | .unwrap_or(PathBuf::from("templates")) 60 | } 61 | 62 | pub fn bind(addr: &'static str) -> TcpListener { 63 | let listener = 64 | TcpListener::bind(addr).unwrap_or_else(|_| panic!("Failed to bind to address: {addr}")); 65 | 66 | let port = match listener.local_addr() { 67 | Ok(addr) => addr.port(), 68 | Err(e) => { 69 | error!("Network error while retrieving port: \"{e}\". Defaulting to port 80"); 70 | 80 71 | } 72 | }; 73 | 74 | if let Ok(addrs) = if_addrs::get_if_addrs() { 75 | info!("Listening on:"); 76 | addrs 77 | .into_iter() 78 | .filter(|i| !i.name.starts_with("br-") && !i.name.starts_with("docker")) 79 | .map(|i| i.ip()) 80 | .filter(IpAddr::is_ipv4) 81 | .for_each(|i| { 82 | data!("http://{}:{}", i, port); 83 | }) 84 | } 85 | 86 | listener 87 | } 88 | 89 | #[cfg(debug_assertions)] 90 | type DB = Mutex>>; 91 | 92 | #[cfg(debug_assertions)] 93 | #[derive(Debug, Default, Clone)] 94 | pub(crate) struct TemplateFormData { 95 | pub contents: Vec>, 96 | pub indexes: VecDeque, 97 | } 98 | 99 | #[cfg(debug_assertions)] 100 | #[derive(Debug, Default)] 101 | pub(crate) struct Templates { 102 | pub sources: DB, 103 | pub forms: DB>, 104 | } 105 | 106 | #[cfg(debug_assertions)] 107 | pub(crate) static TEMPLATES: Lazy = Lazy::new(Templates::default); 108 | 109 | #[cfg(not(debug_assertions))] 110 | pub(crate) struct TemplateSourceData { 111 | pub source: String, 112 | pub can_skip_rendering: bool, 113 | } 114 | 115 | #[cfg(not(debug_assertions))] 116 | pub(crate) static TEMPLATES: Lazy> = Lazy::new(|| { 117 | walkdir::WalkDir::new(template_dir()) 118 | .into_iter() 119 | .filter_map(Result::ok) 120 | .filter(|i| i.path().is_file()) 121 | .fold(litemap::LiteMap::new(), |mut acc, entry| { 122 | let dir = entry.path().to_string_lossy().to_string(); 123 | let t = std::fs::read_to_string(dir).unwrap(); 124 | acc.insert( 125 | format!( 126 | "/{}", 127 | entry 128 | .path() 129 | .strip_prefix(template_dir()) 130 | .unwrap() 131 | .to_string_lossy() 132 | .to_string() 133 | .trim_end_matches(template_extension()) 134 | .replace("index", "") 135 | ), 136 | TemplateSourceData { 137 | source: t.clone(), 138 | can_skip_rendering: !(t.contains("{{") 139 | || t.contains("}}") 140 | || t.contains("{%") 141 | || t.contains("%}")), 142 | }, 143 | ); 144 | acc 145 | }) 146 | }); 147 | 148 | #[cfg(debug_assertions)] 149 | pub(crate) fn endpointof(path: &str) -> Option<&str> { 150 | let without_extension = path.trim_end_matches(template_extension()); 151 | if without_extension == "/index" { 152 | Some("/") 153 | } else if without_extension == "index" { 154 | Some("") 155 | } else { 156 | Some(without_extension) 157 | } 158 | } 159 | 160 | pub(crate) fn path_of_endpoint>(endpoint: S) -> String { 161 | let endpoint = endpoint.as_ref(); 162 | format!( 163 | "{}{}", 164 | if endpoint.ends_with('/') { 165 | format!("{endpoint}index") 166 | } else { 167 | endpoint.into() 168 | } 169 | .trim_start_matches('/'), 170 | if Path::new(endpoint).extension().is_none() { 171 | template_extension() 172 | } else { 173 | "" 174 | } 175 | ) 176 | } 177 | -------------------------------------------------------------------------------- /src/render.rs: -------------------------------------------------------------------------------- 1 | use minijinja::value::{Value, ValueKind}; 2 | use parking_lot::Mutex; 3 | use std::borrow::Cow; 4 | 5 | use minijinja::Environment; 6 | use once_cell::sync::Lazy; 7 | use tap::Tap; 8 | 9 | use crate::framework::*; 10 | use crate::{path_of_endpoint, template_extension, TEMPLATES}; 11 | 12 | const HMR_ENABLED: bool = cfg!(debug_assertions); 13 | 14 | pub(crate) static ENVIRONMENT: Lazy> = Lazy::new(|| { 15 | Mutex::new(Environment::new().tap_mut(|env| { 16 | env.add_global("hmr", HMR_ENABLED); 17 | env.add_function("module", module); 18 | })) 19 | }); 20 | 21 | fn module(path: String, form: Option) -> Result { 22 | let path = path_of_endpoint(path); 23 | let path = path.trim_end_matches(template_extension()); 24 | 25 | match (form.as_ref().map(Value::kind), form) { 26 | (Some(ValueKind::Map), Some(form)) => match serde_urlencoded::to_string(form) { 27 | Ok(form) => Ok(format!( 28 | r#"
"#, 29 | )), 30 | Err(e) => Err(minijinja::Error::new( 31 | minijinja::ErrorKind::BadSerialization, 32 | format!("invalid form data: {e}"), 33 | )), 34 | }, 35 | (Some(_), _) => Err(minijinja::Error::new( 36 | minijinja::ErrorKind::BadSerialization, 37 | "form data should be a map", 38 | )), 39 | (None, _) => Ok(format!( 40 | r#"
"# 41 | )), 42 | } 43 | } 44 | 45 | #[cfg(debug_assertions)] 46 | fn inject_template_path(path: &str, template: &str) -> String { 47 | let loc = if let Some(stripped) = template.strip_prefix("") { 48 | stripped.find('>').map(|i| i + 15) 49 | } else { 50 | template.find('>') 51 | }; 52 | 53 | if let Some(insert_pos) = loc { 54 | format!( 55 | "{} hmr-path=\"{}\"{}", 56 | &template[..insert_pos], 57 | path, 58 | &template[insert_pos..] 59 | ) 60 | } else { 61 | template.to_string() 62 | } 63 | } 64 | 65 | #[cfg(debug_assertions)] 66 | fn inject_hmr(template: &str) -> String { 67 | if let Some(head_end_pos) = template.find("") { 68 | format!( 69 | "{}\n\t\n{}", 70 | &template[..head_end_pos], 71 | include_str!("hmr.js"), 72 | &template[head_end_pos..] 73 | ) 74 | } else { 75 | template.to_string() 76 | } 77 | } 78 | 79 | #[cfg(not(debug_assertions))] 80 | pub(crate) fn render + std::fmt::Debug>( 81 | template_name: S, 82 | value: minijinja::value::Value, 83 | ) -> RenderedTemplate { 84 | let template = TEMPLATES.get(template_name.as_ref()).unwrap(); 85 | 86 | if template.can_skip_rendering { 87 | return into_rendered_template(Cow::Borrowed(template.source.as_str())); 88 | } else { 89 | match ENVIRONMENT.lock().render_str(&template.source, value) { 90 | Ok(t) => return into_rendered_template(Cow::Owned(t)), 91 | Err(e) => { 92 | error!("Error while rendering {}: {:?}", template_name.as_ref(), e); 93 | return into_rendered_template(Cow::Borrowed("")); 94 | } 95 | } 96 | } 97 | } 98 | 99 | #[cfg(debug_assertions)] 100 | pub(crate) fn render + std::fmt::Debug>( 101 | template: S, 102 | value: minijinja::value::Value, 103 | ) -> RenderedTemplate { 104 | init_template(template.as_ref()); 105 | 106 | let template_sources = TEMPLATES.sources.lock(); 107 | let template_source = template_sources.get(template.as_ref()).unwrap().lock(); 108 | 109 | let maybe_rendered = ENVIRONMENT.lock().render_str( 110 | &inject_hmr(&inject_template_path(template.as_ref(), &template_source)), 111 | value, 112 | ); 113 | 114 | match maybe_rendered { 115 | Ok(t) => into_rendered_template(Cow::Owned(t)), 116 | Err(e) => { 117 | error!("Error while rendering {}: {}", template.as_ref(), e); 118 | into_rendered_template(Cow::Borrowed("")) 119 | } 120 | } 121 | } 122 | 123 | #[cfg(debug_assertions)] 124 | fn init_template(template_name: &str) { 125 | let template_exists = TEMPLATES.sources.lock().contains_key(template_name); 126 | if !template_exists { 127 | reload_template( 128 | &crate::template_dir() 129 | .join(std::path::Path::new(template_name.trim_start_matches('/'))) 130 | .display() 131 | .to_string(), 132 | ); 133 | } 134 | } 135 | 136 | #[cfg(debug_assertions)] 137 | pub(crate) fn reload_template(template_name: &str) { 138 | use minijinja::{machinery::WhitespaceConfig, syntax::SyntaxConfig}; 139 | 140 | let _path = &path_of_endpoint(template_name); 141 | let path = std::path::Path::new(_path); 142 | 143 | let template_source = std::fs::read_to_string(path).unwrap(); 144 | 145 | match minijinja::machinery::parse( 146 | &template_source, 147 | &std::env::current_dir() 148 | .unwrap() 149 | .join(path) 150 | .display() 151 | .to_string(), 152 | SyntaxConfig, 153 | WhitespaceConfig::default(), 154 | ) { 155 | Ok(_) => { 156 | TEMPLATES.sources.lock().insert( 157 | crate::endpointof(_path.trim_start_matches("templates")) 158 | .unwrap() 159 | .into(), 160 | Mutex::new(template_source), 161 | ); 162 | } 163 | Err(e) => { 164 | error!("{e}"); 165 | } 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /src/framework/framework_axum.rs: -------------------------------------------------------------------------------- 1 | use std::borrow::Cow; 2 | use std::collections::BTreeMap; 3 | use std::net::SocketAddr; 4 | use std::path::Path; 5 | 6 | #[cfg(debug_assertions)] 7 | pub use axum::extract::ws::WebSocket; 8 | use axum::extract::FromRequest; 9 | use axum::response::{Html, IntoResponse}; 10 | use axum::{async_trait, Router}; 11 | 12 | pub type RenderedTemplate = Html>; 13 | 14 | pub fn into_rendered_template(cow: Cow<'static, str>) -> RenderedTemplate { 15 | Html(cow) 16 | } 17 | 18 | #[cfg(debug_assertions)] 19 | pub async fn hmr_websocket( 20 | axum::extract::ConnectInfo(ip): axum::extract::ConnectInfo, 21 | ws: axum::extract::WebSocketUpgrade, 22 | ) -> axum::response::Response { 23 | let ip = ip.ip(); 24 | ws.on_upgrade(move |socket| async move { crate::hmr::hmr_handler(socket, ip).await }) 25 | } 26 | 27 | #[cfg(debug_assertions)] 28 | pub async fn websocket_recv( 29 | socket: &mut WebSocket, 30 | ) -> Option> { 31 | socket.recv().await 32 | } 33 | 34 | #[cfg(debug_assertions)] 35 | pub async fn websocket_unwrap( 36 | socket: Result>, 37 | ) { 38 | socket.unwrap(); 39 | } 40 | 41 | #[cfg(debug_assertions)] 42 | pub fn websocket_message_text(text: String) -> axum::extract::ws::Message { 43 | axum::extract::ws::Message::Text(text) 44 | } 45 | 46 | #[cfg(debug_assertions)] 47 | pub fn websocket_message_binary(data: Vec) -> axum::extract::ws::Message { 48 | axum::extract::ws::Message::Binary(data) 49 | } 50 | 51 | #[cfg(debug_assertions)] 52 | pub fn websocket_try_as_text(message: axum::extract::ws::Message) -> Option { 53 | match message { 54 | axum::extract::ws::Message::Text(t) => Some(t), 55 | _ => None, 56 | } 57 | } 58 | 59 | #[cfg(debug_assertions)] 60 | pub fn websocket_try_as_binary(message: axum::extract::ws::Message) -> Option> { 61 | match message { 62 | axum::extract::ws::Message::Binary(b) => Some(b), 63 | _ => None, 64 | } 65 | } 66 | 67 | pub trait RouterExt { 68 | /// Transforms the router, giving it permissions necessary for HMR during debug builds. 69 | /// Does nothing when building for release. 70 | #[cfg(debug_assertions)] 71 | fn into_service_with_hmr( 72 | self, 73 | ) -> axum::extract::connect_info::IntoMakeServiceWithConnectInfo; 74 | #[cfg(not(debug_assertions))] 75 | fn into_service_with_hmr(self) -> axum::routing::IntoMakeService; 76 | fn with_bundled_css>(self, endpoint: &str, main_css_path: P) -> Self; 77 | } 78 | 79 | impl RouterExt for axum::Router { 80 | #[cfg(debug_assertions)] 81 | fn into_service_with_hmr( 82 | self, 83 | ) -> axum::extract::connect_info::IntoMakeServiceWithConnectInfo { 84 | crate::hmr::watch_templates(); 85 | self.route("/hmr", axum::routing::get(hmr_websocket)) 86 | .layer(tower_http::trace::TraceLayer::new_for_http()) 87 | .into_make_service_with_connect_info::() 88 | } 89 | #[cfg(not(debug_assertions))] 90 | fn into_service_with_hmr(self) -> axum::routing::IntoMakeService { 91 | self.into_make_service() 92 | } 93 | 94 | #[cfg(debug_assertions)] 95 | fn with_bundled_css>(self, endpoint: &str, main_css_path: P) -> Self { 96 | crate::style::STYLE_MAIN_FILE 97 | .set(main_css_path.as_ref().to_path_buf()) 98 | .unwrap(); 99 | 100 | crate::hmr::watch_style(); 101 | 102 | self.route(endpoint, axum::routing::get(main_css)) 103 | } 104 | 105 | #[cfg(not(debug_assertions))] 106 | fn with_bundled_css>(self, endpoint: &str, main_css_path: P) -> Self { 107 | crate::style::MAIN_CSS 108 | .set(crate::style::transform_css(&main_css_path.as_ref().to_path_buf()).unwrap()) 109 | .unwrap(); 110 | 111 | self.route(endpoint, axum::routing::get(main_css)) 112 | } 113 | } 114 | 115 | #[cfg(debug_assertions)] 116 | async fn main_css() -> impl IntoResponse { 117 | ( 118 | [("Content-Type", "text/css")], 119 | crate::style::transform_css(crate::style::STYLE_MAIN_FILE.get().unwrap()).unwrap(), 120 | ) 121 | } 122 | 123 | #[cfg(not(debug_assertions))] 124 | async fn main_css() -> impl IntoResponse { 125 | ( 126 | [("Content-Type", "text/css")], 127 | crate::style::MAIN_CSS.get().unwrap().as_str(), 128 | ) 129 | } 130 | 131 | #[async_trait] 132 | impl FromRequest for crate::template::Template 133 | where 134 | axum::Form>: FromRequest, 135 | S: Send + Sync + std::fmt::Debug, 136 | { 137 | type Rejection = (); 138 | 139 | #[cfg(not(debug_assertions))] 140 | async fn from_request(req: axum::extract::Request, state: &S) -> Result { 141 | use axum::RequestPartsExt; 142 | let (mut parts, body) = req.into_parts(); 143 | 144 | let endpoint = parts 145 | .extract::() 146 | .await 147 | .map(|path| path.as_str().to_owned()) 148 | .unwrap(); 149 | 150 | let req = axum::http::Request::from_parts(parts, body); 151 | 152 | match axum::Form::>::from_request(req, state).await { 153 | Ok(axum::Form(form)) => Ok(Self { 154 | path: endpoint, 155 | form, 156 | }), 157 | Err(_) => Err(()), 158 | } 159 | } 160 | 161 | #[cfg(debug_assertions)] 162 | async fn from_request(req: axum::extract::Request, state: &S) -> Result { 163 | use axum::RequestPartsExt; 164 | 165 | let (mut parts, body) = req.into_parts(); 166 | 167 | let this_endpoint = parts 168 | .extract::() 169 | .await 170 | .map(|path| path.as_str().to_owned()) 171 | .unwrap(); 172 | 173 | let ip = parts 174 | .extract::>() 175 | .await 176 | .unwrap() 177 | .ip(); 178 | 179 | let req = axum::http::Request::from_parts(parts, body); 180 | 181 | axum::Form::from_request(req, state) 182 | .await 183 | .map(|form| crate::template::template_hydrate(ip, this_endpoint, form.0)) 184 | .map_err(|_| ()) 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.5.0 2 | 3 | ### Performance improvements 4 | 5 | A few adjustments were made to make sure that "rendering" a plain HTML file can be done automatically and with 6 | virtually no overhead. Despite HYRO precomputing whether a template is plain or not during startup, we still need 7 | to look up that data, which was the main performance bottleneck. Fortunately, all I had to do was swap out the 8 | `HashMap` with a [`LiteMap`](https://github.com/unicode-org/icu4x/tree/main/utils/litemap), which performs much better 9 | with smaller maps, while performing similar to [`hashbrown::HashMap`](https://github.com/rust-lang/hashbrown) at a 10 | capacity of >50. It doesn't scale as well into the thousands of entries quite like a regular `HashMap`, but I assume 11 | people won't need thousands of pages. At least not yet. 12 | 13 | | Version | Rendering a Template | Rendering Plain HTML | 14 | | --------- | --------------------- | ---------------------- | 15 | | 0.1.0 | 2.570µs (389K /s) | 7.570µs (132K /s) | 16 | | 0.2.0 | 2.390µs (418K /s) | 0.039µs (25.6M /s) | 17 | | **0.5.0** | **2.298µs (429K /s)** | **0.025µs (39.4M /s)** | 18 | 19 | ## 0.4.0 20 | 21 | ### **BREAKING CHANGES** 22 | 23 | - Frameworks and runtimes need to be manually selected via. a feature. To keep using Tokio and Axum, use the 24 | `framework-axum` feature. 25 | - If previously using Axum, remove any imports of `RouterExt`. Required traits for each framework are included 26 | by using `use hyro::prelude::*`. 27 | - `hyro::bind` is no longer `async`. 28 | 29 | ### Modular frameworks and runtimes 30 | 31 | Axum and Tokio work very well together - creating a wicked combo of high performance thanks to Tokio's scheduler, 32 | and a fully-featured and practical API (that works well with HYRO) thanks to Axum. However, this combination 33 | has a large overhead, and won't work entirely on embedded platforms. It's sometimes just not what users want! 34 | HYRO's API has been reorganized to allow for modular implementation of frameworks and runtimes via. feature flags. 35 | 36 | - `framework-trillium` enables support for the [Trillium](https://github.com/trillium-rs/trillium) framework, a 37 | composable toolkit perfect for more lightweight web applications. All of HYRO's HMR and bundling features are 38 | supported, with HMR completing at around 5x the speed of Axum! 39 | - `runtime-smol` enables support for the [smol](https://github.com/smol-rs/smol) runtime, perfect for embedded 40 | applications. 41 | 42 | ## 0.3.2 43 | 44 | ### Minor Changes 45 | 46 | - Reduced dependencies 47 | - Added a new logo 48 | 49 | ## 0.3.1 50 | 51 | ### Minor Changes 52 | 53 | - Allowed overriding `form` when rendering a template 54 | 55 | ## 0.3.0 56 | 57 | ### **BREAKING CHANGES** 58 | 59 | - `RouterExt::with_bundled_css`: now only takes the endpoint and main.css path as parameters. 60 | see `config::set_style_options` and `config::set_style_targets` 61 | - `style::CARTERS_PARSER_OPTIONS` and `style::CARTERS_TARGET_OPTIONS` ⟶ (removed, now applied by default) 62 | - `set_template_dir` ⟶ `config::set_template_dir` 63 | 64 | ### Improving configurability 65 | 66 | When building a real-world app with HYRO myself, I relized that it wasn't very configurable. This release 67 | focuses on the `hyro::config` module, which provides simple APIs for... configuration! 68 | 69 | - The template environment can be configured with `config::modify_template_env`. Now you can add custom 70 | functions, filters, global variables, etc. to your templates. 71 | - Templates' file extensions can be configured with `config::set_template_file_extention`. Changing the 72 | extension won't change the behavior of the template rendering engine. Helpful if you like the shorter 73 | `.html.j2` that still works with intellisense. 74 | - Migrated existing configurables like template directory, style options, and style targets to the new API. 75 | 76 | ### HMR Fixes 77 | 78 | - Fixed HMR not triggering for the styles directory if it wasn't configured as a child of the templates directory. 79 | - Fixed HMR rarely dropping form data. Some browsers wouldn't upgrade the HMR's websocket until a message was 80 | recieved due to non-deterministic browser caching. Fixed by a migration to `parking_lot::Mutex`, maintaining 81 | a sustained lock during rendering, and restricting HMR's access to global form data. 82 | - Fixed HMR halting rendering when encountering a template parsing error. This is standard behavior during 83 | release builds since invalid templates is inexcusable, but was changed to skip rendering until the template 84 | is valid during HMR. Utilizes the optional `unstable_machinery` feature of jinja2 to efficiently test for valid templates. 85 | - Fixed HMR garbling forms for out-of-order elements when re-rendering. Previously assumed that all elements were 86 | rendered in ascending order. 87 | 88 | ### Minor changes 89 | 90 | - Added an optional second argument to the `module` template function that allows passing form data via. a map. 91 | - Added the `reexports` module, currently re-exporting minijinja and lightningcss 92 | - Colorized output from HMR messages, app errors, and the `bind` function. 93 | 94 | ## 0.2.1 95 | 96 | ### Minor changes 97 | 98 | - Fixed an issue where changes to an `index` template wouldn't perform a full-reload and would render 99 | to an incorrect and unused endpoint. 100 | 101 | ## 0.2.0 102 | 103 | ### Unreasonable speed improvement for plain templates 104 | 105 | When setting up benchmarks, I noticed that large templates without any logic (essentially plain HTML) 106 | took longer to render than a small template with only two inputs. Since, without HMR, templates aren't 107 | modified during runtime, "rendering" plain templates will share a `&'static str`. We don't make any 108 | calls to minijinja or clone data. The only API difference is that endpoints previously returning a 109 | `Html` should now return a `Html>`. 110 | 111 | | Version | Benchmark | Average Speed | 112 | | --------- | ---------------- | -------------------- | 113 | | 0.1.0 | form_and_context | 2.57µs (389K /s) | 114 | | 0.1.0 | plain | 7.57µs (132K /s) | 115 | | **0.2.0** | form_and_context | **2.39µs (418K /s)** | 116 | | **0.2.0** | plain | **39ns (25.6M /s)** | 117 | 118 | ### Minor changes 119 | 120 | - Added `set_template_dir` for... setting the template directory. Defaults to `templates`. 121 | - Fixed an issue where `cargo check --release` would fail because of a missing generic at `src/template.rs:57`. 122 | 123 | ## 0.1.0 124 | 125 | Initial commit 126 | -------------------------------------------------------------------------------- /src/hmr.rs: -------------------------------------------------------------------------------- 1 | use std::collections::VecDeque; 2 | use std::net::IpAddr; 3 | use std::path::{Path, PathBuf}; 4 | use std::sync::atomic::{AtomicU8, Ordering}; 5 | 6 | #[cfg(feature = "runtime-smol")] 7 | use futures_lite::pin; 8 | 9 | use notify::{Config, Event, EventKind, RecommendedWatcher, RecursiveMode, Watcher}; 10 | use once_cell::sync::Lazy; 11 | 12 | use crate::framework::*; 13 | use crate::render::reload_template; 14 | use crate::runtime::*; 15 | use crate::style::STYLE_MAIN_FILE; 16 | use crate::{endpointof, template_dir, template_extension, TEMPLATES}; 17 | 18 | pub(crate) static PWD: Lazy = 19 | Lazy::new(|| std::env::current_dir().unwrap().join(template_dir())); 20 | 21 | static HMR_BROADCAST: Lazy<(BroadcastSender, BroadcastReceiver)> = 22 | Lazy::new(|| broadcast_channel(1)); 23 | 24 | static CONNECTIONS: AtomicU8 = AtomicU8::new(0); 25 | 26 | pub(crate) async fn hmr_handler(mut socket: WebSocket, ip: IpAddr) { 27 | let conn_id = CONNECTIONS.fetch_add(1, Ordering::SeqCst); 28 | 29 | // It took me. an hour. to find out this single line was breaking HMR. 30 | // this is its grave. 31 | //TEMPLATES.forms.lock().insert(ip, Default::default()); 32 | 33 | #[allow(unused_mut)] 34 | let mut rx = broadcast_subscribe(&HMR_BROADCAST); 35 | 36 | while let Ok(path) = rx.recv().await { 37 | let mut dur_start = instant_now(); 38 | if socket 39 | .send(websocket_message_text("you up?".into())) 40 | .await 41 | .is_err() 42 | { 43 | background!( 44 | "(HMR) {} CONN{} (browser status) connection closed", 45 | path, 46 | conn_id 47 | ); 48 | CONNECTIONS.fetch_sub(1, Ordering::SeqCst); 49 | return; 50 | } 51 | 52 | if path.ends_with(template_extension()) { 53 | let endpoint = format!("/{}", endpointof(&path).unwrap()); 54 | 55 | socket 56 | .send(websocket_message_text(endpoint.clone())) 57 | .await 58 | .unwrap_or_default(); 59 | 60 | let mut escape = false; 61 | if let Some(Ok(msg)) = websocket_recv(&mut socket).await { 62 | if let Some(t) = websocket_try_as_text(msg) { 63 | if t == "r" { 64 | escape = true; 65 | } 66 | } 67 | } 68 | 69 | background!( 70 | "(HMR) {} CONN{} (browser status) took {:?}", 71 | path, 72 | conn_id, 73 | dur_start.elapsed() 74 | ); 75 | 76 | if escape { 77 | background!( 78 | "(HMR) {} CONN{} (browser status) performing full reload", 79 | path, 80 | conn_id 81 | ); 82 | CONNECTIONS.fetch_sub(1, Ordering::SeqCst); 83 | socket.close().await.unwrap(); 84 | return; 85 | } 86 | 87 | dur_start = instant_now(); 88 | 89 | if let Some(Ok(msg)) = websocket_recv(&mut socket).await { 90 | if let Some(b) = websocket_try_as_binary(msg) { 91 | let forms = TEMPLATES.forms.lock(); 92 | let mut ip_endpoint_history = forms.get(&ip).unwrap().lock(); 93 | 94 | ip_endpoint_history.get_mut(&endpoint).unwrap().indexes = b 95 | .chunks(4) 96 | .map(<[u8; 4] as TryFrom<&[u8]>>::try_from) 97 | .map(Result::unwrap) 98 | .map(u32::from_le_bytes) 99 | .collect::>(); 100 | } 101 | } 102 | 103 | background!( 104 | "(HMR) {} CONN{} (server form sync) took {:?}", 105 | path, 106 | conn_id, 107 | dur_start.elapsed() 108 | ); 109 | } else { 110 | socket 111 | .send(websocket_message_binary(vec![0])) 112 | .await 113 | .unwrap_or_default(); 114 | } 115 | } 116 | 117 | background!("(HMR): Closed"); 118 | socket.close().await.unwrap(); 119 | } 120 | 121 | async fn async_watch + std::fmt::Debug>(watch_path: P) -> notify::Result<()> { 122 | #[cfg(feature = "runtime-tokio")] 123 | let (mut watcher, mut rx) = async_watcher()?; 124 | 125 | #[cfg(not(feature = "runtime-tokio"))] 126 | let (mut watcher, rx) = async_watcher()?; 127 | watcher.watch(watch_path.as_ref(), RecursiveMode::Recursive)?; 128 | 129 | let parent_path = watch_path.as_ref().parent().unwrap(); 130 | 131 | #[cfg(feature = "runtime-smol")] 132 | pin!(rx); 133 | 134 | while let Some(res) = rx.next().await { 135 | match res { 136 | Ok(Event { 137 | kind: EventKind::Access(_), 138 | paths, 139 | .. 140 | }) => { 141 | for path in paths { 142 | let dur_start = instant_now(); 143 | let relative_path = path.strip_prefix(parent_path).unwrap(); 144 | let path = path.strip_prefix(watch_path.as_ref()).unwrap(); 145 | 146 | reload_template(&relative_path.display().to_string()); 147 | 148 | background!( 149 | "\n(HMR) {} (template render) took {:?}", 150 | path.display(), 151 | dur_start.elapsed() 152 | ); 153 | 154 | websocket_unwrap(HMR_BROADCAST.0.send(path.display().to_string())).await; 155 | } 156 | } 157 | Err(e) => error!("(HMR): {e:?}"), 158 | _ => (), 159 | } 160 | } 161 | 162 | Ok(()) 163 | } 164 | 165 | pub(crate) fn watch_templates() { 166 | spawn(async { 167 | if let Err(e) = async_watch(&*PWD).await { 168 | error!("(HMR): {e}"); 169 | } 170 | }); 171 | } 172 | 173 | pub(crate) fn watch_style() { 174 | spawn(async { 175 | let style_file = std::env::current_dir() 176 | .unwrap() 177 | .join(STYLE_MAIN_FILE.get().unwrap()); 178 | 179 | let style_path = style_file.parent().unwrap(); 180 | 181 | if style_path.strip_prefix(&*PWD).is_err() { 182 | if let Err(e) = async_watch(style_path).await { 183 | error!("(HMR): {e}"); 184 | } 185 | } 186 | }); 187 | } 188 | 189 | fn async_watcher() -> notify::Result<(RecommendedWatcher, MpscReceiver>)> { 190 | #[allow(unused_mut)] 191 | let (mut tx, rx) = mpsc_channel(1); 192 | let watcher = RecommendedWatcher::new( 193 | move |res| { 194 | block_on(async { 195 | tx.send(res).await.unwrap(); 196 | }) 197 | }, 198 | Config::default(), 199 | )?; 200 | 201 | Ok((watcher, rx)) 202 | } 203 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.20.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler" 16 | version = "1.0.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 19 | 20 | [[package]] 21 | name = "ahash" 22 | version = "0.7.6" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" 25 | dependencies = [ 26 | "getrandom", 27 | "once_cell", 28 | "version_check", 29 | ] 30 | 31 | [[package]] 32 | name = "ahash" 33 | version = "0.8.11" 34 | source = "registry+https://github.com/rust-lang/crates.io-index" 35 | checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" 36 | dependencies = [ 37 | "cfg-if", 38 | "getrandom", 39 | "once_cell", 40 | "version_check", 41 | "zerocopy", 42 | ] 43 | 44 | [[package]] 45 | name = "aho-corasick" 46 | version = "1.0.4" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "6748e8def348ed4d14996fa801f4122cd763fff530258cdc03f64b25f89d3a5a" 49 | dependencies = [ 50 | "memchr", 51 | ] 52 | 53 | [[package]] 54 | name = "allocator-api2" 55 | version = "0.2.18" 56 | source = "registry+https://github.com/rust-lang/crates.io-index" 57 | checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" 58 | 59 | [[package]] 60 | name = "anes" 61 | version = "0.1.6" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" 64 | 65 | [[package]] 66 | name = "anstyle" 67 | version = "1.0.1" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" 70 | 71 | [[package]] 72 | name = "async-channel" 73 | version = "2.2.1" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "136d4d23bcc79e27423727b36823d86233aad06dfea531837b038394d11e9928" 76 | dependencies = [ 77 | "concurrent-queue", 78 | "event-listener 5.3.0", 79 | "event-listener-strategy 0.5.1", 80 | "futures-core", 81 | "pin-project-lite", 82 | ] 83 | 84 | [[package]] 85 | name = "async-executor" 86 | version = "1.11.0" 87 | source = "registry+https://github.com/rust-lang/crates.io-index" 88 | checksum = "b10202063978b3351199d68f8b22c4e47e4b1b822f8d43fd862d5ea8c006b29a" 89 | dependencies = [ 90 | "async-task", 91 | "concurrent-queue", 92 | "fastrand 2.0.2", 93 | "futures-lite 2.3.0", 94 | "slab", 95 | ] 96 | 97 | [[package]] 98 | name = "async-global-executor" 99 | version = "2.4.1" 100 | source = "registry+https://github.com/rust-lang/crates.io-index" 101 | checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" 102 | dependencies = [ 103 | "async-channel", 104 | "async-executor", 105 | "async-io 2.3.2", 106 | "async-lock 3.3.0", 107 | "blocking", 108 | "futures-lite 2.3.0", 109 | "once_cell", 110 | ] 111 | 112 | [[package]] 113 | name = "async-io" 114 | version = "1.13.0" 115 | source = "registry+https://github.com/rust-lang/crates.io-index" 116 | checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" 117 | dependencies = [ 118 | "async-lock 2.8.0", 119 | "autocfg", 120 | "cfg-if", 121 | "concurrent-queue", 122 | "futures-lite 1.13.0", 123 | "log", 124 | "parking", 125 | "polling 2.8.0", 126 | "rustix 0.37.23", 127 | "slab", 128 | "socket2 0.4.9", 129 | "waker-fn", 130 | ] 131 | 132 | [[package]] 133 | name = "async-io" 134 | version = "2.3.2" 135 | source = "registry+https://github.com/rust-lang/crates.io-index" 136 | checksum = "dcccb0f599cfa2f8ace422d3555572f47424da5648a4382a9dd0310ff8210884" 137 | dependencies = [ 138 | "async-lock 3.3.0", 139 | "cfg-if", 140 | "concurrent-queue", 141 | "futures-io", 142 | "futures-lite 2.3.0", 143 | "parking", 144 | "polling 3.5.0", 145 | "rustix 0.38.34", 146 | "slab", 147 | "tracing", 148 | "windows-sys 0.52.0", 149 | ] 150 | 151 | [[package]] 152 | name = "async-lock" 153 | version = "2.8.0" 154 | source = "registry+https://github.com/rust-lang/crates.io-index" 155 | checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" 156 | dependencies = [ 157 | "event-listener 2.5.3", 158 | ] 159 | 160 | [[package]] 161 | name = "async-lock" 162 | version = "3.3.0" 163 | source = "registry+https://github.com/rust-lang/crates.io-index" 164 | checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" 165 | dependencies = [ 166 | "event-listener 4.0.3", 167 | "event-listener-strategy 0.4.0", 168 | "pin-project-lite", 169 | ] 170 | 171 | [[package]] 172 | name = "async-net" 173 | version = "2.0.0" 174 | source = "registry+https://github.com/rust-lang/crates.io-index" 175 | checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" 176 | dependencies = [ 177 | "async-io 2.3.2", 178 | "blocking", 179 | "futures-lite 2.3.0", 180 | ] 181 | 182 | [[package]] 183 | name = "async-task" 184 | version = "4.4.0" 185 | source = "registry+https://github.com/rust-lang/crates.io-index" 186 | checksum = "ecc7ab41815b3c653ccd2978ec3255c81349336702dfdf62ee6f7069b12a3aae" 187 | 188 | [[package]] 189 | name = "async-trait" 190 | version = "0.1.80" 191 | source = "registry+https://github.com/rust-lang/crates.io-index" 192 | checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" 193 | dependencies = [ 194 | "proc-macro2", 195 | "quote", 196 | "syn 2.0.60", 197 | ] 198 | 199 | [[package]] 200 | name = "async-tungstenite" 201 | version = "0.25.1" 202 | source = "registry+https://github.com/rust-lang/crates.io-index" 203 | checksum = "2cca750b12e02c389c1694d35c16539f88b8bbaa5945934fdc1b41a776688589" 204 | dependencies = [ 205 | "futures-io", 206 | "futures-util", 207 | "log", 208 | "pin-project-lite", 209 | "tungstenite", 210 | ] 211 | 212 | [[package]] 213 | name = "async_cell" 214 | version = "0.2.2" 215 | source = "registry+https://github.com/rust-lang/crates.io-index" 216 | checksum = "834eee9ce518130a3b4d5af09ecc43e9d6b57ee76613f227a1ddd6b77c7a62bc" 217 | 218 | [[package]] 219 | name = "atomic-waker" 220 | version = "1.1.1" 221 | source = "registry+https://github.com/rust-lang/crates.io-index" 222 | checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3" 223 | 224 | [[package]] 225 | name = "autocfg" 226 | version = "1.1.0" 227 | source = "registry+https://github.com/rust-lang/crates.io-index" 228 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 229 | 230 | [[package]] 231 | name = "axum" 232 | version = "0.7.5" 233 | source = "registry+https://github.com/rust-lang/crates.io-index" 234 | checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" 235 | dependencies = [ 236 | "async-trait", 237 | "axum-core", 238 | "base64 0.21.2", 239 | "bytes", 240 | "futures-util", 241 | "http", 242 | "http-body", 243 | "http-body-util", 244 | "hyper", 245 | "hyper-util", 246 | "itoa", 247 | "matchit", 248 | "memchr", 249 | "mime", 250 | "percent-encoding", 251 | "pin-project-lite", 252 | "rustversion", 253 | "serde", 254 | "serde_urlencoded", 255 | "sha1", 256 | "sync_wrapper 1.0.1", 257 | "tokio", 258 | "tokio-tungstenite", 259 | "tower", 260 | "tower-layer", 261 | "tower-service", 262 | ] 263 | 264 | [[package]] 265 | name = "axum-core" 266 | version = "0.4.3" 267 | source = "registry+https://github.com/rust-lang/crates.io-index" 268 | checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" 269 | dependencies = [ 270 | "async-trait", 271 | "bytes", 272 | "futures-util", 273 | "http", 274 | "http-body", 275 | "http-body-util", 276 | "mime", 277 | "pin-project-lite", 278 | "rustversion", 279 | "sync_wrapper 0.1.2", 280 | "tower-layer", 281 | "tower-service", 282 | ] 283 | 284 | [[package]] 285 | name = "backtrace" 286 | version = "0.3.68" 287 | source = "registry+https://github.com/rust-lang/crates.io-index" 288 | checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" 289 | dependencies = [ 290 | "addr2line", 291 | "cc", 292 | "cfg-if", 293 | "libc", 294 | "miniz_oxide", 295 | "object", 296 | "rustc-demangle", 297 | ] 298 | 299 | [[package]] 300 | name = "base64" 301 | version = "0.21.2" 302 | source = "registry+https://github.com/rust-lang/crates.io-index" 303 | checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" 304 | 305 | [[package]] 306 | name = "base64" 307 | version = "0.22.0" 308 | source = "registry+https://github.com/rust-lang/crates.io-index" 309 | checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" 310 | 311 | [[package]] 312 | name = "base64-simd" 313 | version = "0.7.0" 314 | source = "registry+https://github.com/rust-lang/crates.io-index" 315 | checksum = "781dd20c3aff0bd194fe7d2a977dd92f21c173891f3a03b677359e5fa457e5d5" 316 | dependencies = [ 317 | "simd-abstraction", 318 | ] 319 | 320 | [[package]] 321 | name = "bitflags" 322 | version = "1.3.2" 323 | source = "registry+https://github.com/rust-lang/crates.io-index" 324 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 325 | 326 | [[package]] 327 | name = "bitflags" 328 | version = "2.4.0" 329 | source = "registry+https://github.com/rust-lang/crates.io-index" 330 | checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" 331 | 332 | [[package]] 333 | name = "bitvec" 334 | version = "1.0.1" 335 | source = "registry+https://github.com/rust-lang/crates.io-index" 336 | checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" 337 | dependencies = [ 338 | "funty", 339 | "radium", 340 | "tap", 341 | "wyz", 342 | ] 343 | 344 | [[package]] 345 | name = "block-buffer" 346 | version = "0.10.4" 347 | source = "registry+https://github.com/rust-lang/crates.io-index" 348 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 349 | dependencies = [ 350 | "generic-array", 351 | ] 352 | 353 | [[package]] 354 | name = "blocking" 355 | version = "1.5.1" 356 | source = "registry+https://github.com/rust-lang/crates.io-index" 357 | checksum = "6a37913e8dc4ddcc604f0c6d3bf2887c995153af3611de9e23c352b44c1b9118" 358 | dependencies = [ 359 | "async-channel", 360 | "async-lock 3.3.0", 361 | "async-task", 362 | "fastrand 2.0.2", 363 | "futures-io", 364 | "futures-lite 2.3.0", 365 | "piper", 366 | "tracing", 367 | ] 368 | 369 | [[package]] 370 | name = "bumpalo" 371 | version = "3.13.0" 372 | source = "registry+https://github.com/rust-lang/crates.io-index" 373 | checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" 374 | 375 | [[package]] 376 | name = "bytecheck" 377 | version = "0.6.11" 378 | source = "registry+https://github.com/rust-lang/crates.io-index" 379 | checksum = "8b6372023ac861f6e6dc89c8344a8f398fb42aaba2b5dbc649ca0c0e9dbcb627" 380 | dependencies = [ 381 | "bytecheck_derive", 382 | "ptr_meta", 383 | "simdutf8", 384 | ] 385 | 386 | [[package]] 387 | name = "bytecheck_derive" 388 | version = "0.6.11" 389 | source = "registry+https://github.com/rust-lang/crates.io-index" 390 | checksum = "a7ec4c6f261935ad534c0c22dbef2201b45918860eb1c574b972bd213a76af61" 391 | dependencies = [ 392 | "proc-macro2", 393 | "quote", 394 | "syn 1.0.109", 395 | ] 396 | 397 | [[package]] 398 | name = "byteorder" 399 | version = "1.4.3" 400 | source = "registry+https://github.com/rust-lang/crates.io-index" 401 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 402 | 403 | [[package]] 404 | name = "bytes" 405 | version = "1.4.0" 406 | source = "registry+https://github.com/rust-lang/crates.io-index" 407 | checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" 408 | 409 | [[package]] 410 | name = "cast" 411 | version = "0.3.0" 412 | source = "registry+https://github.com/rust-lang/crates.io-index" 413 | checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" 414 | 415 | [[package]] 416 | name = "cc" 417 | version = "1.0.82" 418 | source = "registry+https://github.com/rust-lang/crates.io-index" 419 | checksum = "305fe645edc1442a0fa8b6726ba61d422798d37a52e12eaecf4b022ebbb88f01" 420 | dependencies = [ 421 | "libc", 422 | ] 423 | 424 | [[package]] 425 | name = "cfg-if" 426 | version = "1.0.0" 427 | source = "registry+https://github.com/rust-lang/crates.io-index" 428 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 429 | 430 | [[package]] 431 | name = "ciborium" 432 | version = "0.2.1" 433 | source = "registry+https://github.com/rust-lang/crates.io-index" 434 | checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" 435 | dependencies = [ 436 | "ciborium-io", 437 | "ciborium-ll", 438 | "serde", 439 | ] 440 | 441 | [[package]] 442 | name = "ciborium-io" 443 | version = "0.2.1" 444 | source = "registry+https://github.com/rust-lang/crates.io-index" 445 | checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" 446 | 447 | [[package]] 448 | name = "ciborium-ll" 449 | version = "0.2.1" 450 | source = "registry+https://github.com/rust-lang/crates.io-index" 451 | checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" 452 | dependencies = [ 453 | "ciborium-io", 454 | "half", 455 | ] 456 | 457 | [[package]] 458 | name = "clap" 459 | version = "4.3.21" 460 | source = "registry+https://github.com/rust-lang/crates.io-index" 461 | checksum = "c27cdf28c0f604ba3f512b0c9a409f8de8513e4816705deb0498b627e7c3a3fd" 462 | dependencies = [ 463 | "clap_builder", 464 | ] 465 | 466 | [[package]] 467 | name = "clap_builder" 468 | version = "4.3.21" 469 | source = "registry+https://github.com/rust-lang/crates.io-index" 470 | checksum = "08a9f1ab5e9f01a9b81f202e8562eb9a10de70abf9eaeac1be465c28b75aa4aa" 471 | dependencies = [ 472 | "anstyle", 473 | "clap_lex", 474 | ] 475 | 476 | [[package]] 477 | name = "clap_lex" 478 | version = "0.5.0" 479 | source = "registry+https://github.com/rust-lang/crates.io-index" 480 | checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" 481 | 482 | [[package]] 483 | name = "concurrent-queue" 484 | version = "2.4.0" 485 | source = "registry+https://github.com/rust-lang/crates.io-index" 486 | checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363" 487 | dependencies = [ 488 | "crossbeam-utils", 489 | ] 490 | 491 | [[package]] 492 | name = "const-str" 493 | version = "0.3.2" 494 | source = "registry+https://github.com/rust-lang/crates.io-index" 495 | checksum = "21077772762a1002bb421c3af42ac1725fa56066bfc53d9a55bb79905df2aaf3" 496 | dependencies = [ 497 | "const-str-proc-macro", 498 | ] 499 | 500 | [[package]] 501 | name = "const-str-proc-macro" 502 | version = "0.3.2" 503 | source = "registry+https://github.com/rust-lang/crates.io-index" 504 | checksum = "5e1e0fdd2e5d3041e530e1b21158aeeef8b5d0e306bc5c1e3d6cf0930d10e25a" 505 | dependencies = [ 506 | "proc-macro2", 507 | "quote", 508 | "syn 1.0.109", 509 | ] 510 | 511 | [[package]] 512 | name = "cpufeatures" 513 | version = "0.2.9" 514 | source = "registry+https://github.com/rust-lang/crates.io-index" 515 | checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" 516 | dependencies = [ 517 | "libc", 518 | ] 519 | 520 | [[package]] 521 | name = "criterion" 522 | version = "0.5.1" 523 | source = "registry+https://github.com/rust-lang/crates.io-index" 524 | checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" 525 | dependencies = [ 526 | "anes", 527 | "cast", 528 | "ciborium", 529 | "clap", 530 | "criterion-plot", 531 | "is-terminal", 532 | "itertools", 533 | "num-traits", 534 | "once_cell", 535 | "oorandom", 536 | "plotters", 537 | "rayon", 538 | "regex", 539 | "serde", 540 | "serde_derive", 541 | "serde_json", 542 | "tinytemplate", 543 | "walkdir", 544 | ] 545 | 546 | [[package]] 547 | name = "criterion-plot" 548 | version = "0.5.0" 549 | source = "registry+https://github.com/rust-lang/crates.io-index" 550 | checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" 551 | dependencies = [ 552 | "cast", 553 | "itertools", 554 | ] 555 | 556 | [[package]] 557 | name = "crossbeam-channel" 558 | version = "0.5.8" 559 | source = "registry+https://github.com/rust-lang/crates.io-index" 560 | checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" 561 | dependencies = [ 562 | "cfg-if", 563 | "crossbeam-utils", 564 | ] 565 | 566 | [[package]] 567 | name = "crossbeam-deque" 568 | version = "0.8.3" 569 | source = "registry+https://github.com/rust-lang/crates.io-index" 570 | checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" 571 | dependencies = [ 572 | "cfg-if", 573 | "crossbeam-epoch", 574 | "crossbeam-utils", 575 | ] 576 | 577 | [[package]] 578 | name = "crossbeam-epoch" 579 | version = "0.9.15" 580 | source = "registry+https://github.com/rust-lang/crates.io-index" 581 | checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" 582 | dependencies = [ 583 | "autocfg", 584 | "cfg-if", 585 | "crossbeam-utils", 586 | "memoffset", 587 | "scopeguard", 588 | ] 589 | 590 | [[package]] 591 | name = "crossbeam-utils" 592 | version = "0.8.16" 593 | source = "registry+https://github.com/rust-lang/crates.io-index" 594 | checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" 595 | dependencies = [ 596 | "cfg-if", 597 | ] 598 | 599 | [[package]] 600 | name = "crypto-common" 601 | version = "0.1.6" 602 | source = "registry+https://github.com/rust-lang/crates.io-index" 603 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 604 | dependencies = [ 605 | "generic-array", 606 | "typenum", 607 | ] 608 | 609 | [[package]] 610 | name = "cssparser" 611 | version = "0.33.0" 612 | source = "registry+https://github.com/rust-lang/crates.io-index" 613 | checksum = "9be934d936a0fbed5bcdc01042b770de1398bf79d0e192f49fa7faea0e99281e" 614 | dependencies = [ 615 | "cssparser-macros", 616 | "dtoa-short", 617 | "itoa", 618 | "phf", 619 | "smallvec", 620 | ] 621 | 622 | [[package]] 623 | name = "cssparser-color" 624 | version = "0.1.0" 625 | source = "registry+https://github.com/rust-lang/crates.io-index" 626 | checksum = "556c099a61d85989d7af52b692e35a8d68a57e7df8c6d07563dc0778b3960c9f" 627 | dependencies = [ 628 | "cssparser", 629 | ] 630 | 631 | [[package]] 632 | name = "cssparser-macros" 633 | version = "0.6.1" 634 | source = "registry+https://github.com/rust-lang/crates.io-index" 635 | checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" 636 | dependencies = [ 637 | "quote", 638 | "syn 2.0.60", 639 | ] 640 | 641 | [[package]] 642 | name = "dashmap" 643 | version = "5.5.0" 644 | source = "registry+https://github.com/rust-lang/crates.io-index" 645 | checksum = "6943ae99c34386c84a470c499d3414f66502a41340aa895406e0d2e4a207b91d" 646 | dependencies = [ 647 | "cfg-if", 648 | "hashbrown 0.14.3", 649 | "lock_api", 650 | "once_cell", 651 | "parking_lot_core", 652 | ] 653 | 654 | [[package]] 655 | name = "data-encoding" 656 | version = "2.4.0" 657 | source = "registry+https://github.com/rust-lang/crates.io-index" 658 | checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" 659 | 660 | [[package]] 661 | name = "data-url" 662 | version = "0.1.1" 663 | source = "registry+https://github.com/rust-lang/crates.io-index" 664 | checksum = "3a30bfce702bcfa94e906ef82421f2c0e61c076ad76030c16ee5d2e9a32fe193" 665 | dependencies = [ 666 | "matches", 667 | ] 668 | 669 | [[package]] 670 | name = "digest" 671 | version = "0.10.7" 672 | source = "registry+https://github.com/rust-lang/crates.io-index" 673 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 674 | dependencies = [ 675 | "block-buffer", 676 | "crypto-common", 677 | ] 678 | 679 | [[package]] 680 | name = "dtoa" 681 | version = "1.0.9" 682 | source = "registry+https://github.com/rust-lang/crates.io-index" 683 | checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" 684 | 685 | [[package]] 686 | name = "dtoa-short" 687 | version = "0.3.4" 688 | source = "registry+https://github.com/rust-lang/crates.io-index" 689 | checksum = "dbaceec3c6e4211c79e7b1800fb9680527106beb2f9c51904a3210c03a448c74" 690 | dependencies = [ 691 | "dtoa", 692 | ] 693 | 694 | [[package]] 695 | name = "either" 696 | version = "1.9.0" 697 | source = "registry+https://github.com/rust-lang/crates.io-index" 698 | checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" 699 | 700 | [[package]] 701 | name = "encoding_rs" 702 | version = "0.8.34" 703 | source = "registry+https://github.com/rust-lang/crates.io-index" 704 | checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" 705 | dependencies = [ 706 | "cfg-if", 707 | ] 708 | 709 | [[package]] 710 | name = "errno" 711 | version = "0.3.8" 712 | source = "registry+https://github.com/rust-lang/crates.io-index" 713 | checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" 714 | dependencies = [ 715 | "libc", 716 | "windows-sys 0.52.0", 717 | ] 718 | 719 | [[package]] 720 | name = "event-listener" 721 | version = "2.5.3" 722 | source = "registry+https://github.com/rust-lang/crates.io-index" 723 | checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" 724 | 725 | [[package]] 726 | name = "event-listener" 727 | version = "4.0.3" 728 | source = "registry+https://github.com/rust-lang/crates.io-index" 729 | checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" 730 | dependencies = [ 731 | "concurrent-queue", 732 | "parking", 733 | "pin-project-lite", 734 | ] 735 | 736 | [[package]] 737 | name = "event-listener" 738 | version = "5.3.0" 739 | source = "registry+https://github.com/rust-lang/crates.io-index" 740 | checksum = "6d9944b8ca13534cdfb2800775f8dd4902ff3fc75a50101466decadfdf322a24" 741 | dependencies = [ 742 | "concurrent-queue", 743 | "parking", 744 | "pin-project-lite", 745 | ] 746 | 747 | [[package]] 748 | name = "event-listener-strategy" 749 | version = "0.4.0" 750 | source = "registry+https://github.com/rust-lang/crates.io-index" 751 | checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" 752 | dependencies = [ 753 | "event-listener 4.0.3", 754 | "pin-project-lite", 755 | ] 756 | 757 | [[package]] 758 | name = "event-listener-strategy" 759 | version = "0.5.1" 760 | source = "registry+https://github.com/rust-lang/crates.io-index" 761 | checksum = "332f51cb23d20b0de8458b86580878211da09bcd4503cb579c225b3d124cabb3" 762 | dependencies = [ 763 | "event-listener 5.3.0", 764 | "pin-project-lite", 765 | ] 766 | 767 | [[package]] 768 | name = "example-basic-trillium" 769 | version = "0.1.0" 770 | dependencies = [ 771 | "hyro", 772 | "trillium", 773 | "trillium-router", 774 | "trillium-smol", 775 | ] 776 | 777 | [[package]] 778 | name = "fastrand" 779 | version = "1.9.0" 780 | source = "registry+https://github.com/rust-lang/crates.io-index" 781 | checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" 782 | dependencies = [ 783 | "instant", 784 | ] 785 | 786 | [[package]] 787 | name = "fastrand" 788 | version = "2.0.2" 789 | source = "registry+https://github.com/rust-lang/crates.io-index" 790 | checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" 791 | 792 | [[package]] 793 | name = "filetime" 794 | version = "0.2.22" 795 | source = "registry+https://github.com/rust-lang/crates.io-index" 796 | checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0" 797 | dependencies = [ 798 | "cfg-if", 799 | "libc", 800 | "redox_syscall", 801 | "windows-sys 0.48.0", 802 | ] 803 | 804 | [[package]] 805 | name = "fnv" 806 | version = "1.0.7" 807 | source = "registry+https://github.com/rust-lang/crates.io-index" 808 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 809 | 810 | [[package]] 811 | name = "form_urlencoded" 812 | version = "1.2.1" 813 | source = "registry+https://github.com/rust-lang/crates.io-index" 814 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 815 | dependencies = [ 816 | "percent-encoding", 817 | ] 818 | 819 | [[package]] 820 | name = "fsevent-sys" 821 | version = "4.1.0" 822 | source = "registry+https://github.com/rust-lang/crates.io-index" 823 | checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" 824 | dependencies = [ 825 | "libc", 826 | ] 827 | 828 | [[package]] 829 | name = "funty" 830 | version = "2.0.0" 831 | source = "registry+https://github.com/rust-lang/crates.io-index" 832 | checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" 833 | 834 | [[package]] 835 | name = "futures" 836 | version = "0.3.28" 837 | source = "registry+https://github.com/rust-lang/crates.io-index" 838 | checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" 839 | dependencies = [ 840 | "futures-channel", 841 | "futures-core", 842 | "futures-executor", 843 | "futures-io", 844 | "futures-sink", 845 | "futures-task", 846 | "futures-util", 847 | ] 848 | 849 | [[package]] 850 | name = "futures-channel" 851 | version = "0.3.30" 852 | source = "registry+https://github.com/rust-lang/crates.io-index" 853 | checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" 854 | dependencies = [ 855 | "futures-core", 856 | "futures-sink", 857 | ] 858 | 859 | [[package]] 860 | name = "futures-core" 861 | version = "0.3.30" 862 | source = "registry+https://github.com/rust-lang/crates.io-index" 863 | checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" 864 | 865 | [[package]] 866 | name = "futures-executor" 867 | version = "0.3.28" 868 | source = "registry+https://github.com/rust-lang/crates.io-index" 869 | checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" 870 | dependencies = [ 871 | "futures-core", 872 | "futures-task", 873 | "futures-util", 874 | ] 875 | 876 | [[package]] 877 | name = "futures-io" 878 | version = "0.3.30" 879 | source = "registry+https://github.com/rust-lang/crates.io-index" 880 | checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" 881 | 882 | [[package]] 883 | name = "futures-lite" 884 | version = "1.13.0" 885 | source = "registry+https://github.com/rust-lang/crates.io-index" 886 | checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" 887 | dependencies = [ 888 | "fastrand 1.9.0", 889 | "futures-core", 890 | "futures-io", 891 | "memchr", 892 | "parking", 893 | "pin-project-lite", 894 | "waker-fn", 895 | ] 896 | 897 | [[package]] 898 | name = "futures-lite" 899 | version = "2.3.0" 900 | source = "registry+https://github.com/rust-lang/crates.io-index" 901 | checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" 902 | dependencies = [ 903 | "fastrand 2.0.2", 904 | "futures-core", 905 | "futures-io", 906 | "parking", 907 | "pin-project-lite", 908 | ] 909 | 910 | [[package]] 911 | name = "futures-macro" 912 | version = "0.3.30" 913 | source = "registry+https://github.com/rust-lang/crates.io-index" 914 | checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" 915 | dependencies = [ 916 | "proc-macro2", 917 | "quote", 918 | "syn 2.0.60", 919 | ] 920 | 921 | [[package]] 922 | name = "futures-sink" 923 | version = "0.3.30" 924 | source = "registry+https://github.com/rust-lang/crates.io-index" 925 | checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" 926 | 927 | [[package]] 928 | name = "futures-task" 929 | version = "0.3.30" 930 | source = "registry+https://github.com/rust-lang/crates.io-index" 931 | checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" 932 | 933 | [[package]] 934 | name = "futures-util" 935 | version = "0.3.30" 936 | source = "registry+https://github.com/rust-lang/crates.io-index" 937 | checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" 938 | dependencies = [ 939 | "futures-channel", 940 | "futures-core", 941 | "futures-io", 942 | "futures-macro", 943 | "futures-sink", 944 | "futures-task", 945 | "memchr", 946 | "pin-project-lite", 947 | "pin-utils", 948 | "slab", 949 | ] 950 | 951 | [[package]] 952 | name = "fxhash" 953 | version = "0.2.1" 954 | source = "registry+https://github.com/rust-lang/crates.io-index" 955 | checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" 956 | dependencies = [ 957 | "byteorder", 958 | ] 959 | 960 | [[package]] 961 | name = "generic-array" 962 | version = "0.14.7" 963 | source = "registry+https://github.com/rust-lang/crates.io-index" 964 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 965 | dependencies = [ 966 | "typenum", 967 | "version_check", 968 | ] 969 | 970 | [[package]] 971 | name = "getrandom" 972 | version = "0.2.10" 973 | source = "registry+https://github.com/rust-lang/crates.io-index" 974 | checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" 975 | dependencies = [ 976 | "cfg-if", 977 | "libc", 978 | "wasi", 979 | ] 980 | 981 | [[package]] 982 | name = "gimli" 983 | version = "0.27.3" 984 | source = "registry+https://github.com/rust-lang/crates.io-index" 985 | checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" 986 | 987 | [[package]] 988 | name = "half" 989 | version = "1.8.2" 990 | source = "registry+https://github.com/rust-lang/crates.io-index" 991 | checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" 992 | 993 | [[package]] 994 | name = "hashbrown" 995 | version = "0.12.3" 996 | source = "registry+https://github.com/rust-lang/crates.io-index" 997 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 998 | dependencies = [ 999 | "ahash 0.7.6", 1000 | ] 1001 | 1002 | [[package]] 1003 | name = "hashbrown" 1004 | version = "0.14.3" 1005 | source = "registry+https://github.com/rust-lang/crates.io-index" 1006 | checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" 1007 | dependencies = [ 1008 | "ahash 0.8.11", 1009 | "allocator-api2", 1010 | ] 1011 | 1012 | [[package]] 1013 | name = "hermit-abi" 1014 | version = "0.3.2" 1015 | source = "registry+https://github.com/rust-lang/crates.io-index" 1016 | checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" 1017 | 1018 | [[package]] 1019 | name = "http" 1020 | version = "1.1.0" 1021 | source = "registry+https://github.com/rust-lang/crates.io-index" 1022 | checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" 1023 | dependencies = [ 1024 | "bytes", 1025 | "fnv", 1026 | "itoa", 1027 | ] 1028 | 1029 | [[package]] 1030 | name = "http-body" 1031 | version = "1.0.0" 1032 | source = "registry+https://github.com/rust-lang/crates.io-index" 1033 | checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" 1034 | dependencies = [ 1035 | "bytes", 1036 | "http", 1037 | ] 1038 | 1039 | [[package]] 1040 | name = "http-body-util" 1041 | version = "0.1.1" 1042 | source = "registry+https://github.com/rust-lang/crates.io-index" 1043 | checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" 1044 | dependencies = [ 1045 | "bytes", 1046 | "futures-core", 1047 | "http", 1048 | "http-body", 1049 | "pin-project-lite", 1050 | ] 1051 | 1052 | [[package]] 1053 | name = "httparse" 1054 | version = "1.8.0" 1055 | source = "registry+https://github.com/rust-lang/crates.io-index" 1056 | checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" 1057 | 1058 | [[package]] 1059 | name = "httpdate" 1060 | version = "1.0.3" 1061 | source = "registry+https://github.com/rust-lang/crates.io-index" 1062 | checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" 1063 | 1064 | [[package]] 1065 | name = "hyper" 1066 | version = "1.3.1" 1067 | source = "registry+https://github.com/rust-lang/crates.io-index" 1068 | checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" 1069 | dependencies = [ 1070 | "bytes", 1071 | "http", 1072 | "http-body", 1073 | "httpdate", 1074 | "pin-project-lite", 1075 | "smallvec", 1076 | "tokio", 1077 | ] 1078 | 1079 | [[package]] 1080 | name = "hyper-util" 1081 | version = "0.1.3" 1082 | source = "registry+https://github.com/rust-lang/crates.io-index" 1083 | checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" 1084 | dependencies = [ 1085 | "bytes", 1086 | "futures-util", 1087 | "http", 1088 | "http-body", 1089 | "hyper", 1090 | "pin-project-lite", 1091 | "socket2 0.5.3", 1092 | "tokio", 1093 | ] 1094 | 1095 | [[package]] 1096 | name = "hyro" 1097 | version = "0.5.0" 1098 | dependencies = [ 1099 | "async-channel", 1100 | "async-global-executor", 1101 | "async-io 2.3.2", 1102 | "axum", 1103 | "cfg-if", 1104 | "criterion", 1105 | "futures", 1106 | "futures-lite 2.3.0", 1107 | "if-addrs", 1108 | "lightningcss", 1109 | "litemap", 1110 | "minijinja", 1111 | "notify", 1112 | "once_cell", 1113 | "parking_lot", 1114 | "serde_urlencoded", 1115 | "tap", 1116 | "tokio", 1117 | "tower-http", 1118 | "trillium", 1119 | "trillium-router", 1120 | "trillium-websockets", 1121 | "walkdir", 1122 | ] 1123 | 1124 | [[package]] 1125 | name = "idna" 1126 | version = "0.5.0" 1127 | source = "registry+https://github.com/rust-lang/crates.io-index" 1128 | checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" 1129 | dependencies = [ 1130 | "unicode-bidi", 1131 | "unicode-normalization", 1132 | ] 1133 | 1134 | [[package]] 1135 | name = "if-addrs" 1136 | version = "0.12.0" 1137 | source = "registry+https://github.com/rust-lang/crates.io-index" 1138 | checksum = "bb2a33e9c38988ecbda730c85b0fd9ddcdf83c0305ac7fd21c8bb9f57f2f0cc8" 1139 | dependencies = [ 1140 | "libc", 1141 | "windows-sys 0.52.0", 1142 | ] 1143 | 1144 | [[package]] 1145 | name = "inotify" 1146 | version = "0.9.6" 1147 | source = "registry+https://github.com/rust-lang/crates.io-index" 1148 | checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff" 1149 | dependencies = [ 1150 | "bitflags 1.3.2", 1151 | "inotify-sys", 1152 | "libc", 1153 | ] 1154 | 1155 | [[package]] 1156 | name = "inotify-sys" 1157 | version = "0.1.5" 1158 | source = "registry+https://github.com/rust-lang/crates.io-index" 1159 | checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" 1160 | dependencies = [ 1161 | "libc", 1162 | ] 1163 | 1164 | [[package]] 1165 | name = "instant" 1166 | version = "0.1.12" 1167 | source = "registry+https://github.com/rust-lang/crates.io-index" 1168 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" 1169 | dependencies = [ 1170 | "cfg-if", 1171 | ] 1172 | 1173 | [[package]] 1174 | name = "io-lifetimes" 1175 | version = "1.0.11" 1176 | source = "registry+https://github.com/rust-lang/crates.io-index" 1177 | checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" 1178 | dependencies = [ 1179 | "hermit-abi", 1180 | "libc", 1181 | "windows-sys 0.48.0", 1182 | ] 1183 | 1184 | [[package]] 1185 | name = "is-terminal" 1186 | version = "0.4.9" 1187 | source = "registry+https://github.com/rust-lang/crates.io-index" 1188 | checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" 1189 | dependencies = [ 1190 | "hermit-abi", 1191 | "rustix 0.38.34", 1192 | "windows-sys 0.48.0", 1193 | ] 1194 | 1195 | [[package]] 1196 | name = "itertools" 1197 | version = "0.10.5" 1198 | source = "registry+https://github.com/rust-lang/crates.io-index" 1199 | checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" 1200 | dependencies = [ 1201 | "either", 1202 | ] 1203 | 1204 | [[package]] 1205 | name = "itoa" 1206 | version = "1.0.9" 1207 | source = "registry+https://github.com/rust-lang/crates.io-index" 1208 | checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" 1209 | 1210 | [[package]] 1211 | name = "js-sys" 1212 | version = "0.3.64" 1213 | source = "registry+https://github.com/rust-lang/crates.io-index" 1214 | checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" 1215 | dependencies = [ 1216 | "wasm-bindgen", 1217 | ] 1218 | 1219 | [[package]] 1220 | name = "kqueue" 1221 | version = "1.0.8" 1222 | source = "registry+https://github.com/rust-lang/crates.io-index" 1223 | checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c" 1224 | dependencies = [ 1225 | "kqueue-sys", 1226 | "libc", 1227 | ] 1228 | 1229 | [[package]] 1230 | name = "kqueue-sys" 1231 | version = "1.0.4" 1232 | source = "registry+https://github.com/rust-lang/crates.io-index" 1233 | checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" 1234 | dependencies = [ 1235 | "bitflags 1.3.2", 1236 | "libc", 1237 | ] 1238 | 1239 | [[package]] 1240 | name = "lazy_static" 1241 | version = "1.4.0" 1242 | source = "registry+https://github.com/rust-lang/crates.io-index" 1243 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 1244 | 1245 | [[package]] 1246 | name = "libc" 1247 | version = "0.2.153" 1248 | source = "registry+https://github.com/rust-lang/crates.io-index" 1249 | checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" 1250 | 1251 | [[package]] 1252 | name = "lightningcss" 1253 | version = "1.0.0-alpha.55" 1254 | source = "registry+https://github.com/rust-lang/crates.io-index" 1255 | checksum = "3bd5bed3814fb631bfc1e24c2be6f7e86a9837c660909acab79a38374dcb8798" 1256 | dependencies = [ 1257 | "ahash 0.8.11", 1258 | "bitflags 2.4.0", 1259 | "const-str", 1260 | "cssparser", 1261 | "cssparser-color", 1262 | "dashmap", 1263 | "data-encoding", 1264 | "getrandom", 1265 | "itertools", 1266 | "lazy_static", 1267 | "parcel_selectors", 1268 | "parcel_sourcemap", 1269 | "paste", 1270 | "pathdiff", 1271 | "rayon", 1272 | "smallvec", 1273 | ] 1274 | 1275 | [[package]] 1276 | name = "linux-raw-sys" 1277 | version = "0.3.8" 1278 | source = "registry+https://github.com/rust-lang/crates.io-index" 1279 | checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" 1280 | 1281 | [[package]] 1282 | name = "linux-raw-sys" 1283 | version = "0.4.13" 1284 | source = "registry+https://github.com/rust-lang/crates.io-index" 1285 | checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" 1286 | 1287 | [[package]] 1288 | name = "litemap" 1289 | version = "0.7.2" 1290 | source = "registry+https://github.com/rust-lang/crates.io-index" 1291 | checksum = "f9d642685b028806386b2b6e75685faadd3eb65a85fff7df711ce18446a422da" 1292 | 1293 | [[package]] 1294 | name = "lock_api" 1295 | version = "0.4.10" 1296 | source = "registry+https://github.com/rust-lang/crates.io-index" 1297 | checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" 1298 | dependencies = [ 1299 | "autocfg", 1300 | "scopeguard", 1301 | ] 1302 | 1303 | [[package]] 1304 | name = "log" 1305 | version = "0.4.20" 1306 | source = "registry+https://github.com/rust-lang/crates.io-index" 1307 | checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" 1308 | 1309 | [[package]] 1310 | name = "matches" 1311 | version = "0.1.10" 1312 | source = "registry+https://github.com/rust-lang/crates.io-index" 1313 | checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" 1314 | 1315 | [[package]] 1316 | name = "matchit" 1317 | version = "0.7.2" 1318 | source = "registry+https://github.com/rust-lang/crates.io-index" 1319 | checksum = "ed1202b2a6f884ae56f04cff409ab315c5ce26b5e58d7412e484f01fd52f52ef" 1320 | 1321 | [[package]] 1322 | name = "memchr" 1323 | version = "2.7.2" 1324 | source = "registry+https://github.com/rust-lang/crates.io-index" 1325 | checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" 1326 | 1327 | [[package]] 1328 | name = "memoffset" 1329 | version = "0.9.0" 1330 | source = "registry+https://github.com/rust-lang/crates.io-index" 1331 | checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" 1332 | dependencies = [ 1333 | "autocfg", 1334 | ] 1335 | 1336 | [[package]] 1337 | name = "mime" 1338 | version = "0.3.17" 1339 | source = "registry+https://github.com/rust-lang/crates.io-index" 1340 | checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 1341 | 1342 | [[package]] 1343 | name = "minijinja" 1344 | version = "2.0.0-alpha.0" 1345 | source = "registry+https://github.com/rust-lang/crates.io-index" 1346 | checksum = "bdd7a5a74b327c5a0f837ca770583b1ca66404901a77387d3c3ec9bd8ede7ef9" 1347 | dependencies = [ 1348 | "serde", 1349 | ] 1350 | 1351 | [[package]] 1352 | name = "miniz_oxide" 1353 | version = "0.7.1" 1354 | source = "registry+https://github.com/rust-lang/crates.io-index" 1355 | checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" 1356 | dependencies = [ 1357 | "adler", 1358 | ] 1359 | 1360 | [[package]] 1361 | name = "mio" 1362 | version = "0.8.8" 1363 | source = "registry+https://github.com/rust-lang/crates.io-index" 1364 | checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" 1365 | dependencies = [ 1366 | "libc", 1367 | "log", 1368 | "wasi", 1369 | "windows-sys 0.48.0", 1370 | ] 1371 | 1372 | [[package]] 1373 | name = "notify" 1374 | version = "6.0.1" 1375 | source = "registry+https://github.com/rust-lang/crates.io-index" 1376 | checksum = "5738a2795d57ea20abec2d6d76c6081186709c0024187cd5977265eda6598b51" 1377 | dependencies = [ 1378 | "bitflags 1.3.2", 1379 | "crossbeam-channel", 1380 | "filetime", 1381 | "fsevent-sys", 1382 | "inotify", 1383 | "kqueue", 1384 | "libc", 1385 | "mio", 1386 | "walkdir", 1387 | "windows-sys 0.45.0", 1388 | ] 1389 | 1390 | [[package]] 1391 | name = "num-traits" 1392 | version = "0.2.16" 1393 | source = "registry+https://github.com/rust-lang/crates.io-index" 1394 | checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" 1395 | dependencies = [ 1396 | "autocfg", 1397 | ] 1398 | 1399 | [[package]] 1400 | name = "num_cpus" 1401 | version = "1.16.0" 1402 | source = "registry+https://github.com/rust-lang/crates.io-index" 1403 | checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" 1404 | dependencies = [ 1405 | "hermit-abi", 1406 | "libc", 1407 | ] 1408 | 1409 | [[package]] 1410 | name = "object" 1411 | version = "0.31.1" 1412 | source = "registry+https://github.com/rust-lang/crates.io-index" 1413 | checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" 1414 | dependencies = [ 1415 | "memchr", 1416 | ] 1417 | 1418 | [[package]] 1419 | name = "once_cell" 1420 | version = "1.18.0" 1421 | source = "registry+https://github.com/rust-lang/crates.io-index" 1422 | checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" 1423 | dependencies = [ 1424 | "parking_lot_core", 1425 | ] 1426 | 1427 | [[package]] 1428 | name = "oorandom" 1429 | version = "11.1.3" 1430 | source = "registry+https://github.com/rust-lang/crates.io-index" 1431 | checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" 1432 | 1433 | [[package]] 1434 | name = "outref" 1435 | version = "0.1.0" 1436 | source = "registry+https://github.com/rust-lang/crates.io-index" 1437 | checksum = "7f222829ae9293e33a9f5e9f440c6760a3d450a64affe1846486b140db81c1f4" 1438 | 1439 | [[package]] 1440 | name = "parcel_selectors" 1441 | version = "0.26.4" 1442 | source = "registry+https://github.com/rust-lang/crates.io-index" 1443 | checksum = "05d74befe2d076330d9a58bf9ca2da424568724ab278adf15fb5718253133887" 1444 | dependencies = [ 1445 | "bitflags 2.4.0", 1446 | "cssparser", 1447 | "fxhash", 1448 | "log", 1449 | "phf", 1450 | "phf_codegen", 1451 | "precomputed-hash", 1452 | "smallvec", 1453 | ] 1454 | 1455 | [[package]] 1456 | name = "parcel_sourcemap" 1457 | version = "2.1.1" 1458 | source = "registry+https://github.com/rust-lang/crates.io-index" 1459 | checksum = "485b74d7218068b2b7c0e3ff12fbc61ae11d57cb5d8224f525bd304c6be05bbb" 1460 | dependencies = [ 1461 | "base64-simd", 1462 | "data-url", 1463 | "rkyv", 1464 | "serde", 1465 | "serde_json", 1466 | "vlq", 1467 | ] 1468 | 1469 | [[package]] 1470 | name = "parking" 1471 | version = "2.2.0" 1472 | source = "registry+https://github.com/rust-lang/crates.io-index" 1473 | checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" 1474 | 1475 | [[package]] 1476 | name = "parking_lot" 1477 | version = "0.12.1" 1478 | source = "registry+https://github.com/rust-lang/crates.io-index" 1479 | checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" 1480 | dependencies = [ 1481 | "lock_api", 1482 | "parking_lot_core", 1483 | ] 1484 | 1485 | [[package]] 1486 | name = "parking_lot_core" 1487 | version = "0.9.8" 1488 | source = "registry+https://github.com/rust-lang/crates.io-index" 1489 | checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" 1490 | dependencies = [ 1491 | "cfg-if", 1492 | "libc", 1493 | "redox_syscall", 1494 | "smallvec", 1495 | "windows-targets 0.48.2", 1496 | ] 1497 | 1498 | [[package]] 1499 | name = "paste" 1500 | version = "1.0.14" 1501 | source = "registry+https://github.com/rust-lang/crates.io-index" 1502 | checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" 1503 | 1504 | [[package]] 1505 | name = "pathdiff" 1506 | version = "0.2.1" 1507 | source = "registry+https://github.com/rust-lang/crates.io-index" 1508 | checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" 1509 | 1510 | [[package]] 1511 | name = "percent-encoding" 1512 | version = "2.3.1" 1513 | source = "registry+https://github.com/rust-lang/crates.io-index" 1514 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 1515 | 1516 | [[package]] 1517 | name = "phf" 1518 | version = "0.10.1" 1519 | source = "registry+https://github.com/rust-lang/crates.io-index" 1520 | checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" 1521 | dependencies = [ 1522 | "phf_macros", 1523 | "phf_shared", 1524 | "proc-macro-hack", 1525 | ] 1526 | 1527 | [[package]] 1528 | name = "phf_codegen" 1529 | version = "0.10.0" 1530 | source = "registry+https://github.com/rust-lang/crates.io-index" 1531 | checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" 1532 | dependencies = [ 1533 | "phf_generator", 1534 | "phf_shared", 1535 | ] 1536 | 1537 | [[package]] 1538 | name = "phf_generator" 1539 | version = "0.10.0" 1540 | source = "registry+https://github.com/rust-lang/crates.io-index" 1541 | checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" 1542 | dependencies = [ 1543 | "phf_shared", 1544 | "rand", 1545 | ] 1546 | 1547 | [[package]] 1548 | name = "phf_macros" 1549 | version = "0.10.0" 1550 | source = "registry+https://github.com/rust-lang/crates.io-index" 1551 | checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0" 1552 | dependencies = [ 1553 | "phf_generator", 1554 | "phf_shared", 1555 | "proc-macro-hack", 1556 | "proc-macro2", 1557 | "quote", 1558 | "syn 1.0.109", 1559 | ] 1560 | 1561 | [[package]] 1562 | name = "phf_shared" 1563 | version = "0.10.0" 1564 | source = "registry+https://github.com/rust-lang/crates.io-index" 1565 | checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" 1566 | dependencies = [ 1567 | "siphasher", 1568 | ] 1569 | 1570 | [[package]] 1571 | name = "pin-project" 1572 | version = "1.1.3" 1573 | source = "registry+https://github.com/rust-lang/crates.io-index" 1574 | checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" 1575 | dependencies = [ 1576 | "pin-project-internal", 1577 | ] 1578 | 1579 | [[package]] 1580 | name = "pin-project-internal" 1581 | version = "1.1.3" 1582 | source = "registry+https://github.com/rust-lang/crates.io-index" 1583 | checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" 1584 | dependencies = [ 1585 | "proc-macro2", 1586 | "quote", 1587 | "syn 2.0.60", 1588 | ] 1589 | 1590 | [[package]] 1591 | name = "pin-project-lite" 1592 | version = "0.2.14" 1593 | source = "registry+https://github.com/rust-lang/crates.io-index" 1594 | checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" 1595 | 1596 | [[package]] 1597 | name = "pin-utils" 1598 | version = "0.1.0" 1599 | source = "registry+https://github.com/rust-lang/crates.io-index" 1600 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1601 | 1602 | [[package]] 1603 | name = "piper" 1604 | version = "0.2.1" 1605 | source = "registry+https://github.com/rust-lang/crates.io-index" 1606 | checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4" 1607 | dependencies = [ 1608 | "atomic-waker", 1609 | "fastrand 2.0.2", 1610 | "futures-io", 1611 | ] 1612 | 1613 | [[package]] 1614 | name = "plotters" 1615 | version = "0.3.5" 1616 | source = "registry+https://github.com/rust-lang/crates.io-index" 1617 | checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" 1618 | dependencies = [ 1619 | "num-traits", 1620 | "plotters-backend", 1621 | "plotters-svg", 1622 | "wasm-bindgen", 1623 | "web-sys", 1624 | ] 1625 | 1626 | [[package]] 1627 | name = "plotters-backend" 1628 | version = "0.3.5" 1629 | source = "registry+https://github.com/rust-lang/crates.io-index" 1630 | checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609" 1631 | 1632 | [[package]] 1633 | name = "plotters-svg" 1634 | version = "0.3.5" 1635 | source = "registry+https://github.com/rust-lang/crates.io-index" 1636 | checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab" 1637 | dependencies = [ 1638 | "plotters-backend", 1639 | ] 1640 | 1641 | [[package]] 1642 | name = "polling" 1643 | version = "2.8.0" 1644 | source = "registry+https://github.com/rust-lang/crates.io-index" 1645 | checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" 1646 | dependencies = [ 1647 | "autocfg", 1648 | "bitflags 1.3.2", 1649 | "cfg-if", 1650 | "concurrent-queue", 1651 | "libc", 1652 | "log", 1653 | "pin-project-lite", 1654 | "windows-sys 0.48.0", 1655 | ] 1656 | 1657 | [[package]] 1658 | name = "polling" 1659 | version = "3.5.0" 1660 | source = "registry+https://github.com/rust-lang/crates.io-index" 1661 | checksum = "24f040dee2588b4963afb4e420540439d126f73fdacf4a9c486a96d840bac3c9" 1662 | dependencies = [ 1663 | "cfg-if", 1664 | "concurrent-queue", 1665 | "pin-project-lite", 1666 | "rustix 0.38.34", 1667 | "tracing", 1668 | "windows-sys 0.52.0", 1669 | ] 1670 | 1671 | [[package]] 1672 | name = "ppv-lite86" 1673 | version = "0.2.17" 1674 | source = "registry+https://github.com/rust-lang/crates.io-index" 1675 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 1676 | 1677 | [[package]] 1678 | name = "precomputed-hash" 1679 | version = "0.1.1" 1680 | source = "registry+https://github.com/rust-lang/crates.io-index" 1681 | checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" 1682 | 1683 | [[package]] 1684 | name = "proc-macro-hack" 1685 | version = "0.5.20+deprecated" 1686 | source = "registry+https://github.com/rust-lang/crates.io-index" 1687 | checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" 1688 | 1689 | [[package]] 1690 | name = "proc-macro2" 1691 | version = "1.0.81" 1692 | source = "registry+https://github.com/rust-lang/crates.io-index" 1693 | checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" 1694 | dependencies = [ 1695 | "unicode-ident", 1696 | ] 1697 | 1698 | [[package]] 1699 | name = "ptr_meta" 1700 | version = "0.1.4" 1701 | source = "registry+https://github.com/rust-lang/crates.io-index" 1702 | checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" 1703 | dependencies = [ 1704 | "ptr_meta_derive", 1705 | ] 1706 | 1707 | [[package]] 1708 | name = "ptr_meta_derive" 1709 | version = "0.1.4" 1710 | source = "registry+https://github.com/rust-lang/crates.io-index" 1711 | checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" 1712 | dependencies = [ 1713 | "proc-macro2", 1714 | "quote", 1715 | "syn 1.0.109", 1716 | ] 1717 | 1718 | [[package]] 1719 | name = "quote" 1720 | version = "1.0.36" 1721 | source = "registry+https://github.com/rust-lang/crates.io-index" 1722 | checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" 1723 | dependencies = [ 1724 | "proc-macro2", 1725 | ] 1726 | 1727 | [[package]] 1728 | name = "radium" 1729 | version = "0.7.0" 1730 | source = "registry+https://github.com/rust-lang/crates.io-index" 1731 | checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" 1732 | 1733 | [[package]] 1734 | name = "rand" 1735 | version = "0.8.5" 1736 | source = "registry+https://github.com/rust-lang/crates.io-index" 1737 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 1738 | dependencies = [ 1739 | "libc", 1740 | "rand_chacha", 1741 | "rand_core", 1742 | ] 1743 | 1744 | [[package]] 1745 | name = "rand_chacha" 1746 | version = "0.3.1" 1747 | source = "registry+https://github.com/rust-lang/crates.io-index" 1748 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 1749 | dependencies = [ 1750 | "ppv-lite86", 1751 | "rand_core", 1752 | ] 1753 | 1754 | [[package]] 1755 | name = "rand_core" 1756 | version = "0.6.4" 1757 | source = "registry+https://github.com/rust-lang/crates.io-index" 1758 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 1759 | dependencies = [ 1760 | "getrandom", 1761 | ] 1762 | 1763 | [[package]] 1764 | name = "rayon" 1765 | version = "1.7.0" 1766 | source = "registry+https://github.com/rust-lang/crates.io-index" 1767 | checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" 1768 | dependencies = [ 1769 | "either", 1770 | "rayon-core", 1771 | ] 1772 | 1773 | [[package]] 1774 | name = "rayon-core" 1775 | version = "1.11.0" 1776 | source = "registry+https://github.com/rust-lang/crates.io-index" 1777 | checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" 1778 | dependencies = [ 1779 | "crossbeam-channel", 1780 | "crossbeam-deque", 1781 | "crossbeam-utils", 1782 | "num_cpus", 1783 | ] 1784 | 1785 | [[package]] 1786 | name = "redox_syscall" 1787 | version = "0.3.5" 1788 | source = "registry+https://github.com/rust-lang/crates.io-index" 1789 | checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" 1790 | dependencies = [ 1791 | "bitflags 1.3.2", 1792 | ] 1793 | 1794 | [[package]] 1795 | name = "regex" 1796 | version = "1.9.3" 1797 | source = "registry+https://github.com/rust-lang/crates.io-index" 1798 | checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a" 1799 | dependencies = [ 1800 | "aho-corasick", 1801 | "memchr", 1802 | "regex-automata", 1803 | "regex-syntax", 1804 | ] 1805 | 1806 | [[package]] 1807 | name = "regex-automata" 1808 | version = "0.3.6" 1809 | source = "registry+https://github.com/rust-lang/crates.io-index" 1810 | checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69" 1811 | dependencies = [ 1812 | "aho-corasick", 1813 | "memchr", 1814 | "regex-syntax", 1815 | ] 1816 | 1817 | [[package]] 1818 | name = "regex-syntax" 1819 | version = "0.7.4" 1820 | source = "registry+https://github.com/rust-lang/crates.io-index" 1821 | checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" 1822 | 1823 | [[package]] 1824 | name = "rend" 1825 | version = "0.4.0" 1826 | source = "registry+https://github.com/rust-lang/crates.io-index" 1827 | checksum = "581008d2099240d37fb08d77ad713bcaec2c4d89d50b5b21a8bb1996bbab68ab" 1828 | dependencies = [ 1829 | "bytecheck", 1830 | ] 1831 | 1832 | [[package]] 1833 | name = "rkyv" 1834 | version = "0.7.42" 1835 | source = "registry+https://github.com/rust-lang/crates.io-index" 1836 | checksum = "0200c8230b013893c0b2d6213d6ec64ed2b9be2e0e016682b7224ff82cff5c58" 1837 | dependencies = [ 1838 | "bitvec", 1839 | "bytecheck", 1840 | "hashbrown 0.12.3", 1841 | "ptr_meta", 1842 | "rend", 1843 | "rkyv_derive", 1844 | "seahash", 1845 | "tinyvec", 1846 | "uuid", 1847 | ] 1848 | 1849 | [[package]] 1850 | name = "rkyv_derive" 1851 | version = "0.7.42" 1852 | source = "registry+https://github.com/rust-lang/crates.io-index" 1853 | checksum = "b2e06b915b5c230a17d7a736d1e2e63ee753c256a8614ef3f5147b13a4f5541d" 1854 | dependencies = [ 1855 | "proc-macro2", 1856 | "quote", 1857 | "syn 1.0.109", 1858 | ] 1859 | 1860 | [[package]] 1861 | name = "rlimit" 1862 | version = "0.10.1" 1863 | source = "registry+https://github.com/rust-lang/crates.io-index" 1864 | checksum = "3560f70f30a0f16d11d01ed078a07740fe6b489667abc7c7b029155d9f21c3d8" 1865 | dependencies = [ 1866 | "libc", 1867 | ] 1868 | 1869 | [[package]] 1870 | name = "routefinder" 1871 | version = "0.5.4" 1872 | source = "registry+https://github.com/rust-lang/crates.io-index" 1873 | checksum = "0971d3c8943a6267d6bd0d782fdc4afa7593e7381a92a3df950ff58897e066b5" 1874 | dependencies = [ 1875 | "memchr", 1876 | "smartcow", 1877 | "smartstring", 1878 | ] 1879 | 1880 | [[package]] 1881 | name = "rustc-demangle" 1882 | version = "0.1.23" 1883 | source = "registry+https://github.com/rust-lang/crates.io-index" 1884 | checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" 1885 | 1886 | [[package]] 1887 | name = "rustix" 1888 | version = "0.37.23" 1889 | source = "registry+https://github.com/rust-lang/crates.io-index" 1890 | checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" 1891 | dependencies = [ 1892 | "bitflags 1.3.2", 1893 | "errno", 1894 | "io-lifetimes", 1895 | "libc", 1896 | "linux-raw-sys 0.3.8", 1897 | "windows-sys 0.48.0", 1898 | ] 1899 | 1900 | [[package]] 1901 | name = "rustix" 1902 | version = "0.38.34" 1903 | source = "registry+https://github.com/rust-lang/crates.io-index" 1904 | checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" 1905 | dependencies = [ 1906 | "bitflags 2.4.0", 1907 | "errno", 1908 | "libc", 1909 | "linux-raw-sys 0.4.13", 1910 | "windows-sys 0.52.0", 1911 | ] 1912 | 1913 | [[package]] 1914 | name = "rustversion" 1915 | version = "1.0.14" 1916 | source = "registry+https://github.com/rust-lang/crates.io-index" 1917 | checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" 1918 | 1919 | [[package]] 1920 | name = "ryu" 1921 | version = "1.0.15" 1922 | source = "registry+https://github.com/rust-lang/crates.io-index" 1923 | checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" 1924 | 1925 | [[package]] 1926 | name = "same-file" 1927 | version = "1.0.6" 1928 | source = "registry+https://github.com/rust-lang/crates.io-index" 1929 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 1930 | dependencies = [ 1931 | "winapi-util", 1932 | ] 1933 | 1934 | [[package]] 1935 | name = "scopeguard" 1936 | version = "1.2.0" 1937 | source = "registry+https://github.com/rust-lang/crates.io-index" 1938 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 1939 | 1940 | [[package]] 1941 | name = "seahash" 1942 | version = "4.1.0" 1943 | source = "registry+https://github.com/rust-lang/crates.io-index" 1944 | checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" 1945 | 1946 | [[package]] 1947 | name = "serde" 1948 | version = "1.0.183" 1949 | source = "registry+https://github.com/rust-lang/crates.io-index" 1950 | checksum = "32ac8da02677876d532745a130fc9d8e6edfa81a269b107c5b00829b91d8eb3c" 1951 | dependencies = [ 1952 | "serde_derive", 1953 | ] 1954 | 1955 | [[package]] 1956 | name = "serde_derive" 1957 | version = "1.0.183" 1958 | source = "registry+https://github.com/rust-lang/crates.io-index" 1959 | checksum = "aafe972d60b0b9bee71a91b92fee2d4fb3c9d7e8f6b179aa99f27203d99a4816" 1960 | dependencies = [ 1961 | "proc-macro2", 1962 | "quote", 1963 | "syn 2.0.60", 1964 | ] 1965 | 1966 | [[package]] 1967 | name = "serde_json" 1968 | version = "1.0.104" 1969 | source = "registry+https://github.com/rust-lang/crates.io-index" 1970 | checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" 1971 | dependencies = [ 1972 | "itoa", 1973 | "ryu", 1974 | "serde", 1975 | ] 1976 | 1977 | [[package]] 1978 | name = "serde_urlencoded" 1979 | version = "0.7.1" 1980 | source = "registry+https://github.com/rust-lang/crates.io-index" 1981 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 1982 | dependencies = [ 1983 | "form_urlencoded", 1984 | "itoa", 1985 | "ryu", 1986 | "serde", 1987 | ] 1988 | 1989 | [[package]] 1990 | name = "sha-1" 1991 | version = "0.10.1" 1992 | source = "registry+https://github.com/rust-lang/crates.io-index" 1993 | checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" 1994 | dependencies = [ 1995 | "cfg-if", 1996 | "cpufeatures", 1997 | "digest", 1998 | ] 1999 | 2000 | [[package]] 2001 | name = "sha1" 2002 | version = "0.10.5" 2003 | source = "registry+https://github.com/rust-lang/crates.io-index" 2004 | checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" 2005 | dependencies = [ 2006 | "cfg-if", 2007 | "cpufeatures", 2008 | "digest", 2009 | ] 2010 | 2011 | [[package]] 2012 | name = "signal-hook" 2013 | version = "0.3.17" 2014 | source = "registry+https://github.com/rust-lang/crates.io-index" 2015 | checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" 2016 | dependencies = [ 2017 | "libc", 2018 | "signal-hook-registry", 2019 | ] 2020 | 2021 | [[package]] 2022 | name = "signal-hook-async-std" 2023 | version = "0.2.2" 2024 | source = "registry+https://github.com/rust-lang/crates.io-index" 2025 | checksum = "0c4aa94397e2023af5b7cff5b8d4785e935cfb77f0e4aab0cae3b26258ace556" 2026 | dependencies = [ 2027 | "async-io 1.13.0", 2028 | "futures-lite 1.13.0", 2029 | "libc", 2030 | "signal-hook", 2031 | ] 2032 | 2033 | [[package]] 2034 | name = "signal-hook-registry" 2035 | version = "1.4.1" 2036 | source = "registry+https://github.com/rust-lang/crates.io-index" 2037 | checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" 2038 | dependencies = [ 2039 | "libc", 2040 | ] 2041 | 2042 | [[package]] 2043 | name = "simd-abstraction" 2044 | version = "0.7.1" 2045 | source = "registry+https://github.com/rust-lang/crates.io-index" 2046 | checksum = "9cadb29c57caadc51ff8346233b5cec1d240b68ce55cf1afc764818791876987" 2047 | dependencies = [ 2048 | "outref", 2049 | ] 2050 | 2051 | [[package]] 2052 | name = "simdutf8" 2053 | version = "0.1.4" 2054 | source = "registry+https://github.com/rust-lang/crates.io-index" 2055 | checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" 2056 | 2057 | [[package]] 2058 | name = "siphasher" 2059 | version = "0.3.10" 2060 | source = "registry+https://github.com/rust-lang/crates.io-index" 2061 | checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" 2062 | 2063 | [[package]] 2064 | name = "slab" 2065 | version = "0.4.8" 2066 | source = "registry+https://github.com/rust-lang/crates.io-index" 2067 | checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" 2068 | dependencies = [ 2069 | "autocfg", 2070 | ] 2071 | 2072 | [[package]] 2073 | name = "smallvec" 2074 | version = "1.13.2" 2075 | source = "registry+https://github.com/rust-lang/crates.io-index" 2076 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 2077 | 2078 | [[package]] 2079 | name = "smartcow" 2080 | version = "0.2.1" 2081 | source = "registry+https://github.com/rust-lang/crates.io-index" 2082 | checksum = "656fcb1c1fca8c4655372134ce87d8afdf5ec5949ebabe8d314be0141d8b5da2" 2083 | dependencies = [ 2084 | "smartstring", 2085 | ] 2086 | 2087 | [[package]] 2088 | name = "smartstring" 2089 | version = "1.0.1" 2090 | source = "registry+https://github.com/rust-lang/crates.io-index" 2091 | checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29" 2092 | dependencies = [ 2093 | "autocfg", 2094 | "static_assertions", 2095 | "version_check", 2096 | ] 2097 | 2098 | [[package]] 2099 | name = "socket2" 2100 | version = "0.4.9" 2101 | source = "registry+https://github.com/rust-lang/crates.io-index" 2102 | checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" 2103 | dependencies = [ 2104 | "libc", 2105 | "winapi", 2106 | ] 2107 | 2108 | [[package]] 2109 | name = "socket2" 2110 | version = "0.5.3" 2111 | source = "registry+https://github.com/rust-lang/crates.io-index" 2112 | checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877" 2113 | dependencies = [ 2114 | "libc", 2115 | "windows-sys 0.48.0", 2116 | ] 2117 | 2118 | [[package]] 2119 | name = "static_assertions" 2120 | version = "1.1.0" 2121 | source = "registry+https://github.com/rust-lang/crates.io-index" 2122 | checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" 2123 | 2124 | [[package]] 2125 | name = "stopper" 2126 | version = "0.2.7" 2127 | source = "registry+https://github.com/rust-lang/crates.io-index" 2128 | checksum = "66c82d03d16a1e591756e978782ce4bc4300f83048b57d44c5600dafa7337019" 2129 | dependencies = [ 2130 | "event-listener 5.3.0", 2131 | "futures-lite 2.3.0", 2132 | "pin-project-lite", 2133 | ] 2134 | 2135 | [[package]] 2136 | name = "syn" 2137 | version = "1.0.109" 2138 | source = "registry+https://github.com/rust-lang/crates.io-index" 2139 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 2140 | dependencies = [ 2141 | "proc-macro2", 2142 | "quote", 2143 | "unicode-ident", 2144 | ] 2145 | 2146 | [[package]] 2147 | name = "syn" 2148 | version = "2.0.60" 2149 | source = "registry+https://github.com/rust-lang/crates.io-index" 2150 | checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" 2151 | dependencies = [ 2152 | "proc-macro2", 2153 | "quote", 2154 | "unicode-ident", 2155 | ] 2156 | 2157 | [[package]] 2158 | name = "sync_wrapper" 2159 | version = "0.1.2" 2160 | source = "registry+https://github.com/rust-lang/crates.io-index" 2161 | checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" 2162 | 2163 | [[package]] 2164 | name = "sync_wrapper" 2165 | version = "1.0.1" 2166 | source = "registry+https://github.com/rust-lang/crates.io-index" 2167 | checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" 2168 | 2169 | [[package]] 2170 | name = "tap" 2171 | version = "1.0.1" 2172 | source = "registry+https://github.com/rust-lang/crates.io-index" 2173 | checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" 2174 | 2175 | [[package]] 2176 | name = "thiserror" 2177 | version = "1.0.59" 2178 | source = "registry+https://github.com/rust-lang/crates.io-index" 2179 | checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" 2180 | dependencies = [ 2181 | "thiserror-impl", 2182 | ] 2183 | 2184 | [[package]] 2185 | name = "thiserror-impl" 2186 | version = "1.0.59" 2187 | source = "registry+https://github.com/rust-lang/crates.io-index" 2188 | checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" 2189 | dependencies = [ 2190 | "proc-macro2", 2191 | "quote", 2192 | "syn 2.0.60", 2193 | ] 2194 | 2195 | [[package]] 2196 | name = "tinytemplate" 2197 | version = "1.2.1" 2198 | source = "registry+https://github.com/rust-lang/crates.io-index" 2199 | checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" 2200 | dependencies = [ 2201 | "serde", 2202 | "serde_json", 2203 | ] 2204 | 2205 | [[package]] 2206 | name = "tinyvec" 2207 | version = "1.6.0" 2208 | source = "registry+https://github.com/rust-lang/crates.io-index" 2209 | checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" 2210 | dependencies = [ 2211 | "tinyvec_macros", 2212 | ] 2213 | 2214 | [[package]] 2215 | name = "tinyvec_macros" 2216 | version = "0.1.1" 2217 | source = "registry+https://github.com/rust-lang/crates.io-index" 2218 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" 2219 | 2220 | [[package]] 2221 | name = "tokio" 2222 | version = "1.31.0" 2223 | source = "registry+https://github.com/rust-lang/crates.io-index" 2224 | checksum = "40de3a2ba249dcb097e01be5e67a5ff53cf250397715a071a81543e8a832a920" 2225 | dependencies = [ 2226 | "backtrace", 2227 | "bytes", 2228 | "libc", 2229 | "mio", 2230 | "pin-project-lite", 2231 | "socket2 0.5.3", 2232 | "tokio-macros", 2233 | "windows-sys 0.48.0", 2234 | ] 2235 | 2236 | [[package]] 2237 | name = "tokio-macros" 2238 | version = "2.1.0" 2239 | source = "registry+https://github.com/rust-lang/crates.io-index" 2240 | checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" 2241 | dependencies = [ 2242 | "proc-macro2", 2243 | "quote", 2244 | "syn 2.0.60", 2245 | ] 2246 | 2247 | [[package]] 2248 | name = "tokio-tungstenite" 2249 | version = "0.21.0" 2250 | source = "registry+https://github.com/rust-lang/crates.io-index" 2251 | checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" 2252 | dependencies = [ 2253 | "futures-util", 2254 | "log", 2255 | "tokio", 2256 | "tungstenite", 2257 | ] 2258 | 2259 | [[package]] 2260 | name = "tower" 2261 | version = "0.4.13" 2262 | source = "registry+https://github.com/rust-lang/crates.io-index" 2263 | checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" 2264 | dependencies = [ 2265 | "futures-core", 2266 | "futures-util", 2267 | "pin-project", 2268 | "pin-project-lite", 2269 | "tokio", 2270 | "tower-layer", 2271 | "tower-service", 2272 | ] 2273 | 2274 | [[package]] 2275 | name = "tower-http" 2276 | version = "0.5.2" 2277 | source = "registry+https://github.com/rust-lang/crates.io-index" 2278 | checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" 2279 | dependencies = [ 2280 | "bitflags 2.4.0", 2281 | "bytes", 2282 | "http", 2283 | "http-body", 2284 | "http-body-util", 2285 | "pin-project-lite", 2286 | "tower-layer", 2287 | "tower-service", 2288 | "tracing", 2289 | ] 2290 | 2291 | [[package]] 2292 | name = "tower-layer" 2293 | version = "0.3.2" 2294 | source = "registry+https://github.com/rust-lang/crates.io-index" 2295 | checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" 2296 | 2297 | [[package]] 2298 | name = "tower-service" 2299 | version = "0.3.2" 2300 | source = "registry+https://github.com/rust-lang/crates.io-index" 2301 | checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" 2302 | 2303 | [[package]] 2304 | name = "tracing" 2305 | version = "0.1.37" 2306 | source = "registry+https://github.com/rust-lang/crates.io-index" 2307 | checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" 2308 | dependencies = [ 2309 | "cfg-if", 2310 | "pin-project-lite", 2311 | "tracing-core", 2312 | ] 2313 | 2314 | [[package]] 2315 | name = "tracing-core" 2316 | version = "0.1.31" 2317 | source = "registry+https://github.com/rust-lang/crates.io-index" 2318 | checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" 2319 | 2320 | [[package]] 2321 | name = "trillium" 2322 | version = "0.2.19" 2323 | source = "registry+https://github.com/rust-lang/crates.io-index" 2324 | checksum = "01c7180eac36666f14504c5a8606d027154a8e3a4704bd0acc69a13f56c202b6" 2325 | dependencies = [ 2326 | "async-trait", 2327 | "log", 2328 | "trillium-http", 2329 | ] 2330 | 2331 | [[package]] 2332 | name = "trillium-http" 2333 | version = "0.3.16" 2334 | source = "registry+https://github.com/rust-lang/crates.io-index" 2335 | checksum = "a18d82a9418c6fc1a872bc163fffd49320229edf783cbbb1aa62ba49f517cfad" 2336 | dependencies = [ 2337 | "encoding_rs", 2338 | "futures-lite 2.3.0", 2339 | "hashbrown 0.14.3", 2340 | "httparse", 2341 | "httpdate", 2342 | "log", 2343 | "memchr", 2344 | "mime", 2345 | "smallvec", 2346 | "smartcow", 2347 | "smartstring", 2348 | "stopper", 2349 | "thiserror", 2350 | "trillium-macros", 2351 | ] 2352 | 2353 | [[package]] 2354 | name = "trillium-macros" 2355 | version = "0.0.6" 2356 | source = "registry+https://github.com/rust-lang/crates.io-index" 2357 | checksum = "916e37646d33632b88ca02d4b8c4e2e6376f2a89d9888de71b7d82c150ed1f6c" 2358 | dependencies = [ 2359 | "proc-macro2", 2360 | "quote", 2361 | "syn 2.0.60", 2362 | ] 2363 | 2364 | [[package]] 2365 | name = "trillium-router" 2366 | version = "0.4.1" 2367 | source = "registry+https://github.com/rust-lang/crates.io-index" 2368 | checksum = "6a7aed20d63101d7dcd165fd047141423009a7f4ccfc75db5b875312d8127dbe" 2369 | dependencies = [ 2370 | "log", 2371 | "routefinder", 2372 | "trillium", 2373 | ] 2374 | 2375 | [[package]] 2376 | name = "trillium-server-common" 2377 | version = "0.5.2" 2378 | source = "registry+https://github.com/rust-lang/crates.io-index" 2379 | checksum = "a96faa60ceaf4b575886eb7d2ad3df4371acf67e0a4489585cccd4ff18966103" 2380 | dependencies = [ 2381 | "async-trait", 2382 | "async_cell", 2383 | "event-listener 4.0.3", 2384 | "futures-lite 2.3.0", 2385 | "log", 2386 | "pin-project-lite", 2387 | "rlimit", 2388 | "trillium", 2389 | "trillium-http", 2390 | "url", 2391 | ] 2392 | 2393 | [[package]] 2394 | name = "trillium-smol" 2395 | version = "0.4.1" 2396 | source = "registry+https://github.com/rust-lang/crates.io-index" 2397 | checksum = "3a1c196273bd6e41705150834f5771699ad9c2e38ce317aecd3f6e0ec4c2b2e6" 2398 | dependencies = [ 2399 | "async-global-executor", 2400 | "async-io 2.3.2", 2401 | "async-net", 2402 | "futures-lite 2.3.0", 2403 | "log", 2404 | "signal-hook", 2405 | "signal-hook-async-std", 2406 | "trillium", 2407 | "trillium-http", 2408 | "trillium-macros", 2409 | "trillium-server-common", 2410 | ] 2411 | 2412 | [[package]] 2413 | name = "trillium-websockets" 2414 | version = "0.6.5" 2415 | source = "registry+https://github.com/rust-lang/crates.io-index" 2416 | checksum = "659ff2c93eac21312e159df0e8d2cc90480fdb30c83f9bf2f553190c0885d327" 2417 | dependencies = [ 2418 | "async-tungstenite", 2419 | "base64 0.22.0", 2420 | "fastrand 2.0.2", 2421 | "futures-lite 2.3.0", 2422 | "futures-util", 2423 | "log", 2424 | "pin-project-lite", 2425 | "sha-1", 2426 | "stopper", 2427 | "thiserror", 2428 | "trillium", 2429 | "trillium-http", 2430 | ] 2431 | 2432 | [[package]] 2433 | name = "tungstenite" 2434 | version = "0.21.0" 2435 | source = "registry+https://github.com/rust-lang/crates.io-index" 2436 | checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" 2437 | dependencies = [ 2438 | "byteorder", 2439 | "bytes", 2440 | "data-encoding", 2441 | "http", 2442 | "httparse", 2443 | "log", 2444 | "rand", 2445 | "sha1", 2446 | "thiserror", 2447 | "url", 2448 | "utf-8", 2449 | ] 2450 | 2451 | [[package]] 2452 | name = "typenum" 2453 | version = "1.16.0" 2454 | source = "registry+https://github.com/rust-lang/crates.io-index" 2455 | checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" 2456 | 2457 | [[package]] 2458 | name = "unicode-bidi" 2459 | version = "0.3.13" 2460 | source = "registry+https://github.com/rust-lang/crates.io-index" 2461 | checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" 2462 | 2463 | [[package]] 2464 | name = "unicode-ident" 2465 | version = "1.0.11" 2466 | source = "registry+https://github.com/rust-lang/crates.io-index" 2467 | checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" 2468 | 2469 | [[package]] 2470 | name = "unicode-normalization" 2471 | version = "0.1.22" 2472 | source = "registry+https://github.com/rust-lang/crates.io-index" 2473 | checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" 2474 | dependencies = [ 2475 | "tinyvec", 2476 | ] 2477 | 2478 | [[package]] 2479 | name = "url" 2480 | version = "2.5.0" 2481 | source = "registry+https://github.com/rust-lang/crates.io-index" 2482 | checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" 2483 | dependencies = [ 2484 | "form_urlencoded", 2485 | "idna", 2486 | "percent-encoding", 2487 | ] 2488 | 2489 | [[package]] 2490 | name = "utf-8" 2491 | version = "0.7.6" 2492 | source = "registry+https://github.com/rust-lang/crates.io-index" 2493 | checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" 2494 | 2495 | [[package]] 2496 | name = "uuid" 2497 | version = "1.4.1" 2498 | source = "registry+https://github.com/rust-lang/crates.io-index" 2499 | checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" 2500 | 2501 | [[package]] 2502 | name = "version_check" 2503 | version = "0.9.4" 2504 | source = "registry+https://github.com/rust-lang/crates.io-index" 2505 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 2506 | 2507 | [[package]] 2508 | name = "vlq" 2509 | version = "0.5.1" 2510 | source = "registry+https://github.com/rust-lang/crates.io-index" 2511 | checksum = "65dd7eed29412da847b0f78bcec0ac98588165988a8cfe41d4ea1d429f8ccfff" 2512 | 2513 | [[package]] 2514 | name = "waker-fn" 2515 | version = "1.1.0" 2516 | source = "registry+https://github.com/rust-lang/crates.io-index" 2517 | checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" 2518 | 2519 | [[package]] 2520 | name = "walkdir" 2521 | version = "2.3.3" 2522 | source = "registry+https://github.com/rust-lang/crates.io-index" 2523 | checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" 2524 | dependencies = [ 2525 | "same-file", 2526 | "winapi-util", 2527 | ] 2528 | 2529 | [[package]] 2530 | name = "wasi" 2531 | version = "0.11.0+wasi-snapshot-preview1" 2532 | source = "registry+https://github.com/rust-lang/crates.io-index" 2533 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 2534 | 2535 | [[package]] 2536 | name = "wasm-bindgen" 2537 | version = "0.2.87" 2538 | source = "registry+https://github.com/rust-lang/crates.io-index" 2539 | checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" 2540 | dependencies = [ 2541 | "cfg-if", 2542 | "wasm-bindgen-macro", 2543 | ] 2544 | 2545 | [[package]] 2546 | name = "wasm-bindgen-backend" 2547 | version = "0.2.87" 2548 | source = "registry+https://github.com/rust-lang/crates.io-index" 2549 | checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" 2550 | dependencies = [ 2551 | "bumpalo", 2552 | "log", 2553 | "once_cell", 2554 | "proc-macro2", 2555 | "quote", 2556 | "syn 2.0.60", 2557 | "wasm-bindgen-shared", 2558 | ] 2559 | 2560 | [[package]] 2561 | name = "wasm-bindgen-macro" 2562 | version = "0.2.87" 2563 | source = "registry+https://github.com/rust-lang/crates.io-index" 2564 | checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" 2565 | dependencies = [ 2566 | "quote", 2567 | "wasm-bindgen-macro-support", 2568 | ] 2569 | 2570 | [[package]] 2571 | name = "wasm-bindgen-macro-support" 2572 | version = "0.2.87" 2573 | source = "registry+https://github.com/rust-lang/crates.io-index" 2574 | checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" 2575 | dependencies = [ 2576 | "proc-macro2", 2577 | "quote", 2578 | "syn 2.0.60", 2579 | "wasm-bindgen-backend", 2580 | "wasm-bindgen-shared", 2581 | ] 2582 | 2583 | [[package]] 2584 | name = "wasm-bindgen-shared" 2585 | version = "0.2.87" 2586 | source = "registry+https://github.com/rust-lang/crates.io-index" 2587 | checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" 2588 | 2589 | [[package]] 2590 | name = "web-sys" 2591 | version = "0.3.64" 2592 | source = "registry+https://github.com/rust-lang/crates.io-index" 2593 | checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" 2594 | dependencies = [ 2595 | "js-sys", 2596 | "wasm-bindgen", 2597 | ] 2598 | 2599 | [[package]] 2600 | name = "winapi" 2601 | version = "0.3.9" 2602 | source = "registry+https://github.com/rust-lang/crates.io-index" 2603 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 2604 | dependencies = [ 2605 | "winapi-i686-pc-windows-gnu", 2606 | "winapi-x86_64-pc-windows-gnu", 2607 | ] 2608 | 2609 | [[package]] 2610 | name = "winapi-i686-pc-windows-gnu" 2611 | version = "0.4.0" 2612 | source = "registry+https://github.com/rust-lang/crates.io-index" 2613 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 2614 | 2615 | [[package]] 2616 | name = "winapi-util" 2617 | version = "0.1.5" 2618 | source = "registry+https://github.com/rust-lang/crates.io-index" 2619 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 2620 | dependencies = [ 2621 | "winapi", 2622 | ] 2623 | 2624 | [[package]] 2625 | name = "winapi-x86_64-pc-windows-gnu" 2626 | version = "0.4.0" 2627 | source = "registry+https://github.com/rust-lang/crates.io-index" 2628 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 2629 | 2630 | [[package]] 2631 | name = "windows-sys" 2632 | version = "0.45.0" 2633 | source = "registry+https://github.com/rust-lang/crates.io-index" 2634 | checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" 2635 | dependencies = [ 2636 | "windows-targets 0.42.2", 2637 | ] 2638 | 2639 | [[package]] 2640 | name = "windows-sys" 2641 | version = "0.48.0" 2642 | source = "registry+https://github.com/rust-lang/crates.io-index" 2643 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 2644 | dependencies = [ 2645 | "windows-targets 0.48.2", 2646 | ] 2647 | 2648 | [[package]] 2649 | name = "windows-sys" 2650 | version = "0.52.0" 2651 | source = "registry+https://github.com/rust-lang/crates.io-index" 2652 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 2653 | dependencies = [ 2654 | "windows-targets 0.52.5", 2655 | ] 2656 | 2657 | [[package]] 2658 | name = "windows-targets" 2659 | version = "0.42.2" 2660 | source = "registry+https://github.com/rust-lang/crates.io-index" 2661 | checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" 2662 | dependencies = [ 2663 | "windows_aarch64_gnullvm 0.42.2", 2664 | "windows_aarch64_msvc 0.42.2", 2665 | "windows_i686_gnu 0.42.2", 2666 | "windows_i686_msvc 0.42.2", 2667 | "windows_x86_64_gnu 0.42.2", 2668 | "windows_x86_64_gnullvm 0.42.2", 2669 | "windows_x86_64_msvc 0.42.2", 2670 | ] 2671 | 2672 | [[package]] 2673 | name = "windows-targets" 2674 | version = "0.48.2" 2675 | source = "registry+https://github.com/rust-lang/crates.io-index" 2676 | checksum = "d1eeca1c172a285ee6c2c84c341ccea837e7c01b12fbb2d0fe3c9e550ce49ec8" 2677 | dependencies = [ 2678 | "windows_aarch64_gnullvm 0.48.2", 2679 | "windows_aarch64_msvc 0.48.2", 2680 | "windows_i686_gnu 0.48.2", 2681 | "windows_i686_msvc 0.48.2", 2682 | "windows_x86_64_gnu 0.48.2", 2683 | "windows_x86_64_gnullvm 0.48.2", 2684 | "windows_x86_64_msvc 0.48.2", 2685 | ] 2686 | 2687 | [[package]] 2688 | name = "windows-targets" 2689 | version = "0.52.5" 2690 | source = "registry+https://github.com/rust-lang/crates.io-index" 2691 | checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" 2692 | dependencies = [ 2693 | "windows_aarch64_gnullvm 0.52.5", 2694 | "windows_aarch64_msvc 0.52.5", 2695 | "windows_i686_gnu 0.52.5", 2696 | "windows_i686_gnullvm", 2697 | "windows_i686_msvc 0.52.5", 2698 | "windows_x86_64_gnu 0.52.5", 2699 | "windows_x86_64_gnullvm 0.52.5", 2700 | "windows_x86_64_msvc 0.52.5", 2701 | ] 2702 | 2703 | [[package]] 2704 | name = "windows_aarch64_gnullvm" 2705 | version = "0.42.2" 2706 | source = "registry+https://github.com/rust-lang/crates.io-index" 2707 | checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" 2708 | 2709 | [[package]] 2710 | name = "windows_aarch64_gnullvm" 2711 | version = "0.48.2" 2712 | source = "registry+https://github.com/rust-lang/crates.io-index" 2713 | checksum = "b10d0c968ba7f6166195e13d593af609ec2e3d24f916f081690695cf5eaffb2f" 2714 | 2715 | [[package]] 2716 | name = "windows_aarch64_gnullvm" 2717 | version = "0.52.5" 2718 | source = "registry+https://github.com/rust-lang/crates.io-index" 2719 | checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" 2720 | 2721 | [[package]] 2722 | name = "windows_aarch64_msvc" 2723 | version = "0.42.2" 2724 | source = "registry+https://github.com/rust-lang/crates.io-index" 2725 | checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" 2726 | 2727 | [[package]] 2728 | name = "windows_aarch64_msvc" 2729 | version = "0.48.2" 2730 | source = "registry+https://github.com/rust-lang/crates.io-index" 2731 | checksum = "571d8d4e62f26d4932099a9efe89660e8bd5087775a2ab5cdd8b747b811f1058" 2732 | 2733 | [[package]] 2734 | name = "windows_aarch64_msvc" 2735 | version = "0.52.5" 2736 | source = "registry+https://github.com/rust-lang/crates.io-index" 2737 | checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" 2738 | 2739 | [[package]] 2740 | name = "windows_i686_gnu" 2741 | version = "0.42.2" 2742 | source = "registry+https://github.com/rust-lang/crates.io-index" 2743 | checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" 2744 | 2745 | [[package]] 2746 | name = "windows_i686_gnu" 2747 | version = "0.48.2" 2748 | source = "registry+https://github.com/rust-lang/crates.io-index" 2749 | checksum = "2229ad223e178db5fbbc8bd8d3835e51e566b8474bfca58d2e6150c48bb723cd" 2750 | 2751 | [[package]] 2752 | name = "windows_i686_gnu" 2753 | version = "0.52.5" 2754 | source = "registry+https://github.com/rust-lang/crates.io-index" 2755 | checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" 2756 | 2757 | [[package]] 2758 | name = "windows_i686_gnullvm" 2759 | version = "0.52.5" 2760 | source = "registry+https://github.com/rust-lang/crates.io-index" 2761 | checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" 2762 | 2763 | [[package]] 2764 | name = "windows_i686_msvc" 2765 | version = "0.42.2" 2766 | source = "registry+https://github.com/rust-lang/crates.io-index" 2767 | checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" 2768 | 2769 | [[package]] 2770 | name = "windows_i686_msvc" 2771 | version = "0.48.2" 2772 | source = "registry+https://github.com/rust-lang/crates.io-index" 2773 | checksum = "600956e2d840c194eedfc5d18f8242bc2e17c7775b6684488af3a9fff6fe3287" 2774 | 2775 | [[package]] 2776 | name = "windows_i686_msvc" 2777 | version = "0.52.5" 2778 | source = "registry+https://github.com/rust-lang/crates.io-index" 2779 | checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" 2780 | 2781 | [[package]] 2782 | name = "windows_x86_64_gnu" 2783 | version = "0.42.2" 2784 | source = "registry+https://github.com/rust-lang/crates.io-index" 2785 | checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" 2786 | 2787 | [[package]] 2788 | name = "windows_x86_64_gnu" 2789 | version = "0.48.2" 2790 | source = "registry+https://github.com/rust-lang/crates.io-index" 2791 | checksum = "ea99ff3f8b49fb7a8e0d305e5aec485bd068c2ba691b6e277d29eaeac945868a" 2792 | 2793 | [[package]] 2794 | name = "windows_x86_64_gnu" 2795 | version = "0.52.5" 2796 | source = "registry+https://github.com/rust-lang/crates.io-index" 2797 | checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" 2798 | 2799 | [[package]] 2800 | name = "windows_x86_64_gnullvm" 2801 | version = "0.42.2" 2802 | source = "registry+https://github.com/rust-lang/crates.io-index" 2803 | checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" 2804 | 2805 | [[package]] 2806 | name = "windows_x86_64_gnullvm" 2807 | version = "0.48.2" 2808 | source = "registry+https://github.com/rust-lang/crates.io-index" 2809 | checksum = "8f1a05a1ece9a7a0d5a7ccf30ba2c33e3a61a30e042ffd247567d1de1d94120d" 2810 | 2811 | [[package]] 2812 | name = "windows_x86_64_gnullvm" 2813 | version = "0.52.5" 2814 | source = "registry+https://github.com/rust-lang/crates.io-index" 2815 | checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" 2816 | 2817 | [[package]] 2818 | name = "windows_x86_64_msvc" 2819 | version = "0.42.2" 2820 | source = "registry+https://github.com/rust-lang/crates.io-index" 2821 | checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" 2822 | 2823 | [[package]] 2824 | name = "windows_x86_64_msvc" 2825 | version = "0.48.2" 2826 | source = "registry+https://github.com/rust-lang/crates.io-index" 2827 | checksum = "d419259aba16b663966e29e6d7c6ecfa0bb8425818bb96f6f1f3c3eb71a6e7b9" 2828 | 2829 | [[package]] 2830 | name = "windows_x86_64_msvc" 2831 | version = "0.52.5" 2832 | source = "registry+https://github.com/rust-lang/crates.io-index" 2833 | checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" 2834 | 2835 | [[package]] 2836 | name = "wyz" 2837 | version = "0.5.1" 2838 | source = "registry+https://github.com/rust-lang/crates.io-index" 2839 | checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" 2840 | dependencies = [ 2841 | "tap", 2842 | ] 2843 | 2844 | [[package]] 2845 | name = "zerocopy" 2846 | version = "0.7.32" 2847 | source = "registry+https://github.com/rust-lang/crates.io-index" 2848 | checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" 2849 | dependencies = [ 2850 | "zerocopy-derive", 2851 | ] 2852 | 2853 | [[package]] 2854 | name = "zerocopy-derive" 2855 | version = "0.7.32" 2856 | source = "registry+https://github.com/rust-lang/crates.io-index" 2857 | checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" 2858 | dependencies = [ 2859 | "proc-macro2", 2860 | "quote", 2861 | "syn 2.0.60", 2862 | ] 2863 | --------------------------------------------------------------------------------