diff --git a/BENCHMARK_WEBSITE_REDESIGN.md b/BENCHMARK_WEBSITE_REDESIGN.md new file mode 100644 index 00000000000..8e22d87fd88 --- /dev/null +++ b/BENCHMARK_WEBSITE_REDESIGN.md @@ -0,0 +1,1640 @@ +# Vortex Benchmarks Website: Architecture & Implementation Plan + +This document describes the architecture for a high-performance benchmarks visualization website for Vortex. It serves as both a design specification and implementation guide for humans and AI agents working on this project. + +_This is mostly Claude-written, but it is also the result of quite a lot of prototyping and research on how to make our benchmarks website not absolutely terrible with respect to load times._ + +--- + +## Table of Contents + +1. [Overview & Goals](#overview--goals) +2. [Current State & Problems](#current-state--problems) +3. [Architecture Overview](#architecture-overview) +4. [Data Model & Schema](#data-model--schema) +5. [Server Architecture](#server-architecture) +6. [Client Architecture](#client-architecture) +7. [API Design](#api-design) +8. [Deployment & Infrastructure](#deployment--infrastructure) +9. [Plan of Attack](#plan-of-attack) +10. [Future Considerations](#future-considerations) + +--- + +## Overview & Goals + +### What We're Building + +A benchmarks visualization website (https://bench.vortex.dev/) that displays performance data for the Vortex columnar file format across multiple benchmark suites. The site shows time-series-like charts of benchmark results over git commits, allowing users to track performance regressions and improvements. + +### Goals + +1. **Fast initial load**: Sub-second time to first contentful paint +2. **Interactive charts**: Instant zoom/pan/scroll across entire commit history (up to 5000+ commits) +3. **Real-time updates**: New benchmark results from CI appear within minutes +4. **Maintainability**: Rust-native stack (Leptos) for team familiarity + +### Secondary Goals + +- Reusability: Architected as a library that others can adapt for their benchmarking needs +- SEO optimization: Nice to have, but speed is paramount +- Mobile-first design: Desktop is primary use case, but should work on mobile too +- Public API for benchmark data (internal tooling only) + +--- + +## Current State & Problems + +### Current Architecture + +``` +GitHub Actions (CI) -> JSON files -> S3 bucket -> Client downloads entire dataset +``` + +- Single monolithic JSON file containing all benchmark results (~80MB uncompressed, ~8MB gzipped) +- Separate commits.json for ordering commits by timestamp +- Client downloads everything, then processes in JavaScript +- Data has been manually truncated to ~2000 commits to keep things more manageable (would be ~4500 at this point) + +### Pain Points + +| Problem | Impact | +| ----------------------------------------- | -------------------------------------------------- | +| 8MB gzipped download | 10-15 seconds on fast internet | +| Client-side JSON parsing + join | Additional 10 seconds processing | +| No incremental loading | Must wait for everything before seeing anything | +| Schema changes require JSON restructuring | Difficult to add new targets/benchmarks | +| No server-side computation | Summary statistics computed client-side repeatedly | +| Manual data truncation | Losing historical data to keep site usable | + +### Data Volume + +- ~2000 commits currently (truncated), would be ~4500+ without truncation +- 10+ benchmark groups (TPC-H at multiple scale factors, ClickBench, compression, random access, various micro-benchmarks) + - TPC-H groups: 19 queries each (× multiple scale factors) + - ClickBench: 44 queries + - etc. +- ~200 individual charts across all groups +- Series names vary by group (e.g., "vortex", "parquet", "duckdb:vortex", "datafusion:parquet") + +--- + +## Architecture Overview + +### High-Level Design + +``` +┌─────────────────┐ ┌─────────────────────────────────────────────┐ +│ GitHub Actions │ POST │ AWS Infrastructure │ +│ (benchmark CI) │ ───────► │ │ +└─────────────────┘ │ ┌─────────────────────────────────────┐ │ + │ │ CloudFront (CDN) │ │ + Users ─────────────►│ │ - Caches HTML/WASM/static assets │ │ + (global) │ │ - Caches API responses (60s TTL) │ │ + │ └──────────────┬──────────────────────┘ │ + │ │ │ + │ ▼ │ + │ ┌─────────────────────────────────────┐ │ + │ │ EC2 / ECS (Leptos) │ │ + │ │ │ │ + │ │ ┌───────────────────────────────┐ │ │ + │ │ │ DuckDB (embedded) │ │ │ + │ │ │ │ │ │ + │ │ │ benchmarks.duckdb │ │ │ + │ │ │ - commits table │ │ │ + │ │ │ - compression table │ │ │ + │ │ │ - tpch_sf1 table │ │ │ + │ │ │ - clickbench table │ │ │ + │ │ │ - random_access table │ │ │ + │ │ │ - etc │ │ │ + │ │ └───────────────────────────────┘ │ │ + │ └─────────────────────────────────────┘ │ + │ │ │ + │ ▼ │ + │ ┌─────────────────────────────────────┐ │ + │ │ S3 Bucket │ │ + │ │ - DuckDB file backups (hourly) │ │ + │ │ - Disaster recovery │ │ + │ └─────────────────────────────────────┘ │ + └─────────────────────────────────────────────┘ +``` + +## Key Architectural Decisions + +### Decision 1: Server-Side DuckDB + +**Choice**: Embedded DuckDB on server with native storage. + +**Alternatives Considered**: + +- Client-side DuckDB-WASM: Adds complexity, requires shipping data to client +- Static JSON files on CDN: Current approach, proven to be too slow +- PostgreSQL/MySQL: Overkill for this workload + +**Rationale**: + +- DuckDB is extremely fast for analytical queries (~5ms for typical chart query) +- Single-file database is simple to deploy, backup, and manage +- Schema evolution is trivial (`ALTER TABLE ADD COLUMN`) +- Keep in mind future library extraction: storage should be swappable + +### Decision 2: Leptos with Islands Architecture + +**Choice**: Leptos SSR with `#[island]` components for interactive charts + +**Alternatives Considered**: + +- Dioxus: Better cross-platform, but weaker SSR/streaming support +- Yew: No streaming SSR, less active development +- Next.js/React: Team prefers Rust, would require JS expertise + +**Rationale**: + +- SSR means fast initial paint (HTML renders before WASM loads) +- Islands keep WASM bundle small (only interactive parts ship as WASM) +- Fine-grained reactivity makes chart updates efficient +- Team already knows Rust + +### Decision 3: Progressive Data Loading + +**Choice**: SSR with most recent N commits (configurable, default ~50), lazy-load full history on demand per chart + +**Alternatives Considered**: + +- Load all data upfront: 20-30MB initial payload for large groups +- Paginated loading: Poor UX for time-series charts +- Virtual scrolling of data: Complex, doesn't match use case + +**Rationale**: + +- Initial HTML is small (~500KB for 44 charts × 50 commits) +- Users see useful content immediately +- Full history loads only when user explicitly needs it +- Each chart loads independently (don't pay for charts you don't view) +- N is configurable (25-100 range, tune based on testing) + +### Decision 4: No Materialized Views + +**Choice**: Direct queries against DuckDB tables with indexes + +**Alternatives Considered**: + +- 1000+ materialized views (one per chart): Complexity, refresh overhead +- Pre-computed JSON cache: Loses benefits of SQL, cache invalidation issues + +**Rationale**: + +- Data volume is small (~100MB total across all groups) +- DuckDB queries complete in <10ms with proper indexes +- Materialized views add complexity without meaningful performance gain +- Easier to add new charts/series without maintaining view definitions + +--- + +## Data Model & Schema + +### Overview + +Each benchmark group is stored as a separate table. All tables share a common `commits` table for ordering. + +**Important**: All benchmark measurements are stored as **unsigned 64-bit integers** (typically nanoseconds). Conversion to human-readable units (seconds, milliseconds, MB/s) happens at display time. This preserves precision and simplifies storage. + +**Sparse Data**: Not all commits have benchmark data. The `commits` table contains all commits, but benchmark tables only have rows for commits where benchmarks actually ran. Queries use LEFT JOIN to include all commits, with NULL values for missing benchmark data. + +### Commits Table + +```sql +-- commits table +-- Stores git commit metadata for ordering and display +CREATE TABLE commits ( + commit_hash VARCHAR PRIMARY KEY, + timestamp TIMESTAMP NOT NULL, + message VARCHAR, + author VARCHAR +); + +-- Index for efficient "most recent N commits" queries +CREATE INDEX idx_commits_timestamp ON commits(timestamp DESC); +``` + +### Benchmark Group Tables + +Each benchmark group follows one of two patterns. Series columns are named dynamically based on the targets being compared (e.g., "vortex", "parquet", "duckdb_vortex", "datafusion_parquet"). + +**Note on series naming**: Series names may be compound (e.g., "duckdb:vortex" means "DuckDB engine reading Vortex format"). In SQL column names, colons are replaced with underscores. + +#### Pattern A: Single Chart (e.g., compression, random_access) + +```sql +-- compression table +-- No chart dimension - just one chart per group +-- All values are u64 (nanoseconds, bytes, etc.) +CREATE TABLE compression ( + commit_hash VARCHAR NOT NULL REFERENCES commits(commit_hash), + -- Series columns - names vary by group + -- Stored as UBIGINT (u64), converted to display units in UI + vortex_throughput_ns UBIGINT, -- nanoseconds per operation + parquet_throughput_ns UBIGINT, + lance_throughput_ns UBIGINT, + vortex_compressed_bytes UBIGINT, -- bytes + parquet_compressed_bytes UBIGINT, + lance_compressed_bytes UBIGINT, + PRIMARY KEY (commit_hash) +); +``` + +#### Pattern B: Multiple Charts (e.g., TPC-H, ClickBench) + +```sql +-- tpch_sf1 table +-- Multiple charts (queries), each showing multiple series (targets) +-- Series names can be compound: "duckdb_vortex" = DuckDB engine + Vortex format +CREATE TABLE tpch_sf1 ( + commit_hash VARCHAR NOT NULL REFERENCES commits(commit_hash), + chart VARCHAR NOT NULL, -- 'q1', 'q2', ..., 'q19' + -- Series columns (nullable for sparse data) + -- All times stored as nanoseconds (u64) + vortex_ns UBIGINT, -- Vortex native reader + parquet_ns UBIGINT, -- Parquet native reader + duckdb_vortex_ns UBIGINT, -- DuckDB reading Vortex + duckdb_parquet_ns UBIGINT, -- DuckDB reading Parquet + datafusion_vortex_ns UBIGINT, + datafusion_parquet_ns UBIGINT, + lance_ns UBIGINT, + PRIMARY KEY (commit_hash, chart) +); + +-- Index for filtering by chart +CREATE INDEX idx_tpch_sf1_chart ON tpch_sf1(chart); +``` + +```sql +-- clickbench table +CREATE TABLE clickbench ( + commit_hash VARCHAR NOT NULL REFERENCES commits(commit_hash), + chart VARCHAR NOT NULL, -- 'q0', 'q1', ..., 'q43' + vortex_ns UBIGINT, + parquet_ns UBIGINT, + duckdb_vortex_ns UBIGINT, + duckdb_parquet_ns UBIGINT, + PRIMARY KEY (commit_hash, chart) +); + +CREATE INDEX idx_clickbench_chart ON clickbench(chart); +``` + +### Schema Evolution + +Adding a new target (series) to an existing benchmark group: + +```sql +ALTER TABLE tpch_sf1 ADD COLUMN arrow_ns UBIGINT; +``` + +- New column is nullable by default (existing rows have NULL) +- No data migration required +- UI picks up new series from configuration + +Adding a new chart to an existing group: + +```sql +INSERT INTO clickbench (commit_hash, chart, vortex_ns, parquet_ns) +VALUES ('abc123', 'q44', 150000000, 200000000); +``` + +Adding a new benchmark group: + +1. Create table with appropriate schema +2. Add group metadata to configuration (see [Group Configuration](#group-configuration)) +3. CI starts posting results to new endpoint + +### Group Configuration + +Store benchmark group metadata in a configuration file or table: + +```rust +// benchmark_groups.rs +pub struct BenchmarkGroup { + pub id: &'static str, // "tpch_sf1" + pub display_name: &'static str, // "TPC-H Scale Factor 1" + pub chart_column: Option<&'static str>, // Some("chart") or None + pub series: Vec, + pub summary_type: SummaryType, // How to compute summary stats +} + +pub struct SeriesConfig { + pub column: &'static str, // "duckdb_vortex_ns" (SQL column name) + pub display_name: &'static str, // "DuckDB + Vortex" (human readable) + pub color: &'static str, // "#3b82f6" + pub unit: MeasurementUnit, // How to convert/display values +} + +/// All benchmark data is stored as u64. This enum defines how to display it. +pub enum MeasurementUnit { + Nanoseconds, // Display as seconds, ms, or μs depending on magnitude + Bytes, // Display as B, KB, MB, GB + BytesPerSecond, // Throughput: display as MB/s, GB/s + Ratio, // Compression ratio: value / 1_000_000 (stored as ratio * 1e6) + Count, // Raw count, no conversion +} + +impl MeasurementUnit { + /// Convert u64 stored value to f64 display value with appropriate unit + pub fn format(&self, value: u64) -> (f64, &'static str) { + match self { + MeasurementUnit::Nanoseconds => { + let ns = value as f64; + if ns >= 1e9 { (ns / 1e9, "s") } + else if ns >= 1e6 { (ns / 1e6, "ms") } + else if ns >= 1e3 { (ns / 1e3, "μs") } + else { (ns, "ns") } + } + MeasurementUnit::Bytes => { + let b = value as f64; + if b >= 1e9 { (b / 1e9, "GB") } + else if b >= 1e6 { (b / 1e6, "MB") } + else if b >= 1e3 { (b / 1e3, "KB") } + else { (b, "B") } + } + // ... etc + } + } +} + +pub enum SummaryType { + GeometricMean, // For TPC-H, ClickBench (ratios/times) + ArithmeticMean, // For throughput benchmarks + Custom(fn(&[u64]) -> f64), +} +``` + +--- + +## Server Architecture + +### Technology Stack + +- **Framework**: Leptos 0.8+ with Axum backend +- **Database**: DuckDB (embedded) +- **Runtime**: Tokio async runtime + +### Project Structure + +``` +bench-website/ +├── Cargo.toml +├── src/ +│ ├── main.rs # Entry point, Axum router setup +│ ├── lib.rs # Leptos app root +│ ├── db/ +│ │ ├── mod.rs +│ │ ├── connection.rs # DuckDB connection pool +│ │ ├── queries.rs # SQL query functions +│ │ └── models.rs # Data structures +│ ├── api/ +│ │ ├── mod.rs +│ │ ├── ingest.rs # POST endpoint for CI +│ │ └── charts.rs # Server functions for chart data +│ ├── components/ +│ │ ├── mod.rs +│ │ ├── app.rs # Root app component +│ │ ├── layout.rs # Navigation, layout +│ │ ├── group_page.rs # Benchmark group page +│ │ ├── chart.rs # Interactive chart island +│ │ └── summary.rs # Summary statistics component +│ └── config/ +│ ├── mod.rs +│ └── groups.rs # Benchmark group definitions +├── style/ +│ └── main.css +└── data/ # DuckDB database (gitignored, populated at runtime) + └── benchmarks.duckdb +``` + +### DuckDB Connection Management + +```rust +// src/db/connection.rs +use duckdb::{Connection, Result}; +use std::sync::Arc; + +/// DuckDB connection wrapper +/// +/// DuckDB supports concurrent reads AND writes from the same process +/// (MVCC handles isolation). We use Arc to share the connection across +/// async tasks. DuckDB's internal locking handles thread safety. +pub struct DbPool { + conn: Arc, +} + +impl DbPool { + pub fn new(config: &StorageConfig) -> Result { + let conn = Connection::open(&config.database_path)?; + + // Create tables if they don't exist + Self::init_schema(&conn)?; + + Ok(Self { + conn: Arc::new(conn), + }) + } + + fn init_schema(conn: &Connection) -> Result<()> { + conn.execute_batch(r#" + CREATE TABLE IF NOT EXISTS commits ( + commit_hash VARCHAR PRIMARY KEY, + timestamp TIMESTAMP NOT NULL, + message VARCHAR, + author VARCHAR + ); + CREATE INDEX IF NOT EXISTS idx_commits_timestamp + ON commits(timestamp DESC); + "#)?; + Ok(()) + } + + /// Execute a query (DuckDB handles concurrent access internally) + pub fn query(&self, f: F) -> Result + where + F: FnOnce(&Connection) -> Result, + { + f(&self.conn) + } +} + +/// Configuration for storage backend (supports library reuse) +pub struct StorageConfig { + pub database_path: String, // ":memory:" or file path +} +``` + +### Ingest Endpoint + +```rust +// src/api/ingest.rs +use axum::{extract::State, http::StatusCode, Json}; +use serde::Deserialize; + +#[derive(Deserialize)] +pub struct IngestRequest { + pub group: String, // "tpch_sf1", "clickbench", etc. + pub commit_hash: String, // git commit SHA + pub commit_timestamp: i64, // Unix timestamp (seconds) + pub commit_message: Option, + pub commit_author: Option, + pub chart: Option, // None for single-chart groups, Some("q1") for multi-chart + pub results: HashMap, // series_name -> value (always u64) +} + +/// POST /api/ingest +/// +/// Called by GitHub Actions after each benchmark run. +/// DuckDB handles concurrent writes via MVCC. +pub async fn ingest_benchmark( + State(db): State, + Json(req): Json, +) -> Result { + // Verify CI token (from header) + // ... token verification ... + + // Upsert commit metadata + db.query(|conn| { + conn.execute( + r#"INSERT INTO commits (commit_hash, timestamp, message, author) + VALUES (?, to_timestamp(?), ?, ?) + ON CONFLICT (commit_hash) DO NOTHING"#, + params![ + &req.commit_hash, + req.commit_timestamp, + &req.commit_message, + &req.commit_author, + ], + ) + }).map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?; + + // Build dynamic INSERT for benchmark results + let columns: Vec<_> = req.results.keys().map(|s| s.as_str()).collect(); + let placeholders: Vec<_> = columns.iter().map(|_| "?").collect(); + + let sql = if let Some(chart) = &req.chart { + format!( + r#"INSERT INTO {group} (commit_hash, chart, {cols}) + VALUES (?, ?, {placeholders}) + ON CONFLICT (commit_hash, chart) DO UPDATE SET {updates}"#, + group = req.group, + cols = columns.join(", "), + placeholders = placeholders.join(", "), + updates = columns.iter().map(|c| format!("{c} = EXCLUDED.{c}")).collect::>().join(", "), + ) + } else { + format!( + r#"INSERT INTO {group} (commit_hash, {cols}) + VALUES (?, {placeholders}) + ON CONFLICT (commit_hash) DO UPDATE SET {updates}"#, + group = req.group, + cols = columns.join(", "), + placeholders = placeholders.join(", "), + updates = columns.iter().map(|c| format!("{c} = EXCLUDED.{c}")).collect::>().join(", "), + ) + }; + + db.query(|conn| { + // Execute with parameters... + // Note: actual implementation needs to handle dynamic params + }).map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?; + + // Trigger async backup to S3 (don't block response) + tokio::spawn(backup_to_s3(req.group.clone())); + + Ok(StatusCode::OK) +} +``` + +### Example POST Requests from CI + +**Single-chart benchmark (compression):** + +```bash +curl -X POST https://bench.vortex.dev/api/ingest \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer ${BENCH_CI_TOKEN}" \ + -d '{ + "group": "compression", + "commit_hash": "abc123def456789", + "commit_timestamp": 1705968000, + "commit_message": "feat: improve compression ratio", + "commit_author": "developer@example.com", + "results": { + "vortex_compress_ns": 1500000000, + "parquet_compress_ns": 2100000000, + "vortex_decompress_ns": 800000000, + "parquet_decompress_ns": 950000000, + "vortex_size_bytes": 52428800, + "parquet_size_bytes": 58720256 + } + }' +``` + +**Multi-chart benchmark group, single query (TPC-H q1):** + +```bash +curl -X POST https://bench.vortex.dev/api/ingest \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer ${BENCH_CI_TOKEN}" \ + -d '{ + "group": "tpch_sf1", + "commit_hash": "abc123def456789", + "commit_timestamp": 1705968000, + "commit_message": "feat: improve compression ratio", + "commit_author": "developer@example.com", + "chart": "q1", + "results": { + "vortex_ns": 150000000, + "parquet_ns": 200000000, + "duckdb_vortex_ns": 180000000, + "duckdb_parquet_ns": 175000000, + "datafusion_vortex_ns": 220000000, + "datafusion_parquet_ns": 210000000 + } + }' +``` + +**Multi-chart benchmark group, all queries at once (recommended):** + +For efficiency, CI can POST multiple charts at once: + +```bash +curl -X POST https://bench.vortex.dev/api/ingest/batch \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer ${BENCH_CI_TOKEN}" \ + -d '{ + "group": "tpch_sf1", + "commit_hash": "abc123def456789", + "commit_timestamp": 1705968000, + "commit_message": "feat: improve compression ratio", + "commit_author": "developer@example.com", + "charts": { + "q1": { + "vortex_ns": 150000000, + "parquet_ns": 200000000, + "duckdb_vortex_ns": 180000000 + }, + "q2": { + "vortex_ns": 85000000, + "parquet_ns": 120000000, + "duckdb_vortex_ns": 95000000 + }, + "q3": { + "vortex_ns": 220000000, + "parquet_ns": 310000000, + "duckdb_vortex_ns": 250000000 + } + } + }' +``` + +**GitHub Actions workflow snippet:** + +```yaml +# .github/workflows/benchmarks.yml +- name: Run TPC-H Benchmarks + run: cargo bench --bench tpch -- --output json > results.json + +- name: Upload Results + env: + BENCH_CI_TOKEN: ${{ secrets.BENCH_CI_TOKEN }} + run: | + # Parse results and POST to benchmark server + # This script transforms benchmark output to our API format + python scripts/upload_benchmarks.py \ + --group tpch_sf1 \ + --commit ${{ github.sha }} \ + --timestamp $(git show -s --format=%ct ${{ github.sha }}) \ + --message "$(git show -s --format=%s ${{ github.sha }})" \ + --author "$(git show -s --format=%ae ${{ github.sha }})" \ + --results results.json \ + --endpoint https://bench.vortex.dev/api/ingest +``` + +--- + +## Client Architecture + +### Rendering Strategy + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ Initial Request │ +│ │ +│ 1. Server receives request for /benchmarks/clickbench │ +│ │ +│ 2. Leptos SSR queries DuckDB: │ +│ WITH recent AS ( │ +│ SELECT commit_hash, timestamp FROM commits │ +│ ORDER BY timestamp DESC LIMIT {N} -- configurable, e.g. 50 │ +│ ) │ +│ SELECT * FROM clickbench JOIN recent USING (commit_hash) │ +│ │ +│ 3. Server renders complete HTML with: │ +│ - Navigation, layout (static) │ +│ - 44 charts with N data points each (SSR'd canvas/svg) │ +│ - Island markers for hydration │ +│ - Serialized props for each island │ +│ │ +│ 4. HTML streams to browser (~500KB for N=50) │ +│ │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Browser Receives │ +│ │ +│ 5. HTML renders immediately - user sees charts with N commits │ +│ │ +│ 6. WASM bundle loads (~300KB gzipped) │ +│ │ +│ 7. Islands hydrate - charts become interactive │ +│ - Zoom/pan works within N-commit range │ +│ - "Show full history" button enabled │ +│ │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ (on user action) +┌─────────────────────────────────────────────────────────────────────────┐ +│ Lazy Load Full History │ +│ │ +│ 8. User clicks "Show full history" on Chart 7 │ +│ │ +│ 9. Client calls server function get_full_chart_history("q6") │ +│ │ +│ 10. Server queries DuckDB for all commits for that chart │ +│ │ +│ 11. ~500KB of data returns for that one chart (5000 commits) │ +│ │ +│ 12. Chart re-renders with full history │ +│ User can now zoom/pan across entire commit range │ +│ │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +### Component Hierarchy + +``` +App +├── Layout +│ ├── Navigation (static) +│ │ └── Group links (compression, tpch_sf1, clickbench, ...) +│ └── Main Content +│ └── (router) +│ +└── Routes + ├── / -> HomePage (static) + │ + ├── /benchmarks/:group -> GroupPage + │ ├── GroupHeader (static) + │ │ ├── Title + │ │ └── Summary statistics + │ │ + │ └── ChartList + │ ├── ChartWithLazyHistory [island] (chart=q1) + │ ├── ChartWithLazyHistory [island] (chart=q2) + │ ├── ... + │ └── ChartWithLazyHistory [island] (chart=qN) + │ + └── /compare -> ComparePage (future) +``` + +### Key Components + +#### GroupPage (Server Component) + +```rust +// src/components/group_page.rs + +/// Configurable initial commit count (tune based on testing) +const INITIAL_COMMITS: usize = 50; // Could be 25-100 + +#[component] +pub fn GroupPage(group_id: String) -> impl IntoView { + // This runs on the server during SSR + let group_config = get_group_config(&group_id); + + // Fetch most recent N commits of data for ALL charts in this group + let initial_data = create_resource( + move || group_id.clone(), + |group| async move { + get_initial_group_data(group, INITIAL_COMMITS).await + } + ); + + view! { +
+ + + }> + {move || initial_data.get().map(|data| { + let charts = group_by_chart(data); + view! { +
+ + } + } + /> +
+ } + })} +
+
+ } +} +``` + +#### ChartWithLazyHistory (Island Component) + +```rust +// src/components/chart.rs + +/// Commit metadata shared across all charts +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct CommitInfo { + pub hash: String, + pub timestamp: i64, // Unix timestamp + pub message: Option, +} + +/// A single measurement point on a chart. +/// Only exists for commits that have actual benchmark data. +/// If a commit has no data for a series, there simply won't be a ChartPoint for it. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct ChartPoint { + pub commit_idx: usize, // Index into CommitInfo array + pub series: String, // e.g., "vortex_ns", "duckdb_parquet_ns" + pub value: u64, // Raw measurement (e.g., nanoseconds) +} + +/// All data needed to render a chart +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct ChartData { + /// All commits in the time range, ordered by timestamp (oldest first). + /// This includes commits WITHOUT benchmark data - the x-axis should show + /// all commits consistently, with gaps where data is missing. + pub commits: Vec, + + /// Measurement points - ONLY for commits that have data. + /// Sparse: if a commit has no data for a series, there's no ChartPoint. + /// When rendering, check if commit_idx exists for the series. + pub points: Vec, + + /// Series names available in this chart (e.g., ["vortex_ns", "parquet_ns"]) + pub series_names: Vec, +} + +impl ChartData { + /// Get all points for a specific series. + /// Returns (commit_idx, value) pairs - only for commits WITH data. + /// Gaps in commit indices indicate missing data (should show as line breaks). + pub fn series_points(&self, series: &str) -> Vec<(usize, u64)> { + self.points + .iter() + .filter(|p| p.series == series) + .map(|p| (p.commit_idx, p.value)) + .collect() + } + + /// Check if a specific commit has data for a series + pub fn has_data(&self, commit_idx: usize, series: &str) -> bool { + self.points.iter().any(|p| p.commit_idx == commit_idx && p.series == series) + } +} + +// ============================================================================ +// HANDLING SPARSE DATA IN CHARTS +// ============================================================================ +// +// Not all commits have benchmark data. This can happen because: +// - Benchmarks only run on certain branches or commit types +// - A benchmark was added after many commits already existed +// - CI failures prevented benchmark runs +// - A new series (target) was added to an existing benchmark +// +// The data model handles this by: +// 1. `commits` array contains ALL commits in the time range (from LEFT JOIN) +// 2. `points` array contains ONLY commits with actual measurements +// 3. When rendering, absence of a ChartPoint for a commit_idx = no data +// +// Chart rendering should: +// - Show all commits on x-axis (consistent spacing) +// - Draw line segments only between consecutive commits WITH data +// - Show gaps (line breaks) where data is missing +// - Tooltips should show "No data" for commits without measurements +// - Do NOT interpolate or connect across gaps +// ============================================================================ + +/// Interactive chart with lazy-loaded full history +/// +/// This is an island - ships as WASM for client-side interactivity. +/// Initial data (N commits) comes from SSR. Full history loads on demand. +#[island] +pub fn ChartWithLazyHistory( + group: String, + chart: String, + initial_data: ChartData, + config: GroupConfig, +) -> impl IntoView { + let (data, set_data) = create_signal(initial_data.clone()); + let (full_history_loaded, set_full_history_loaded) = create_signal(false); + let (loading_history, set_loading_history) = create_signal(false); + + // View range as indices into commits array + let (view_start, set_view_start) = create_signal(0usize); + let (view_end, set_view_end) = create_signal(initial_data.commits.len()); + + let load_full_history = move |_| { + if full_history_loaded.get() || loading_history.get() { + return; + } + set_loading_history.set(true); + + let group = group.clone(); + let chart = chart.clone(); + + spawn_local(async move { + match get_full_chart_history(group, Some(chart)).await { + Ok(full_data) => { + let len = full_data.commits.len(); + set_data.set(full_data); + set_view_end.set(len); + set_full_history_loaded.set(true); + } + Err(e) => { + log::error!("Failed to load history: {}", e); + } + } + set_loading_history.set(false); + }); + }; + + // Auto-load full history when user pans past available data + let on_view_change = move |new_start: usize, new_end: usize| { + if new_start > 0 && !full_history_loaded.get() { + load_full_history(()); + } + set_view_start.set(new_start); + set_view_end.set(new_end); + }; + + view! { +
+
+

{&chart}

+ + + + + + + + {move || format!("{} commits", data.get().commits.len())} + + +
+ + + + +
"← Pan left for full history"
+
+
+ } +} +``` + +#### ChartCanvas (Chart Rendering) + +For charting, use one of these approaches: + +**Option A: plotters + Canvas (Recommended)** + +```rust +use plotters::prelude::*; +use plotters_canvas::CanvasBackend; + +#[component] +fn ChartCanvas( + data: ReadSignal, + view_start: ReadSignal, + view_end: ReadSignal, + config: GroupConfig, + on_view_change: impl Fn(usize, usize) + 'static, +) -> impl IntoView { + let canvas_ref = create_node_ref::(); + + create_effect(move |_| { + let Some(canvas) = canvas_ref.get() else { return }; + let chart_data = data.get(); + let start = view_start.get(); + let end = view_end.get().min(chart_data.commits.len()); + + let backend = CanvasBackend::with_canvas_object(canvas.clone()).unwrap(); + let root = backend.into_drawing_area(); + root.fill(&WHITE).unwrap(); + + // Draw each series - handle sparse data by drawing line segments + // only between consecutive commits that have data + for series_name in &chart_data.series_names { + let points = chart_data.series_points(series_name); + // Filter to visible range [start, end) + let visible: Vec<_> = points.iter() + .filter(|(idx, _)| *idx >= start && *idx < end) + .collect(); + + // Draw line segments between consecutive points + // Gaps in commit indices mean missing data - don't connect across gaps + for window in visible.windows(2) { + let (idx1, val1) = window[0]; + let (idx2, val2) = window[1]; + // Only draw line if commits are adjacent (no gap) + // Or always draw lines and let gaps show as visual discontinuities + // ... plotters line drawing ... + } + } + } + }); + + let on_wheel = move |e: WheelEvent| { + e.prevent_default(); + // Zoom logic + }; + + view! { + + } +} +``` + +**Option B: Custom SVG** + +Alternative if you need more control over rendering. Build SVG elements directly with Leptos's `view!` macro, using computed scales for x/y positioning. More verbose but avoids external dependencies. + +### Data Refresh + +Poll for updates periodically (e.g., every 60 seconds) or rely on users refreshing the page. Since benchmarks don't run that frequently, simple polling is sufficient. + +--- + +## API Design + +### Server Functions (Leptos) + +```rust +// src/api/charts.rs + +/// Number of commits to show in initial view (configurable) +const INITIAL_COMMIT_COUNT: usize = 50; + +/// Get initial data for a benchmark group (most recent N commits) +/// Called during SSR to populate initial page +#[server(GetInitialGroupData)] +pub async fn get_initial_group_data( + group: String, +) -> Result { + let db = use_context::().unwrap(); + let config = get_group_config(&group)?; + + // Use LEFT JOIN: we want ALL recent commits, even those without benchmark data. + // This ensures the x-axis is consistent across all charts. + // Commits without data will have NULL values for series columns. + let sql = if config.chart_column.is_some() { + format!(r#" + WITH recent AS ( + SELECT commit_hash, timestamp, message + FROM commits + ORDER BY timestamp DESC + LIMIT {limit} + ) + SELECT r.commit_hash, r.timestamp, r.message, b.chart, b.* + FROM recent r + LEFT JOIN {group} b ON r.commit_hash = b.commit_hash + ORDER BY b.chart, r.timestamp DESC + "#, limit = INITIAL_COMMIT_COUNT, group = group) + } else { + format!(r#" + WITH recent AS ( + SELECT commit_hash, timestamp, message + FROM commits + ORDER BY timestamp DESC + LIMIT {limit} + ) + SELECT r.commit_hash, r.timestamp, r.message, b.* + FROM recent r + LEFT JOIN {group} b ON r.commit_hash = b.commit_hash + ORDER BY r.timestamp DESC + "#, limit = INITIAL_COMMIT_COUNT, group = group) + }; + + let rows = db.query(|conn| conn.query(&sql, []))?; + Ok(GroupData::from_rows(rows, &config)) +} + +/// Get full history for a single chart +/// Called client-side when user requests full history +#[server(GetFullChartHistory)] +pub async fn get_full_chart_history( + group: String, + chart: Option, +) -> Result { + let db = use_context::().unwrap(); + + // Use LEFT JOIN: include all commits, benchmark data may be NULL. + // For multi-chart groups, filter by chart in the ON clause to get + // NULL for commits that don't have data for this specific chart. + let sql = if let Some(ref chart_name) = chart { + format!(r#" + SELECT c.commit_hash, c.timestamp, c.message, b.* + FROM commits c + LEFT JOIN {group} b ON c.commit_hash = b.commit_hash + AND b.chart = ? + ORDER BY c.timestamp ASC + "#, group = group) + } else { + format!(r#" + SELECT c.commit_hash, c.timestamp, c.message, b.* + FROM commits c + LEFT JOIN {group} b ON c.commit_hash = b.commit_hash + ORDER BY c.timestamp ASC + "#, group = group) + }; + + let rows = db.query(|conn| { + if let Some(chart_name) = chart { + conn.query(&sql, [&chart_name]) + } else { + conn.query(&sql, []) + } + })?; + + Ok(ChartData::from_rows(rows)) +} + +/// Get summary statistics for a benchmark group +#[server(GetGroupSummary)] +pub async fn get_group_summary( + group: String, +) -> Result { + let db = use_context::().unwrap(); + let config = get_group_config(&group)?; + + // Compute statistics over recent commits + // Note: geometric mean requires special handling for u64 values + let sql = format!(r#" + WITH recent AS ( + SELECT commit_hash FROM commits + ORDER BY timestamp DESC + LIMIT 100 -- Summary over last 100 commits + ) + SELECT + AVG(CAST(vortex_ns AS DOUBLE)) as vortex_avg, + EXP(AVG(LN(CAST(NULLIF(vortex_ns, 0) AS DOUBLE)))) as vortex_geomean, + PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY vortex_ns) as vortex_median, + -- ... same for other series ... + FROM {group} + WHERE commit_hash IN (SELECT commit_hash FROM recent) + "#, group = group); + + // ... +} +``` + +### REST Endpoint (CI Ingest) + +``` +POST /api/ingest +Content-Type: application/json +Authorization: Bearer + +{ + "group": "tpch_sf1", + "commit_hash": "abc123def456", + "commit_timestamp": 1705968000, + "chart": "q1", + "results": { + "vortex_ns": 150000000, + "parquet_ns": 200000000, + "lance_ns": 180000000 + } +} + +Response: 200 OK +``` + +--- + +## Deployment & Infrastructure + +### AWS Architecture + +``` +┌────────────────────────────────────────────────────────────────────────┐ +│ AWS Account │ +│ │ +│ ┌─────────────────────────────────────────────────────────────────┐ │ +│ │ CloudFront │ │ +│ │ Distribution: bench.vortex.dev │ │ +│ │ - Origin: ALB │ │ +│ │ - Cache behaviors: │ │ +│ │ - /api/*: TTL 60s, stale-while-revalidate │ │ +│ │ - /pkg/*: TTL 1 year (WASM, immutable) │ │ +│ │ - /*: TTL 60s (HTML) │ │ +│ └─────────────────────────────────────────────────────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌─────────────────────────────────────────────────────────────────┐ │ +│ │ Application Load Balancer │ │ +│ │ - Health check: /health │ │ +│ │ - Target: ECS service │ │ +│ └─────────────────────────────────────────────────────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌─────────────────────────────────────────────────────────────────┐ │ +│ │ ECS Fargate │ │ +│ │ Service: bench-website │ │ +│ │ - Task: 1 vCPU, 2GB RAM │ │ +│ │ - Container: bench-website:latest │ │ +│ │ - Volume: EFS mount at /data │ │ +│ └─────────────────────────────────────────────────────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌─────────────────────────────────────────────────────────────────┐ │ +│ │ EFS (Elastic File System) │ │ +│ │ - Stores DuckDB database file │ │ +│ │ - Persists across container restarts │ │ +│ │ - Single-AZ (cost savings, acceptable for this use case) │ │ +│ └─────────────────────────────────────────────────────────────────┘ │ +│ │ +│ ┌─────────────────────────────────────────────────────────────────┐ │ +│ │ S3 │ │ +│ │ Bucket: vortex-benchmarks-backup │ │ +│ │ - Hourly backups of DuckDB database │ │ +│ │ - Lifecycle: Delete after 30 days │ │ +│ └─────────────────────────────────────────────────────────────────┘ │ +│ │ +└────────────────────────────────────────────────────────────────────────┘ +``` + +### Alternative: Simpler Single EC2 + +For lower traffic/budget: + +``` +CloudFront -> EC2 (t3.medium) -> Local EBS for data + -> S3 for backups +``` + +This is simpler and cheaper (~$30/month) but less resilient. Acceptable for internal tooling. + +### Environment Variables + +```bash +# Required +BENCH_DATA_DIR=/data # Path to data directory +BENCH_CI_TOKEN= # Token for CI authentication +BENCH_S3_BUCKET=vortex-benchmarks-backup + +# Optional +BENCH_PORT=3000 +BENCH_LOG_LEVEL=info +RUST_LOG=bench_website=debug +``` + +### CI/CD Pipeline + +```yaml +# .github/workflows/deploy.yml +name: Deploy Benchmarks Website + +on: + push: + branches: [main] + paths: + - "bench-website/**" + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Build Docker image + run: | + docker build -t bench-website ./bench-website + + - name: Push to ECR + run: | + aws ecr get-login-password | docker login --username AWS --password-stdin $ECR_REGISTRY + docker tag bench-website:latest $ECR_REGISTRY/bench-website:latest + docker push $ECR_REGISTRY/bench-website:latest + + - name: Deploy to ECS + run: | + aws ecs update-service --cluster bench --service bench-website --force-new-deployment +``` + +### Dockerfile + +```dockerfile +# Build stage +FROM rust:1.75 as builder + +WORKDIR /app +COPY . . + +# Install wasm target for Leptos client +RUN rustup target add wasm32-unknown-unknown + +# Install cargo-leptos +RUN cargo install cargo-leptos + +# Build both server and client +RUN cargo leptos build --release + +# Runtime stage +FROM debian:bookworm-slim + +RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/* + +WORKDIR /app + +# Copy server binary +COPY --from=builder /app/target/release/bench-website . + +# Copy client WASM and assets +COPY --from=builder /app/target/site ./site + +ENV BENCH_DATA_DIR=/data +ENV BENCH_PORT=3000 + +EXPOSE 3000 + +CMD ["./bench-website"] +``` + +--- + +## Plan of Attack + +This is a **prototype-first, library-oriented** implementation plan. The goal is to build a reusable benchmark visualization library that can be plugged into any data source. + +### Key Design Decisions + +- **Plotters** for charting (Rust-native, Canvas rendering) +- **DuckDB for storage** - Simple embedded database with fast analytical queries +- **Mock data for development** - Real data pipeline is separate; design for pluggability +- **Library-first mindset** - Keep benchmark-specific details separate from core visualization + +### Key Simplifications + +1. **Get a working prototype ASAP** - Mock/hardcode where possible +2. **Start with 1-2 benchmark groups** - Not all schemas upfront +3. **CI integration comes last** - Once everything works locally +4. **Design for pluggability** - Core lib shouldn't depend on specific data sources + +--- + +### Phase 1: Minimal Working Prototype + +**Goal**: See a Leptos page rendering one chart with mock data from DuckDB + +**Steps**: + +1.1. **Set up project structure** +- Create `bench-website/` with basic Leptos + Axum skeleton +- Add `duckdb` and `plotters` crate dependencies +- Single `main.rs` with inline routes and components + +1.2. **Mock data setup** +- Create test data generator that produces representative benchmark data +- Create TWO tables only: + - `commits` (commit_hash, timestamp, message, author) + - `random_access` (simple single-chart group with ~3 series) +- Generate ~100 mock commits with realistic patterns (some regressions, improvements) +- Store as local DuckDB file + +1.3. **Single chart page** +- Hardcoded route `/` that queries DuckDB +- Server-side render a basic HTML page with data +- Render using plotters to Canvas (or SVG initially to validate data flow) +- No islands, no interactivity yet - just prove SSR + DuckDB works + +**Deliverable**: `cargo leptos watch` shows a page with mock benchmark data + +--- + +### Phase 2: Basic Interactive Charts + +**Goal**: Interactive charts with zoom/pan for two benchmark groups + +**Steps**: + +2.1. **Plotters integration** +- Set up plotters with Canvas backend for WASM +- Render actual line charts for random_access mock data +- Show multiple series with different colors +- Basic axis labels and legend + +2.2. **Add second benchmark group (multi-chart)** +- Add `tpch_sf1` table with mock data (multi-chart: q1-q19) +- Create `/benchmarks/:group` route +- GroupPage component that lists multiple charts +- Demonstrate the "Pattern B" schema (commit_hash + chart + series columns) + +2.3. **Make charts interactive (islands)** +- Convert chart component to `#[island]` +- Implement zoom/pan with mouse wheel via plotters +- Test that WASM hydration works + +**Deliverable**: Two working benchmark groups with interactive charts + +--- + +### Phase 3: Library Interface & Configuration + +**Goal**: Clean interface for plugging in real data sources + +**Steps**: + +3.1. **Define pluggable interfaces** +- `BenchmarkGroup` trait/struct for group configuration +- `SeriesConfig` for series metadata (colors, units, display names) +- `MeasurementUnit` enum for value formatting (ns → ms, bytes → MB, etc.) + +3.2. **Configuration-driven groups** +- Move hardcoded group definitions to configuration +- Support both "single chart" and "multi-chart" patterns +- Dynamic schema creation based on config + +3.3. **Navigation & layout** +- Sidebar with all configured benchmark groups +- Responsive design basics +- URL routing for all groups + +**Deliverable**: Clean library interface, easy to add new benchmark groups + +--- + +### Phase 4: Progressive Loading Optimization + +**Goal**: Fast initial load, lazy history on demand + +**Steps**: + +4.1. **Limit initial data** +- Fetch only last 50 commits on page load +- Verify initial HTML is small (~500KB) + +4.2. **Lazy load full history** +- "Show full history" button per chart +- Server function to fetch all commits for one chart +- Auto-trigger on pan-left + +4.3. **Performance tuning** +- Measure actual load times +- Add indexes if needed +- Cache headers for API responses + +**Deliverable**: Sub-second initial page load + +--- + +### Phase 5: Ingest Endpoint + +**Goal**: Generic API for submitting benchmark results + +**Steps**: + +5.1. **Implement POST /api/ingest** +- Accept benchmark results in standardized format +- Simple token auth (env var) +- UPSERT logic for idempotency +- Works for any configured benchmark group + +5.2. **Batch ingest support** +- POST /api/ingest/batch for multiple charts at once +- Useful for groups like TPC-H where all queries run together + +**Deliverable**: Working ingest API (integration with specific CI is user's responsibility) + +--- + +### Phase 6: Production Readiness + +**Goal**: Ready for deployment + +**Steps**: + +6.1. **Dockerfile** +- Multi-stage Docker build +- Minimal runtime image +- Configurable via environment variables + +6.2. **Health & observability** +- Health check endpoint +- Basic logging +- Metrics hooks (optional) + +6.3. **Documentation** +- How to configure benchmark groups +- How to set up ingest +- How to deploy + +**Deliverable**: Production-ready library that can be deployed and integrated + +--- + +### What's Deferred Until Later Phases + +- Real data import scripts (user has separate pipeline) + +### What's Explicitly Out of Scope + +- Compare view / permalinks +- Export functionality (PNG/CSV) +- Mobile optimization beyond basics +- Materialized views +- Complex backup/restore automation + +--- + +### Files to Create + +``` +bench-website/ +├── Cargo.toml +├── src/ +│ ├── main.rs # Axum server setup, routes +│ ├── lib.rs # Leptos app root +│ ├── mock_data.rs # Test data generation (prototyping only) +│ ├── db/ +│ │ ├── mod.rs +│ │ ├── connection.rs # DuckDB connection pool +│ │ ├── queries.rs # SQL query functions +│ │ └── models.rs # Data structures +│ ├── api/ +│ │ ├── mod.rs +│ │ ├── ingest.rs # POST /api/ingest endpoint +│ │ └── charts.rs # Server functions for chart data +│ ├── components/ +│ │ ├── mod.rs +│ │ ├── app.rs # Root component, router +│ │ ├── layout.rs # Navigation, sidebar +│ │ ├── group_page.rs # Benchmark group page +│ │ └── chart.rs # Interactive chart island (plotters) +│ └── config/ +│ ├── mod.rs +│ └── groups.rs # Benchmark group definitions +├── style/ +│ └── main.css +└── Dockerfile +``` + +--- + +## Future Considerations + +### Scaling Beyond Current Needs + +The current design handles ~125MB of data and ~200 charts comfortably. If data grows significantly: + +- **More commits (10,000+)**: Consider time-based partitioning (e.g., one file per year) +- **More benchmark groups**: No architectural changes needed, just more tables +- **Higher write throughput**: DuckDB handles concurrent writes well, but could add write batching if needed +- **Global low latency**: Deploy read replicas in multiple regions + +### Alternative Charting Libraries + +If plotters proves insufficient: + +- **uPlot**: Extremely fast (47KB), handles 100k+ points, but requires JS interop +- **ECharts via charming**: Full-featured, but large bundle (~1MB) +- **D3 via wasm-bindgen**: Maximum flexibility, moderate complexity + +--- + +## Appendix: Quick Reference + +### Common Commands + +```bash +# Local development +cd bench-website +cargo leptos watch + +# Run tests +cargo test + +# Build for production +cargo leptos build --release + +# Query DuckDB directly (for debugging) +duckdb data/benchmarks.duckdb +> SELECT * FROM tpch_sf1 WHERE chart = 'q1' LIMIT 10; + +# Ingest test data +curl -X POST http://localhost:3000/api/ingest \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer $BENCH_CI_TOKEN" \ + -d '{"group": "tpch_sf1", "commit_hash": "abc123", "commit_timestamp": 1705968000, "chart": "q1", "results": {"vortex_ns": 100000000}}' +``` + +### Key Files + +| File | Purpose | +| ------------------------- | ------------------------------- | +| `src/db/connection.rs` | DuckDB pool and query helpers | +| `src/api/ingest.rs` | CI ingest endpoint | +| `src/api/charts.rs` | Server functions for chart data | +| `src/components/chart.rs` | Interactive chart island | +| `src/config/groups.rs` | Benchmark group definitions | +| `data/benchmarks.duckdb` | DuckDB database (gitignored) | + +### Data Sizes (Estimates) + +| Group | Charts | Commits | Rows | ~Size | +| ---------------------- | -------- | ------- | -------- | ---------- | +| compression | 1 | 5000 | 5,000 | 2MB | +| random_access | 1 | 5000 | 5,000 | 2MB | +| tpch_sf1 | 19 | 5000 | 95,000 | 15MB | +| tpch_sf10 | 19 | 5000 | 95,000 | 15MB | +| tpch_sf100 | 19 | 5000 | 95,000 | 15MB | +| clickbench | 44 | 5000 | 220,000 | 25MB | +| other micro-benchmarks | ~100 | 5000 | ~500,000 | 50MB | +| commits | - | 5000 | 5,000 | 1MB | +| **Total** | **~200** | - | **~1M** | **~125MB** | + +Note: Actual current data is ~2000 commits (manually truncated). With full history restored, expect ~125MB total. \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index dc468062558..3087b2c8a3f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -139,6 +139,18 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "any_spawner" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1384d3fe1eecb464229fcf6eebb72306591c56bf27b373561489458a7c73027d" +dependencies = [ + "futures", + "thiserror 2.0.18", + "tokio", + "wasm-bindgen-futures", +] + [[package]] name = "anyhow" version = "1.0.100" @@ -732,6 +744,12 @@ dependencies = [ "futures-lite", ] +[[package]] +name = "async-once-cell" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288f83726785267c6f2ef073a3d83dc3f9b81464e9f99898240cced85fce35a" + [[package]] name = "async-process" version = "2.5.0" @@ -851,6 +869,36 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +[[package]] +name = "attribute-derive" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05832cdddc8f2650cc2cc187cc2e952b8c133a48eb055f35211f61ee81502d77" +dependencies = [ + "attribute-derive-macro", + "derive-where", + "manyhow", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "attribute-derive-macro" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a7cdbbd4bd005c5d3e2e9c885e6fa575db4f4a3572335b974d8db853b6beb61" +dependencies = [ + "collection_literals", + "interpolator", + "manyhow", + "proc-macro-utils", + "proc-macro2", + "quote", + "quote-use", + "syn 2.0.114", +] + [[package]] name = "autocfg" version = "1.5.0" @@ -1208,6 +1256,62 @@ dependencies = [ "tracing", ] +[[package]] +name = "axum" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8" +dependencies = [ + "axum-core", + "base64", + "bytes", + "form_urlencoded", + "futures-util", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", + "hyper", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "multer", + "percent-encoding", + "pin-project-lite", + "serde_core", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sha1", + "sync_wrapper", + "tokio", + "tokio-tungstenite", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-core" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" +dependencies = [ + "bytes", + "futures-core", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", + "mime", + "pin-project-lite", + "sync_wrapper", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "backon" version = "1.6.0" @@ -1219,6 +1323,12 @@ dependencies = [ "tokio", ] +[[package]] +name = "base16" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d27c3610c36aee21ce8ac510e6224498de4228ad772a171ed65643a24693a5a8" + [[package]] name = "base64" version = "0.22.1" @@ -1241,6 +1351,30 @@ version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" +[[package]] +name = "bench-website" +version = "0.1.0" +dependencies = [ + "axum", + "chrono", + "console_error_panic_hook", + "duckdb", + "leptos", + "leptos_axum", + "leptos_meta", + "leptos_router", + "rand 0.9.2", + "serde", + "serde_json", + "thiserror 2.0.18", + "tokio", + "tower", + "tower-http", + "tracing", + "tracing-subscriber", + "wasm-bindgen", +] + [[package]] name = "better_io" version = "0.2.0" @@ -1557,6 +1691,12 @@ dependencies = [ "libbz2-rs-sys", ] +[[package]] +name = "camino" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48" + [[package]] name = "cast" version = "0.3.0" @@ -1767,6 +1907,17 @@ dependencies = [ "cc", ] +[[package]] +name = "codee" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9dbbdc4b4d349732bc6690de10a9de952bd39ba6a065c586e26600b6b0b91f5" +dependencies = [ + "serde", + "serde_json", + "thiserror 2.0.18", +] + [[package]] name = "codespan-reporting" version = "0.13.1" @@ -1865,6 +2016,12 @@ dependencies = [ "regex-lite", ] +[[package]] +name = "collection_literals" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2550f75b8cfac212855f6b1885455df8eaee8fe8e246b647d69146142e016084" + [[package]] name = "colorchoice" version = "1.0.4" @@ -1971,6 +2128,19 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf0a07a401f374238ab8e2f11a104d2851bf9ce711ec69804834de8af45c7af" +[[package]] +name = "config" +version = "0.15.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b30fa8254caad766fc03cb0ccae691e14bf3bd72bfff27f72802ce729551b3d6" +dependencies = [ + "convert_case 0.6.0", + "pathdiff", + "serde_core", + "toml", + "winnow", +] + [[package]] name = "console" version = "0.15.11" @@ -1996,6 +2166,16 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + [[package]] name = "const-oid" version = "0.9.6" @@ -2022,6 +2202,12 @@ dependencies = [ "tiny-keccak", ] +[[package]] +name = "const-str" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0664d2867b4a32697dfe655557f5c3b187e9b605b38612a748e5ec99811d160" + [[package]] name = "const_for" version = "0.1.5" @@ -2048,6 +2234,12 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "const_str_slice_concat" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f67855af358fcb20fac58f9d714c94e2b228fe5694c1c9b4ead4a366343eda1b" + [[package]] name = "constant_time_eq" version = "0.3.1" @@ -2060,6 +2252,24 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "convert_case" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baaaa0ecca5b51987b9423ccdc971514dd8b0bb7b4060b983d3664dad3f1f89f" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "convert_case" version = "0.10.0" @@ -2383,6 +2593,12 @@ dependencies = [ "parking_lot_core", ] +[[package]] +name = "data-encoding" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" + [[package]] name = "datafusion" version = "50.3.0" @@ -3683,6 +3899,17 @@ dependencies = [ "serde_core", ] +[[package]] +name = "derive-where" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef941ded77d15ca19b40374869ac6000af1c9f2a4c0f3d4c70926287e6364a8f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + [[package]] name = "derive_arbitrary" version = "1.4.2" @@ -3709,7 +3936,7 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" dependencies = [ - "convert_case", + "convert_case 0.10.0", "proc-macro2", "quote", "rustc_version", @@ -3795,12 +4022,35 @@ version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "117240f60069e65410b3ae1bb213295bd828f707b5bec6596a1afc8793ce0cbc" +[[package]] +name = "drain_filter_polyfill" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "669a445ee724c5c69b1b06fe0b63e70a1c84bc9bb7d9696cd4f4e3ec45050408" + [[package]] name = "dtype_dispatch" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3a5ccdfd6c5e7e2fea9c5cf256f2a08216047fab19c621c3da64e9ae4a1462d" +[[package]] +name = "duckdb" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7eeb487dde618b9f6ab26a451775ad5fac3fabe1ca2b64cbbe90b105f264ccd" +dependencies = [ + "arrow 56.2.0", + "cast", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libduckdb-sys", + "num-integer", + "rust_decimal", + "strum 0.27.2", +] + [[package]] name = "duckdb-bench" version = "0.1.0" @@ -3835,6 +4085,16 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +[[package]] +name = "either_of" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "216d23e0ec69759a17f05e1c553f3a6870e5ec73420fbb07807a6f34d5d1d5a4" +dependencies = [ + "paste", + "pin-project-lite", +] + [[package]] name = "encode_unicode" version = "1.0.0" @@ -3905,6 +4165,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +[[package]] +name = "erased" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1731451909bde27714eacba19c2566362a7f35224f52b153d3f42cf60f72472" + [[package]] name = "errno" version = "0.3.14" @@ -3990,6 +4256,18 @@ dependencies = [ "ext-trait", ] +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + [[package]] name = "fancy-regex" version = "0.11.0" @@ -4240,6 +4518,7 @@ dependencies = [ "futures-core", "futures-task", "futures-util", + "num_cpus", ] [[package]] @@ -4381,6 +4660,27 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" +[[package]] +name = "gloo-net" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06f627b1a58ca3d42b45d6104bf1e1a03799df472df00988b6ba21accc10580" +dependencies = [ + "futures-channel", + "futures-core", + "futures-sink", + "gloo-utils", + "http 1.4.0", + "js-sys", + "pin-project", + "serde", + "serde_json", + "thiserror 1.0.69", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "gloo-timers" version = "0.3.0" @@ -4393,6 +4693,19 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gloo-utils" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5555354113b18c547c1d3a98fbf7fb32a9ff4f6fa112ce823a21641a0ba3aa" +dependencies = [ + "js-sys", + "serde", + "serde_json", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "goldenfile" version = "1.9.1" @@ -4411,6 +4724,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9e2d4c0a8296178d8802098410ca05d86b17a10bb5ab559b3fb404c1f948220" +[[package]] +name = "guardian" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17e2ac29387b1aa07a1e448f7bb4f35b500787971e965b02842b900afa5c8f6f" + [[package]] name = "h2" version = "0.4.13" @@ -4489,6 +4808,15 @@ dependencies = [ "foldhash 0.2.0", ] +[[package]] +name = "hashlink" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +dependencies = [ + "hashbrown 0.15.5", +] + [[package]] name = "heck" version = "0.5.0" @@ -4525,6 +4853,15 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "html-escape" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d1ad449764d627e22bfd7cd5e8868264fc9236e07c752972b4080cd351cb476" +dependencies = [ + "utf8-width", +] + [[package]] name = "htmlescape" version = "0.3.1" @@ -4586,6 +4923,12 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "http-range-header" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9171a2ea8a68358193d15dd5d70c1c10a2afc3e7e4c5bc92bc9f025cebd7359c" + [[package]] name = "httparse" version = "1.10.1" @@ -4593,7 +4936,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] -name = "humansize" +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "humansize" version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7" @@ -4607,6 +4956,22 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" +[[package]] +name = "hydration_context" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8714ae4adeaa846d838f380fbd72f049197de629948f91bf045329e0cf0a283" +dependencies = [ + "futures", + "js-sys", + "once_cell", + "or_poisoned", + "pin-project-lite", + "serde", + "throw_error", + "wasm-bindgen", +] + [[package]] name = "hyper" version = "1.8.1" @@ -4621,6 +4986,7 @@ dependencies = [ "http 1.4.0", "http-body 1.0.1", "httparse", + "httpdate", "itoa", "pin-project-lite", "pin-utils", @@ -4924,6 +5290,12 @@ version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8bb03732005da905c88227371639bf1ad885cc712789c011c31c5fb3ab3ccf02" +[[package]] +name = "interpolator" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71dd52191aae121e8611f1e8dc3e324dd0dd1dee1e6dd91d10ee07a3cfb4d9d8" + [[package]] name = "inventory" version = "0.3.21" @@ -5663,6 +6035,228 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "leptos" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f9569fc37575a5d64c0512145af7630bf651007237ef67a8a77328199d315bb" +dependencies = [ + "any_spawner", + "base64", + "cfg-if", + "either_of", + "futures", + "getrandom 0.3.4", + "hydration_context", + "leptos_config", + "leptos_dom", + "leptos_hot_reload", + "leptos_macro", + "leptos_server", + "oco_ref", + "or_poisoned", + "paste", + "rand 0.9.2", + "reactive_graph", + "rustc-hash", + "rustc_version", + "send_wrapper", + "serde", + "serde_json", + "serde_qs", + "server_fn", + "slotmap", + "tachys", + "thiserror 2.0.18", + "throw_error", + "typed-builder 0.23.2", + "typed-builder-macro 0.23.2", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm_split_helpers", + "web-sys", +] + +[[package]] +name = "leptos_axum" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0caa95760f87f3067e05025140becefdbdfd36cbc2adac4519f06e1f1edf4af" +dependencies = [ + "any_spawner", + "axum", + "dashmap", + "futures", + "hydration_context", + "leptos", + "leptos_integration_utils", + "leptos_macro", + "leptos_meta", + "leptos_router", + "parking_lot", + "server_fn", + "tachys", + "tokio", + "tower", + "tower-http", +] + +[[package]] +name = "leptos_config" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071fc40aeb9fcab885965bad1887990477253ad51f926cd19068f45a44c59e89" +dependencies = [ + "config", + "regex", + "serde", + "thiserror 2.0.18", + "typed-builder 0.21.2", +] + +[[package]] +name = "leptos_dom" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78f4330c88694c5575e0bfe4eecf81b045d14e76a4f8b00d5fd2a63f8779f895" +dependencies = [ + "js-sys", + "or_poisoned", + "reactive_graph", + "send_wrapper", + "tachys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "leptos_hot_reload" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d61ec3e1ff8aaee8c5151688550c0363f85bc37845450764c31ff7584a33f38" +dependencies = [ + "anyhow", + "camino", + "indexmap", + "parking_lot", + "proc-macro2", + "quote", + "rstml", + "serde", + "syn 2.0.114", + "walkdir", +] + +[[package]] +name = "leptos_integration_utils" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13cccc9305df53757bae61bf15641bfa6a667b5f78456ace4879dfe0591ae0e8" +dependencies = [ + "futures", + "hydration_context", + "leptos", + "leptos_config", + "leptos_meta", + "leptos_router", + "reactive_graph", +] + +[[package]] +name = "leptos_macro" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c86ffd2e9cf3e264e9b3e16bdb086cefa26bd0fa7bc6a26b0cc5f6c1fd3178ed" +dependencies = [ + "attribute-derive", + "cfg-if", + "convert_case 0.10.0", + "html-escape", + "itertools 0.14.0", + "leptos_hot_reload", + "prettyplease", + "proc-macro-error2", + "proc-macro2", + "quote", + "rstml", + "rustc_version", + "server_fn_macro", + "syn 2.0.114", + "uuid", +] + +[[package]] +name = "leptos_meta" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d489e38d3f541e9e43ecc2e3a815527840345a2afca629b3e23fcc1dd254578" +dependencies = [ + "futures", + "indexmap", + "leptos", + "or_poisoned", + "send_wrapper", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "leptos_router" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01e573711f2fb9ab5d655ec38115220d359eaaf1dcb93cc0ea624543b6dba959" +dependencies = [ + "any_spawner", + "either_of", + "futures", + "gloo-net", + "js-sys", + "leptos", + "leptos_router_macro", + "or_poisoned", + "percent-encoding", + "reactive_graph", + "rustc_version", + "send_wrapper", + "tachys", + "thiserror 2.0.18", + "url", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "leptos_router_macro" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "409c0bd99f986c3cfa1a4db2443c835bc602ded1a12784e22ecb28c3ed5a2ae2" +dependencies = [ + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "leptos_server" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf1045af93050bf3388d1c138426393fc131f6d9e46a65519da884c033ed730" +dependencies = [ + "any_spawner", + "base64", + "codee", + "futures", + "hydration_context", + "or_poisoned", + "reactive_graph", + "send_wrapper", + "serde", + "serde_json", + "server_fn", + "tachys", +] + [[package]] name = "levenshtein_automata" version = "0.2.1" @@ -5738,6 +6332,22 @@ version = "0.2.180" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" +[[package]] +name = "libduckdb-sys" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8c60c2d269e63ae5197e4fe9075efffed35dfda0095a5ac8b41f3c765b18456" +dependencies = [ + "flate2", + "pkg-config", + "reqwest", + "serde", + "serde_json", + "tar", + "vcpkg", + "zip", +] + [[package]] name = "libfuzzer-sys" version = "0.4.10" @@ -5804,6 +6414,12 @@ dependencies = [ "bitflags 2.10.0", ] +[[package]] +name = "linear-map" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfae20f6b19ad527b550c223fddc3077a547fc70cda94b9b566575423fd303ee" + [[package]] name = "link-cplusplus" version = "1.0.12" @@ -5973,6 +6589,29 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58093314a45e00c77d5c508f76e77c3396afbbc0d01506e7fae47b018bac2b1d" +[[package]] +name = "manyhow" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b33efb3ca6d3b07393750d4030418d594ab1139cee518f0dc88db70fec873587" +dependencies = [ + "manyhow-macros", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "manyhow-macros" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46fce34d199b78b6e6073abf984c9cf5fd3e9330145a93ee0738a7443e371495" +dependencies = [ + "proc-macro-utils", + "proc-macro2", + "quote", +] + [[package]] name = "matchers" version = "0.2.0" @@ -5982,6 +6621,12 @@ dependencies = [ "regex-automata", ] +[[package]] +name = "matchit" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" + [[package]] name = "matrixmultiply" version = "0.3.10" @@ -6123,6 +6768,23 @@ dependencies = [ "uuid", ] +[[package]] +name = "multer" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83e87776546dc87511aa5ee218730c92b666d7264ab6ed41f9d215af9cd5224b" +dependencies = [ + "bytes", + "encoding_rs", + "futures-util", + "http 1.4.0", + "httparse", + "memchr", + "mime", + "spin", + "version_check", +] + [[package]] name = "multimap" version = "0.10.1" @@ -6195,6 +6857,12 @@ version = "6.6.666" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf5a574dadd7941adeaa71823ecba5e28331b8313fb2e1c6a5c7e5981ea53ad6" +[[package]] +name = "next_tuple" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60993920e071b0c9b66f14e2b32740a4e27ffc82854dcd72035887f336a09a28" + [[package]] name = "nix" version = "0.29.0" @@ -6566,6 +7234,16 @@ dependencies = [ "tokio", ] +[[package]] +name = "oco_ref" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed0423ff9973dea4d6bd075934fdda86ebb8c05bdf9d6b0507067d4a1226371d" +dependencies = [ + "serde", + "thiserror 2.0.18", +] + [[package]] name = "once_cell" version = "1.21.3" @@ -6750,6 +7428,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +[[package]] +name = "or_poisoned" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c04f5d74368e4d0dfe06c45c8627c81bd7c317d52762d118fb9b3076f6420fd" + [[package]] name = "ordered-float" version = "2.10.1" @@ -6958,6 +7642,12 @@ dependencies = [ "stfu8", ] +[[package]] +name = "pathdiff" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" + [[package]] name = "pbkdf2" version = "0.12.2" @@ -7389,6 +8079,17 @@ dependencies = [ "syn 2.0.114", ] +[[package]] +name = "proc-macro-utils" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eeaf08a13de400bc215877b5bdc088f241b12eb42f0a548d3390dc1c56bb7071" +dependencies = [ + "proc-macro2", + "quote", + "smallvec", +] + [[package]] name = "proc-macro2" version = "1.0.106" @@ -7398,6 +8099,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "proc-macro2-diagnostics" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", + "version_check", + "yansi", +] + [[package]] name = "prost" version = "0.12.6" @@ -7710,6 +8424,28 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "quote-use" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9619db1197b497a36178cfc736dc96b271fe918875fbf1344c436a7e93d0321e" +dependencies = [ + "quote", + "quote-use-macros", +] + +[[package]] +name = "quote-use-macros" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82ebfb7faafadc06a7ab141a6f67bcfb24cb8beb158c6fe933f2f035afa99f35" +dependencies = [ + "proc-macro-utils", + "proc-macro2", + "quote", + "syn 2.0.114", +] + [[package]] name = "r-efi" version = "5.3.0" @@ -7962,6 +8698,60 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "reactive_graph" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17f0df355582937223ea403e52490201d65295bd6981383c69bfae5a1f8730c2" +dependencies = [ + "any_spawner", + "async-lock", + "futures", + "guardian", + "hydration_context", + "indexmap", + "or_poisoned", + "paste", + "pin-project-lite", + "rustc-hash", + "rustc_version", + "send_wrapper", + "serde", + "slotmap", + "thiserror 2.0.18", + "web-sys", +] + +[[package]] +name = "reactive_stores" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35372f05664a62a3dd389503371a15b8feb3396f99f6ec000de651fddb030942" +dependencies = [ + "dashmap", + "guardian", + "itertools 0.14.0", + "or_poisoned", + "paste", + "reactive_graph", + "reactive_stores_macro", + "rustc-hash", + "send_wrapper", +] + +[[package]] +name = "reactive_stores_macro" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fa40919eb2975100283b2a70e68eafce1e8bcf81f0622ff168e4c2b3f8d46bb" +dependencies = [ + "convert_case 0.8.0", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.114", +] + [[package]] name = "redox_syscall" version = "0.5.18" @@ -8267,6 +9057,21 @@ dependencies = [ "syn 2.0.114", ] +[[package]] +name = "rstml" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61cf4616de7499fc5164570d40ca4e1b24d231c6833a88bff0fe00725080fd56" +dependencies = [ + "derive-where", + "proc-macro2", + "proc-macro2-diagnostics", + "quote", + "syn 2.0.114", + "syn_derive", + "thiserror 2.0.18", +] + [[package]] name = "rust-ini" version = "0.21.3" @@ -8536,6 +9341,15 @@ version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +[[package]] +name = "send_wrapper" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" +dependencies = [ + "futures-core", +] + [[package]] name = "seq-macro" version = "0.3.6" @@ -8595,6 +9409,28 @@ dependencies = [ "zmij", ] +[[package]] +name = "serde_path_to_error" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" +dependencies = [ + "itoa", + "serde", + "serde_core", +] + +[[package]] +name = "serde_qs" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3faaf9e727533a19351a43cc5a8de957372163c7d35cc48c90b75cdda13c352" +dependencies = [ + "percent-encoding", + "serde", + "thiserror 2.0.18", +] + [[package]] name = "serde_repr" version = "0.1.20" @@ -8636,6 +9472,71 @@ dependencies = [ "serde", ] +[[package]] +name = "server_fn" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353d02fa2886cd8dae0b8da0965289fa8f2ecc7df633d1ce965f62fdf9644d29" +dependencies = [ + "axum", + "base64", + "bytes", + "const-str", + "const_format", + "dashmap", + "futures", + "gloo-net", + "http 1.4.0", + "http-body-util", + "hyper", + "inventory", + "js-sys", + "pin-project-lite", + "rustc_version", + "rustversion", + "send_wrapper", + "serde", + "serde_json", + "serde_qs", + "server_fn_macro_default", + "thiserror 2.0.18", + "throw_error", + "tokio", + "tower", + "tower-layer", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", + "xxhash-rust", +] + +[[package]] +name = "server_fn_macro" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "950b8cfc9ff5f39ca879c5a7c5e640de2695a199e18e424c3289d0964cabe642" +dependencies = [ + "const_format", + "convert_case 0.8.0", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.114", + "xxhash-rust", +] + +[[package]] +name = "server_fn_macro_default" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63eb08f80db903d3c42f64e60ebb3875e0305be502bdc064ec0a0eab42207f00" +dependencies = [ + "server_fn_macro", + "syn 2.0.114", +] + [[package]] name = "sha1" version = "0.10.6" @@ -9025,6 +9926,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn_derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb066a04799e45f5d582e8fc6ec8e6d6896040d00898eb4e6a835196815b219" +dependencies = [ + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.114", +] + [[package]] name = "sync_wrapper" version = "1.0.2" @@ -9104,6 +10017,40 @@ dependencies = [ "testing_table", ] +[[package]] +name = "tachys" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b2db11e455f7e84e2cc3e76f8a3f3843f7956096265d5ecff781eabe235077" +dependencies = [ + "any_spawner", + "async-trait", + "const_str_slice_concat", + "drain_filter_polyfill", + "either_of", + "erased", + "futures", + "html-escape", + "indexmap", + "itertools 0.14.0", + "js-sys", + "linear-map", + "next_tuple", + "oco_ref", + "or_poisoned", + "parking_lot", + "paste", + "reactive_graph", + "reactive_stores", + "rustc-hash", + "rustc_version", + "send_wrapper", + "slotmap", + "throw_error", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "taffy" version = "0.9.2" @@ -9513,6 +10460,15 @@ dependencies = [ "ordered-float 2.10.1", ] +[[package]] +name = "throw_error" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc0ed6038fcbc0795aca7c92963ddda636573b956679204e044492d2b13c8f64" +dependencies = [ + "pin-project-lite", +] + [[package]] name = "time" version = "0.3.45" @@ -9649,6 +10605,18 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-tungstenite" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25a406cddcc431a75d3d9afc6a7c0f7428d4891dd973e4d54c56b46127bf857" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite", +] + [[package]] name = "tokio-util" version = "0.7.18" @@ -9758,6 +10726,7 @@ dependencies = [ "tokio", "tower-layer", "tower-service", + "tracing", ] [[package]] @@ -9774,13 +10743,19 @@ dependencies = [ "http 1.4.0", "http-body 1.0.1", "http-body-util", + "http-range-header", + "httpdate", "iri-string", + "mime", + "mime_guess", + "percent-encoding", "pin-project-lite", "tokio", "tokio-util", "tower", "tower-layer", "tower-service", + "tracing", ] [[package]] @@ -9895,6 +10870,23 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "tungstenite" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442" +dependencies = [ + "bytes", + "data-encoding", + "http 1.4.0", + "httparse", + "log", + "rand 0.9.2", + "sha1", + "thiserror 2.0.18", + "utf-8", +] + [[package]] name = "twox-hash" version = "2.1.2" @@ -9904,6 +10896,46 @@ dependencies = [ "rand 0.9.2", ] +[[package]] +name = "typed-builder" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fef81aec2ca29576f9f6ae8755108640d0a86dd3161b2e8bca6cfa554e98f77d" +dependencies = [ + "typed-builder-macro 0.21.2", +] + +[[package]] +name = "typed-builder" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31aa81521b70f94402501d848ccc0ecaa8f93c8eb6999eb9747e72287757ffda" +dependencies = [ + "typed-builder-macro 0.23.2", +] + +[[package]] +name = "typed-builder-macro" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ecb9ecf7799210407c14a8cfdfe0173365780968dc57973ed082211958e0b18" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "typed-builder-macro" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "076a02dc54dd46795c2e9c8282ed40bcfb1e22747e955de9389a1de28190fb26" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + [[package]] name = "typenum" version = "1.19.0" @@ -10006,6 +11038,12 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + [[package]] name = "utf8-ranges" version = "1.0.5" @@ -11163,6 +12201,28 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wasm_split_helpers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a114b3073258dd5de3d812cdd048cca6842342755e828a14dbf15f843f2d1b84" +dependencies = [ + "async-once-cell", + "wasm_split_macros", +] + +[[package]] +name = "wasm_split_macros" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56481f8ed1a9f9ae97ea7b08a5e2b12e8adf9a7818a6ba952b918e09c7be8bf0" +dependencies = [ + "base16", + "quote", + "sha2", + "syn 2.0.114", +] + [[package]] name = "web-sys" version = "0.3.85" diff --git a/Cargo.toml b/Cargo.toml index 86582a0c114..93e107a0d3b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,6 +52,8 @@ members = [ "benchmarks/datafusion-bench", "benchmarks/duckdb-bench", "benchmarks/random-access-bench", + # Benchmarks Website + "bench-website", ] exclude = ["java/testfiles", "wasm-test"] resolver = "2" diff --git a/REUSE.toml b/REUSE.toml index 46787ae62e2..28ba02515ff 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -26,7 +26,8 @@ SPDX-License-Identifier = "CC-BY-4.0" # Utility code. [[annotations]] -path = ["**/README.md", "CLAUDE.md", "CONTRIBUTING.md", "STYLE.md", "tsc/**.md"] +# TODO(connor): Remove this vvv +path = ["**/README.md", "CLAUDE.md", "CONTRIBUTING.md", "STYLE.md", "tsc/**.md", "BENCHMARK_WEBSITE_REDESIGN.md"] SPDX-FileCopyrightText = "Copyright the Vortex contributors" SPDX-License-Identifier = "CC-BY-4.0" diff --git a/bench-website/Cargo.lock b/bench-website/Cargo.lock new file mode 100644 index 00000000000..596f7a49728 --- /dev/null +++ b/bench-website/Cargo.lock @@ -0,0 +1,4253 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom 0.2.17", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "const-random", + "getrandom 0.3.4", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "any_spawner" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1384d3fe1eecb464229fcf6eebb72306591c56bf27b373561489458a7c73027d" +dependencies = [ + "futures", + "thiserror 2.0.18", + "tokio", + "wasm-bindgen-futures", +] + +[[package]] +name = "anyhow" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" + +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" +dependencies = [ + "derive_arbitrary", +] + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "arrow" +version = "56.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e833808ff2d94ed40d9379848a950d995043c7fb3e81a30b383f4c6033821cc" +dependencies = [ + "arrow-arith", + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-ord", + "arrow-row", + "arrow-schema", + "arrow-select", + "arrow-string", +] + +[[package]] +name = "arrow-arith" +version = "56.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad08897b81588f60ba983e3ca39bda2b179bdd84dced378e7df81a5313802ef8" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "chrono", + "num", +] + +[[package]] +name = "arrow-array" +version = "56.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8548ca7c070d8db9ce7aa43f37393e4bfcf3f2d3681df278490772fd1673d08d" +dependencies = [ + "ahash 0.8.12", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "chrono", + "half", + "hashbrown 0.16.1", + "num", +] + +[[package]] +name = "arrow-buffer" +version = "56.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e003216336f70446457e280807a73899dd822feaf02087d31febca1363e2fccc" +dependencies = [ + "bytes", + "half", + "num", +] + +[[package]] +name = "arrow-cast" +version = "56.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "919418a0681298d3a77d1a315f625916cb5678ad0d74b9c60108eb15fd083023" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", + "atoi", + "base64", + "chrono", + "comfy-table", + "half", + "lexical-core", + "num", + "ryu", +] + +[[package]] +name = "arrow-data" +version = "56.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5c64fff1d142f833d78897a772f2e5b55b36cb3e6320376f0961ab0db7bd6d0" +dependencies = [ + "arrow-buffer", + "arrow-schema", + "half", + "num", +] + +[[package]] +name = "arrow-ord" +version = "56.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c8f82583eb4f8d84d4ee55fd1cb306720cddead7596edce95b50ee418edf66f" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", +] + +[[package]] +name = "arrow-row" +version = "56.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d07ba24522229d9085031df6b94605e0f4b26e099fb7cdeec37abd941a73753" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "half", +] + +[[package]] +name = "arrow-schema" +version = "56.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3aa9e59c611ebc291c28582077ef25c97f1975383f1479b12f3b9ffee2ffabe" +dependencies = [ + "bitflags", +] + +[[package]] +name = "arrow-select" +version = "56.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c41dbbd1e97bfcaee4fcb30e29105fb2c75e4d82ae4de70b792a5d3f66b2e7a" +dependencies = [ + "ahash 0.8.12", + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "num", +] + +[[package]] +name = "arrow-string" +version = "56.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53f5183c150fbc619eede22b861ea7c0eebed8eaac0333eaa7f6da5205fd504d" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", + "memchr", + "num", + "regex", + "regex-syntax", +] + +[[package]] +name = "async-compression" +version = "0.4.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d10e4f991a553474232bc0a31799f6d24b034a84c0971d80d2e2f78b2e576e40" +dependencies = [ + "compression-codecs", + "compression-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "async-lock" +version = "3.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-once-cell" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288f83726785267c6f2ef073a3d83dc3f9b81464e9f99898240cced85fce35a" + +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "attribute-derive" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05832cdddc8f2650cc2cc187cc2e952b8c133a48eb055f35211f61ee81502d77" +dependencies = [ + "attribute-derive-macro", + "derive-where", + "manyhow", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "attribute-derive-macro" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a7cdbbd4bd005c5d3e2e9c885e6fa575db4f4a3572335b974d8db853b6beb61" +dependencies = [ + "collection_literals", + "interpolator", + "manyhow", + "proc-macro-utils", + "proc-macro2", + "quote", + "quote-use", + "syn 2.0.114", +] + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "axum" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8" +dependencies = [ + "axum-core", + "base64", + "bytes", + "form_urlencoded", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "multer", + "percent-encoding", + "pin-project-lite", + "serde_core", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sha1", + "sync_wrapper", + "tokio", + "tokio-tungstenite", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-core" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "sync_wrapper", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "base16" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d27c3610c36aee21ce8ac510e6224498de4228ad772a171ed65643a24693a5a8" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bench-website" +version = "0.1.0" +dependencies = [ + "axum", + "chrono", + "console_error_panic_hook", + "duckdb", + "leptos", + "leptos_axum", + "leptos_meta", + "leptos_router", + "rand 0.9.2", + "serde", + "serde_json", + "thiserror 2.0.18", + "tokio", + "tower", + "tower-http", + "tracing", + "tracing-subscriber", + "wasm-bindgen", +] + +[[package]] +name = "bitflags" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "borsh" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" +dependencies = [ + "borsh-derive", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0686c856aa6aac0c4498f936d7d6a02df690f614c03e4d906d1018062b5c5e2c" +dependencies = [ + "once_cell", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "bumpalo" +version = "3.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" + +[[package]] +name = "bytecheck" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "bytes" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" + +[[package]] +name = "camino" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48" + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "cc" +version = "1.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6354c81bbfd62d9cfa9cb3c773c2b7b2a3a482d569de977fd0e961f6e7c00583" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chrono" +version = "0.4.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "codee" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9dbbdc4b4d349732bc6690de10a9de952bd39ba6a065c586e26600b6b0b91f5" +dependencies = [ + "serde", + "serde_json", + "thiserror 2.0.18", +] + +[[package]] +name = "collection_literals" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2550f75b8cfac212855f6b1885455df8eaee8fe8e246b647d69146142e016084" + +[[package]] +name = "comfy-table" +version = "7.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0d05af1e006a2407bedef5af410552494ce5be9090444dbbcb57258c1af3d56" +dependencies = [ + "strum 0.26.3", + "strum_macros 0.26.4", + "unicode-width", +] + +[[package]] +name = "compression-codecs" +version = "0.4.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00828ba6fd27b45a448e57dbfe84f1029d4c9f26b368157e9a448a5f49a2ec2a" +dependencies = [ + "compression-core", + "flate2", + "memchr", +] + +[[package]] +name = "compression-core" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75984efb6ed102a0d42db99afb6c1948f0380d1d91808d5529916e6c08b49d8d" + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "config" +version = "0.15.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b30fa8254caad766fc03cb0ccae691e14bf3bd72bfff27f72802ce729551b3d6" +dependencies = [ + "convert_case 0.6.0", + "pathdiff", + "serde_core", + "toml", + "winnow", +] + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom 0.2.17", + "once_cell", + "tiny-keccak", +] + +[[package]] +name = "const-str" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0664d2867b4a32697dfe655557f5c3b187e9b605b38612a748e5ec99811d160" + +[[package]] +name = "const_format" +version = "0.2.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7faa7469a93a566e9ccc1c73fe783b4a65c274c5ace346038dca9c39fe0030ad" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "const_str_slice_concat" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f67855af358fcb20fac58f9d714c94e2b228fe5694c1c9b4ead4a366343eda1b" + +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "convert_case" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baaaa0ecca5b51987b9423ccdc971514dd8b0bb7b4060b983d3664dad3f1f89f" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "convert_case" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "dashmap" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "data-encoding" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" + +[[package]] +name = "derive-where" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef941ded77d15ca19b40374869ac6000af1c9f2a4c0f3d4c70926287e6364a8f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "derive_arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "drain_filter_polyfill" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "669a445ee724c5c69b1b06fe0b63e70a1c84bc9bb7d9696cd4f4e3ec45050408" + +[[package]] +name = "duckdb" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7eeb487dde618b9f6ab26a451775ad5fac3fabe1ca2b64cbbe90b105f264ccd" +dependencies = [ + "arrow", + "cast", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libduckdb-sys", + "num-integer", + "rust_decimal", + "strum 0.27.2", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "either_of" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "216d23e0ec69759a17f05e1c553f3a6870e5ec73420fbb07807a6f34d5d1d5a4" +dependencies = [ + "paste", + "pin-project-lite", +] + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "erased" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1731451909bde27714eacba19c2566362a7f35224f52b153d3f42cf60f72472" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "event-listener" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + +[[package]] +name = "filetime" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db" +dependencies = [ + "cfg-if", + "libc", + "libredox", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8591b0bcc8a98a64310a2fae1bb3e9b8564dd10e381e6e28010fde8e8e8568db" + +[[package]] +name = "flate2" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b375d6465b98090a5f25b1c7703f3859783755aa9a80433b36e0379a3ec2f369" +dependencies = [ + "crc32fast", + "miniz_oxide", + "zlib-rs", +] + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", + "num_cpus", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi", + "wasip2", + "wasm-bindgen", +] + +[[package]] +name = "gloo-net" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06f627b1a58ca3d42b45d6104bf1e1a03799df472df00988b6ba21accc10580" +dependencies = [ + "futures-channel", + "futures-core", + "futures-sink", + "gloo-utils", + "http", + "js-sys", + "pin-project", + "serde", + "serde_json", + "thiserror 1.0.69", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "gloo-utils" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5555354113b18c547c1d3a98fbf7fb32a9ff4f6fa112ce823a21641a0ba3aa" +dependencies = [ + "js-sys", + "serde", + "serde_json", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "guardian" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17e2ac29387b1aa07a1e448f7bb4f35b500787971e965b02842b900afa5c8f6f" + +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "num-traits", + "zerocopy", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.8", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "hashlink" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +dependencies = [ + "hashbrown 0.15.5", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "html-escape" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d1ad449764d627e22bfd7cd5e8868264fc9236e07c752972b4080cd351cb476" +dependencies = [ + "utf8-width", +] + +[[package]] +name = "http" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "http-range-header" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9171a2ea8a68358193d15dd5d70c1c10a2afc3e7e4c5bc92bc9f025cebd7359c" + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hydration_context" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8714ae4adeaa846d838f380fbd72f049197de629948f91bf045329e0cf0a283" +dependencies = [ + "futures", + "js-sys", + "once_cell", + "or_poisoned", + "pin-project-lite", + "serde", + "throw_error", + "wasm-bindgen", +] + +[[package]] +name = "hyper" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "pin-utils", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", + "webpki-roots", +] + +[[package]] +name = "hyper-util" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f" +dependencies = [ + "base64", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" + +[[package]] +name = "icu_properties" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" + +[[package]] +name = "icu_provider" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", +] + +[[package]] +name = "interpolator" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71dd52191aae121e8611f1e8dc3e324dd0dd1dee1e6dd91d10ee07a3cfb4d9d8" + +[[package]] +name = "inventory" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc61209c082fbeb19919bee74b176221b27223e27b65d781eb91af24eb1fb46e" +dependencies = [ + "rustversion", +] + +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "iri-string" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "js-sys" +version = "0.3.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "leptos" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f9569fc37575a5d64c0512145af7630bf651007237ef67a8a77328199d315bb" +dependencies = [ + "any_spawner", + "base64", + "cfg-if", + "either_of", + "futures", + "getrandom 0.3.4", + "hydration_context", + "leptos_config", + "leptos_dom", + "leptos_hot_reload", + "leptos_macro", + "leptos_server", + "oco_ref", + "or_poisoned", + "paste", + "rand 0.9.2", + "reactive_graph", + "rustc-hash", + "rustc_version", + "send_wrapper", + "serde", + "serde_json", + "serde_qs", + "server_fn", + "slotmap", + "tachys", + "thiserror 2.0.18", + "throw_error", + "typed-builder 0.23.2", + "typed-builder-macro 0.23.2", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm_split_helpers", + "web-sys", +] + +[[package]] +name = "leptos_axum" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0caa95760f87f3067e05025140becefdbdfd36cbc2adac4519f06e1f1edf4af" +dependencies = [ + "any_spawner", + "axum", + "dashmap", + "futures", + "hydration_context", + "leptos", + "leptos_integration_utils", + "leptos_macro", + "leptos_meta", + "leptos_router", + "parking_lot", + "server_fn", + "tachys", + "tokio", + "tower", + "tower-http", +] + +[[package]] +name = "leptos_config" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071fc40aeb9fcab885965bad1887990477253ad51f926cd19068f45a44c59e89" +dependencies = [ + "config", + "regex", + "serde", + "thiserror 2.0.18", + "typed-builder 0.21.2", +] + +[[package]] +name = "leptos_dom" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78f4330c88694c5575e0bfe4eecf81b045d14e76a4f8b00d5fd2a63f8779f895" +dependencies = [ + "js-sys", + "or_poisoned", + "reactive_graph", + "send_wrapper", + "tachys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "leptos_hot_reload" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d61ec3e1ff8aaee8c5151688550c0363f85bc37845450764c31ff7584a33f38" +dependencies = [ + "anyhow", + "camino", + "indexmap", + "parking_lot", + "proc-macro2", + "quote", + "rstml", + "serde", + "syn 2.0.114", + "walkdir", +] + +[[package]] +name = "leptos_integration_utils" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13cccc9305df53757bae61bf15641bfa6a667b5f78456ace4879dfe0591ae0e8" +dependencies = [ + "futures", + "hydration_context", + "leptos", + "leptos_config", + "leptos_meta", + "leptos_router", + "reactive_graph", +] + +[[package]] +name = "leptos_macro" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c86ffd2e9cf3e264e9b3e16bdb086cefa26bd0fa7bc6a26b0cc5f6c1fd3178ed" +dependencies = [ + "attribute-derive", + "cfg-if", + "convert_case 0.10.0", + "html-escape", + "itertools", + "leptos_hot_reload", + "prettyplease", + "proc-macro-error2", + "proc-macro2", + "quote", + "rstml", + "rustc_version", + "server_fn_macro", + "syn 2.0.114", + "uuid", +] + +[[package]] +name = "leptos_meta" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d489e38d3f541e9e43ecc2e3a815527840345a2afca629b3e23fcc1dd254578" +dependencies = [ + "futures", + "indexmap", + "leptos", + "or_poisoned", + "send_wrapper", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "leptos_router" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01e573711f2fb9ab5d655ec38115220d359eaaf1dcb93cc0ea624543b6dba959" +dependencies = [ + "any_spawner", + "either_of", + "futures", + "gloo-net", + "js-sys", + "leptos", + "leptos_router_macro", + "or_poisoned", + "percent-encoding", + "reactive_graph", + "rustc_version", + "send_wrapper", + "tachys", + "thiserror 2.0.18", + "url", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "leptos_router_macro" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "409c0bd99f986c3cfa1a4db2443c835bc602ded1a12784e22ecb28c3ed5a2ae2" +dependencies = [ + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "leptos_server" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf1045af93050bf3388d1c138426393fc131f6d9e46a65519da884c033ed730" +dependencies = [ + "any_spawner", + "base64", + "codee", + "futures", + "hydration_context", + "or_poisoned", + "reactive_graph", + "send_wrapper", + "serde", + "serde_json", + "server_fn", + "tachys", +] + +[[package]] +name = "lexical-core" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d8d125a277f807e55a77304455eb7b1cb52f2b18c143b60e766c120bd64a594" +dependencies = [ + "lexical-parse-float", + "lexical-parse-integer", + "lexical-util", + "lexical-write-float", + "lexical-write-integer", +] + +[[package]] +name = "lexical-parse-float" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52a9f232fbd6f550bc0137dcb5f99ab674071ac2d690ac69704593cb4abbea56" +dependencies = [ + "lexical-parse-integer", + "lexical-util", +] + +[[package]] +name = "lexical-parse-integer" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a7a039f8fb9c19c996cd7b2fcce303c1b2874fe1aca544edc85c4a5f8489b34" +dependencies = [ + "lexical-util", +] + +[[package]] +name = "lexical-util" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2604dd126bb14f13fb5d1bd6a66155079cb9fa655b37f875b3a742c705dbed17" + +[[package]] +name = "lexical-write-float" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c438c87c013188d415fbabbb1dceb44249ab81664efbd31b14ae55dabb6361" +dependencies = [ + "lexical-util", + "lexical-write-integer", +] + +[[package]] +name = "lexical-write-integer" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "409851a618475d2d5796377cad353802345cba92c867d9fbcde9cf4eac4e14df" +dependencies = [ + "lexical-util", +] + +[[package]] +name = "libc" +version = "0.2.180" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" + +[[package]] +name = "libduckdb-sys" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8c60c2d269e63ae5197e4fe9075efffed35dfda0095a5ac8b41f3c765b18456" +dependencies = [ + "flate2", + "pkg-config", + "reqwest", + "serde", + "serde_json", + "tar", + "vcpkg", + "zip", +] + +[[package]] +name = "libm" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" + +[[package]] +name = "libredox" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" +dependencies = [ + "bitflags", + "libc", + "redox_syscall 0.7.0", +] + +[[package]] +name = "linear-map" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfae20f6b19ad527b550c223fddc3077a547fc70cda94b9b566575423fd303ee" + +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + +[[package]] +name = "litemap" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + +[[package]] +name = "manyhow" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b33efb3ca6d3b07393750d4030418d594ab1139cee518f0dc88db70fec873587" +dependencies = [ + "manyhow-macros", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "manyhow-macros" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46fce34d199b78b6e6073abf984c9cf5fd3e9330145a93ee0738a7443e371495" +dependencies = [ + "proc-macro-utils", + "proc-macro2", + "quote", +] + +[[package]] +name = "matchit" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "multer" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83e87776546dc87511aa5ee218730c92b666d7264ab6ed41f9d215af9cd5224b" +dependencies = [ + "bytes", + "encoding_rs", + "futures-util", + "http", + "httparse", + "memchr", + "mime", + "spin", + "version_check", +] + +[[package]] +name = "next_tuple" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60993920e071b0c9b66f14e2b32740a4e27ffc82854dcd72035887f336a09a28" + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "oco_ref" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed0423ff9973dea4d6bd075934fdda86ebb8c05bdf9d6b0507067d4a1226371d" +dependencies = [ + "serde", + "thiserror 2.0.18", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "or_poisoned" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c04f5d74368e4d0dfe06c45c8627c81bd7c317d52762d118fb9b3076f6420fd" + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.5.18", + "smallvec", + "windows-link", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pathdiff" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "potential_utf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "zerovec", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.114", +] + +[[package]] +name = "proc-macro-crate" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "proc-macro-utils" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eeaf08a13de400bc215877b5bdc088f241b12eb42f0a548d3390dc1c56bb7071" +dependencies = [ + "proc-macro2", + "quote", + "smallvec", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proc-macro2-diagnostics" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", + "version_check", + "yansi", +] + +[[package]] +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "quinn" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror 2.0.18", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" +dependencies = [ + "bytes", + "getrandom 0.3.4", + "lru-slab", + "rand 0.9.2", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.18", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.60.2", +] + +[[package]] +name = "quote" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "quote-use" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9619db1197b497a36178cfc736dc96b271fe918875fbf1344c436a7e93d0321e" +dependencies = [ + "quote", + "quote-use-macros", +] + +[[package]] +name = "quote-use-macros" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82ebfb7faafadc06a7ab141a6f67bcfb24cb8beb158c6fe933f2f035afa99f35" +dependencies = [ + "proc-macro-utils", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "reactive_graph" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17f0df355582937223ea403e52490201d65295bd6981383c69bfae5a1f8730c2" +dependencies = [ + "any_spawner", + "async-lock", + "futures", + "guardian", + "hydration_context", + "indexmap", + "or_poisoned", + "paste", + "pin-project-lite", + "rustc-hash", + "rustc_version", + "send_wrapper", + "serde", + "slotmap", + "thiserror 2.0.18", + "web-sys", +] + +[[package]] +name = "reactive_stores" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35372f05664a62a3dd389503371a15b8feb3396f99f6ec000de651fddb030942" +dependencies = [ + "dashmap", + "guardian", + "itertools", + "or_poisoned", + "paste", + "reactive_graph", + "reactive_stores_macro", + "rustc-hash", + "send_wrapper", +] + +[[package]] +name = "reactive_stores_macro" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fa40919eb2975100283b2a70e68eafce1e8bcf81f0622ff168e4c2b3f8d46bb" +dependencies = [ + "convert_case 0.8.0", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_syscall" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" + +[[package]] +name = "rend" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" +dependencies = [ + "bytecheck", +] + +[[package]] +name = "reqwest" +version = "0.12.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +dependencies = [ + "base64", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rkyv" +version = "0.7.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2297bf9c81a3f0dc96bc9521370b88f054168c29826a75e89c55ff196e7ed6a1" +dependencies = [ + "bitvec", + "bytecheck", + "bytes", + "hashbrown 0.12.3", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84d7b42d4b8d06048d3ac8db0eb31bcb942cbeb709f0b5f2b2ebde398d3038f5" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "rstml" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61cf4616de7499fc5164570d40ca4e1b24d231c6833a88bff0fe00725080fd56" +dependencies = [ + "derive-where", + "proc-macro2", + "proc-macro2-diagnostics", + "quote", + "syn 2.0.114", + "syn_derive", + "thiserror 2.0.18", +] + +[[package]] +name = "rust_decimal" +version = "1.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61f703d19852dbf87cbc513643fa81428361eb6940f1ac14fd58155d295a3eb0" +dependencies = [ + "arrayvec", + "borsh", + "bytes", + "num-traits", + "rand 0.8.5", + "rkyv", + "serde", + "serde_json", +] + +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +dependencies = [ + "web-time", + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "send_wrapper" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" +dependencies = [ + "futures-core", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" +dependencies = [ + "itoa", + "serde", + "serde_core", +] + +[[package]] +name = "serde_qs" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3faaf9e727533a19351a43cc5a8de957372163c7d35cc48c90b75cdda13c352" +dependencies = [ + "percent-encoding", + "serde", + "thiserror 2.0.18", +] + +[[package]] +name = "serde_spanned" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "server_fn" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353d02fa2886cd8dae0b8da0965289fa8f2ecc7df633d1ce965f62fdf9644d29" +dependencies = [ + "axum", + "base64", + "bytes", + "const-str", + "const_format", + "dashmap", + "futures", + "gloo-net", + "http", + "http-body-util", + "hyper", + "inventory", + "js-sys", + "pin-project-lite", + "rustc_version", + "rustversion", + "send_wrapper", + "serde", + "serde_json", + "serde_qs", + "server_fn_macro_default", + "thiserror 2.0.18", + "throw_error", + "tokio", + "tower", + "tower-layer", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", + "xxhash-rust", +] + +[[package]] +name = "server_fn_macro" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "950b8cfc9ff5f39ca879c5a7c5e640de2695a199e18e424c3289d0964cabe642" +dependencies = [ + "const_format", + "convert_case 0.8.0", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.114", + "xxhash-rust", +] + +[[package]] +name = "server_fn_macro_default" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63eb08f80db903d3c42f64e60ebb3875e0305be502bdc064ec0a0eab42207f00" +dependencies = [ + "server_fn_macro", + "syn 2.0.114", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "simd-adler32" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "slab" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" + +[[package]] +name = "slotmap" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038" +dependencies = [ + "version_check", +] + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "socket2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" + +[[package]] +name = "strum" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" +dependencies = [ + "strum_macros 0.27.2", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.114", +] + +[[package]] +name = "strum_macros" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn_derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb066a04799e45f5d582e8fc6ec8e6d6896040d00898eb4e6a835196815b219" +dependencies = [ + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "tachys" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b2db11e455f7e84e2cc3e76f8a3f3843f7956096265d5ecff781eabe235077" +dependencies = [ + "any_spawner", + "async-trait", + "const_str_slice_concat", + "drain_filter_polyfill", + "either_of", + "erased", + "futures", + "html-escape", + "indexmap", + "itertools", + "js-sys", + "linear-map", + "next_tuple", + "oco_ref", + "or_poisoned", + "parking_lot", + "paste", + "reactive_graph", + "reactive_stores", + "rustc-hash", + "rustc_version", + "send_wrapper", + "slotmap", + "throw_error", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tar" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl 2.0.18", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "throw_error" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc0ed6038fcbc0795aca7c92963ddda636573b956679204e044492d2b13c8f64" +dependencies = [ + "pin-project-lite", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinystr" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.49.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" +dependencies = [ + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25a406cddcc431a75d3d9afc6a7c0f7428d4891dd973e4d54c56b46127bf857" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite", +] + +[[package]] +name = "tokio-util" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.9.11+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3afc9a848309fe1aaffaed6e1546a7a14de1f935dc9d89d32afd9a44bab7c46" +dependencies = [ + "serde_core", + "serde_spanned", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.23.10+spec-1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.6+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" +dependencies = [ + "winnow", +] + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" +dependencies = [ + "async-compression", + "bitflags", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "http-range-header", + "httpdate", + "iri-string", + "mime", + "mime_guess", + "percent-encoding", + "pin-project-lite", + "tokio", + "tokio-util", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" +dependencies = [ + "nu-ansi-term", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "tungstenite" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442" +dependencies = [ + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand 0.9.2", + "sha1", + "thiserror 2.0.18", + "utf-8", +] + +[[package]] +name = "typed-builder" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fef81aec2ca29576f9f6ae8755108640d0a86dd3161b2e8bca6cfa554e98f77d" +dependencies = [ + "typed-builder-macro 0.21.2", +] + +[[package]] +name = "typed-builder" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31aa81521b70f94402501d848ccc0ecaa8f93c8eb6999eb9747e72287757ffda" +dependencies = [ + "typed-builder-macro 0.23.2", +] + +[[package]] +name = "typed-builder-macro" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ecb9ecf7799210407c14a8cfdfe0173365780968dc57973ed082211958e0b18" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "typed-builder-macro" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "076a02dc54dd46795c2e9c8282ed40bcfb1e22747e955de9389a1de28190fb26" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "unicase" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "utf8-width" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1292c0d970b54115d14f2492fe0170adf21d68a1de108eebc51c1df4f346a091" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "uuid" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" +dependencies = [ + "getrandom 0.3.4", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f" +dependencies = [ + "cfg-if", + "futures-util", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.114", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-streams" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wasm_split_helpers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a114b3073258dd5de3d812cdd048cca6842342755e828a14dbf15f843f2d1b84" +dependencies = [ + "async-once-cell", + "wasm_split_macros", +] + +[[package]] +name = "wasm_split_macros" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56481f8ed1a9f9ae97ea7b08a5e2b12e8adf9a7818a6ba952b918e09c7be8bf0" +dependencies = [ + "base16", + "quote", + "sha2", + "syn 2.0.114", +] + +[[package]] +name = "web-sys" +version = "0.3.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12bed680863276c63889429bfd6cab3b99943659923822de1c8a39c49e4d722c" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "winnow" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" + +[[package]] +name = "writeable" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "xattr" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" +dependencies = [ + "libc", + "rustix", +] + +[[package]] +name = "xxhash-rust" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" + +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + +[[package]] +name = "yoke" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "668f5168d10b9ee831de31933dc111a459c97ec93225beb307aed970d1372dfd" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c7962b26b0a8685668b671ee4b54d007a67d4eaf05fda79ac0ecf41e32270f1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zerotrie" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "zip" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb2a05c7c36fde6c09b08576c9f7fb4cda705990f73b58fe011abf7dfb24168b" +dependencies = [ + "arbitrary", + "crc32fast", + "flate2", + "indexmap", + "memchr", + "zopfli", +] + +[[package]] +name = "zlib-rs" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40990edd51aae2c2b6907af74ffb635029d5788228222c4bb811e9351c0caad3" + +[[package]] +name = "zmij" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfcd145825aace48cff44a8844de64bf75feec3080e0aa5cdbde72961ae51a65" + +[[package]] +name = "zopfli" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249" +dependencies = [ + "bumpalo", + "crc32fast", + "log", + "simd-adler32", +] diff --git a/bench-website/Cargo.toml b/bench-website/Cargo.toml new file mode 100644 index 00000000000..e2d2c4eea06 --- /dev/null +++ b/bench-website/Cargo.toml @@ -0,0 +1,78 @@ +[package] +name = "bench-website" +version = "0.1.0" +edition = "2024" +rust-version = "1.89" +publish = false + +[lib] +crate-type = ["cdylib", "rlib"] + +[[bin]] +name = "bench-website" +path = "src/main.rs" + +[dependencies] +# Leptos core +leptos = { version = "0.8", features = ["nightly"] } +leptos_axum = { version = "0.8", optional = true } +leptos_router = { version = "0.8" } +leptos_meta = { version = "0.8" } + +# Backend +axum = { version = "0.8", optional = true } +tokio = { version = "1", features = ["full"], optional = true } +tower = { version = "0.5", optional = true } +tower-http = { version = "0.6", features = ["fs", "compression-gzip"], optional = true } + +# Database +duckdb = { version = "1", optional = true } + +# Serialization +serde = { version = "1", features = ["derive"] } +serde_json = "1" + +# Utilities +chrono = { version = "0.4", features = ["serde"] } +rand = "0.9" +thiserror = "2" +tracing = "0.1" +tracing-subscriber = { version = "0.3", optional = true } + +# WASM +wasm-bindgen = { version = "0.2", optional = true } +console_error_panic_hook = { version = "0.1", optional = true } + +[features] +default = ["ssr"] +ssr = [ + "leptos/ssr", + "dep:leptos_axum", + "dep:axum", + "dep:tokio", + "dep:tower", + "dep:tower-http", + "dep:duckdb", + "dep:tracing-subscriber", +] +hydrate = [ + "leptos/hydrate", + "dep:wasm-bindgen", + "dep:console_error_panic_hook", +] + +[package.metadata.leptos] +output-name = "bench-website" +site-root = "target/site" +site-pkg-dir = "pkg" +style-file = "style/main.css" +assets-dir = "public" +site-addr = "127.0.0.1:3000" +reload-port = 3001 +browserquery = "defaults" +watch = false +env = "DEV" +bin-features = ["ssr"] +bin-default-features = false +lib-features = ["hydrate"] +lib-default-features = false diff --git a/bench-website/src/components/app.rs b/bench-website/src/components/app.rs new file mode 100644 index 00000000000..27b1a877d19 --- /dev/null +++ b/bench-website/src/components/app.rs @@ -0,0 +1,47 @@ +use leptos::prelude::*; +use leptos_meta::Meta; +use leptos_meta::Title; +use leptos_meta::provide_meta_context; +use leptos_router::components::Route; +use leptos_router::components::Router; +use leptos_router::components::Routes; +use leptos_router::path; + +use crate::components::HomePage; + +#[component] +pub fn App() -> impl IntoView { + provide_meta_context(); + + view! { + + <Meta name="description" content="Performance benchmarks for Vortex columnar file format"/> + + <Router> + <main class="min-h-screen bg-gray-100"> + <nav class="bg-gray-900 text-white p-4 shadow-lg"> + <div class="container mx-auto flex items-center justify-between"> + <a href="/" class="text-xl font-bold hover:text-gray-300 transition-colors"> + "Vortex Benchmarks" + </a> + <a + href="https://github.com/spiraldb/vortex" + target="_blank" + rel="noopener noreferrer" + class="text-gray-300 hover:text-white transition-colors" + > + "GitHub" + </a> + </div> + </nav> + <Routes fallback=|| view! { + <div class="container mx-auto py-8 px-4"> + <h1 class="text-2xl font-bold text-gray-800">"Page not found"</h1> + </div> + }> + <Route path=path!("/") view=HomePage /> + </Routes> + </main> + </Router> + } +} diff --git a/bench-website/src/components/chart/mod.rs b/bench-website/src/components/chart/mod.rs new file mode 100644 index 00000000000..65613a9ccbf --- /dev/null +++ b/bench-website/src/components/chart/mod.rs @@ -0,0 +1,166 @@ +//! SVG chart component for rendering benchmark data. +//! +//! This module provides a server-side rendered SVG chart component. +//! For Phase 1, charts are static. Phase 2 will add interactivity +//! via the Plotters Canvas backend. +//! +//! # Submodules +//! +//! - [`scales`]: Coordinate transformation functions +//! - [`paths`]: SVG path data generation +//! - [`ticks`]: Axis tick mark computation + +pub mod paths; +pub mod scales; +pub mod ticks; + +use leptos::prelude::*; + +use self::paths::generate_series_paths; +use self::scales::HEIGHT; +use self::scales::PADDING; +use self::scales::WIDTH; +use self::ticks::compute_x_ticks; +use self::ticks::compute_y_ticks; +use crate::db::ChartData; + +/// Renders an SVG line chart for benchmark data. +/// +/// Displays multiple series as colored lines with a legend. +/// Axes show time values (Y) and commit dates (X). +#[component] +pub fn Chart(data: ChartData) -> impl IntoView { + let (y_min, y_max) = data.y_range(); + let x_max = data.commits.len() as f64; + + // Generate chart data using helper modules + let paths = generate_series_paths(&data.series, x_max, y_min, y_max); + let y_ticks = compute_y_ticks(y_min, y_max, 5); + let x_ticks = compute_x_ticks(&data.commits, 5); + + let title = data.title.clone(); + let unit = data.unit.clone(); + + view! { + <div class="chart-container bg-white rounded-lg shadow-md p-4 mb-6"> + <h3 class="text-lg font-semibold text-gray-800 mb-4">{title}</h3> + <svg + width=WIDTH.to_string() + height=HEIGHT.to_string() + class="chart-svg" + viewBox=format!("0 0 {} {}", WIDTH, HEIGHT) + > + // Background + <rect + x="0" y="0" + width=WIDTH.to_string() + height=HEIGHT.to_string() + fill="#f9fafb" + /> + + // Grid lines + {y_ticks.iter().map(|tick| { + view! { + <line + x1=PADDING.to_string() + y1=tick.position.to_string() + x2=(WIDTH - PADDING).to_string() + y2=tick.position.to_string() + stroke="#e5e7eb" + stroke-width="1" + /> + } + }).collect_view()} + + // Y-axis + <line + x1=PADDING.to_string() + y1=PADDING.to_string() + x2=PADDING.to_string() + y2=(HEIGHT - PADDING).to_string() + stroke="#9ca3af" + stroke-width="1" + /> + + // X-axis + <line + x1=PADDING.to_string() + y1=(HEIGHT - PADDING).to_string() + x2=(WIDTH - PADDING).to_string() + y2=(HEIGHT - PADDING).to_string() + stroke="#9ca3af" + stroke-width="1" + /> + + // Y-axis labels + {y_ticks.iter().map(|tick| { + view! { + <text + x=(PADDING - 8.0).to_string() + y=tick.position.to_string() + text-anchor="end" + dominant-baseline="middle" + style="font-size: 10px; fill: #6b7280" + > + {tick.label.clone()} + </text> + } + }).collect_view()} + + // Y-axis title + <text + x="15" + y=(HEIGHT / 2.0).to_string() + transform=format!("rotate(-90, 15, {})", HEIGHT / 2.0) + text-anchor="middle" + style="font-size: 12px; fill: #4b5563" + > + {format!("Time ({})", unit)} + </text> + + // X-axis tick labels + {x_ticks.iter().map(|tick| { + view! { + <text + x=tick.position.to_string() + y=(HEIGHT - PADDING + 15.0).to_string() + text-anchor="middle" + style="font-size: 10px; fill: #6b7280" + > + {tick.label.clone()} + </text> + } + }).collect_view()} + + // Series lines + {paths.iter().map(|p| { + view! { + <path + d=p.path_d.clone() + stroke=p.color.clone() + stroke-width="2" + fill="none" + /> + } + }).collect_view()} + </svg> + + // Legend + <div class="flex gap-6 mt-4 justify-center"> + {data.series.iter().map(|s| { + let color = s.color.clone(); + let name = s.display_name.clone(); + view! { + <div class="flex items-center gap-2"> + <div + class="w-4 h-3 rounded-sm" + style=format!("background-color: {}", color) + ></div> + <span class="text-sm text-gray-700">{name}</span> + </div> + } + }).collect_view()} + </div> + </div> + } +} diff --git a/bench-website/src/components/chart/paths.rs b/bench-website/src/components/chart/paths.rs new file mode 100644 index 00000000000..23d62099037 --- /dev/null +++ b/bench-website/src/components/chart/paths.rs @@ -0,0 +1,61 @@ +//! SVG path generation for chart series. + +use super::scales::scale_x; +use super::scales::scale_y; +use crate::db::Series; + +/// A rendered series path ready for SVG output. +pub struct SeriesPath { + /// CSS color value (e.g., "#19a508"). + pub color: String, + /// SVG path data string (e.g., "M 60 200 L 70 195 L 80 198"). + pub path_d: String, +} + +/// Generates SVG path data for all series. +/// +/// # Arguments +/// * `series` - The series data to render +/// * `x_max` - Total number of commits (for X scaling) +/// * `y_min` - Minimum Y value (for Y scaling) +/// * `y_max` - Maximum Y value (for Y scaling) +pub fn generate_series_paths( + series: &[Series], + x_max: f64, + y_min: f64, + y_max: f64, +) -> Vec<SeriesPath> { + series + .iter() + .map(|s| { + let points: Vec<(f64, f64)> = s + .points + .iter() + .map(|p| { + ( + scale_x(p.commit_idx, x_max), + scale_y(p.value_ms(), y_min, y_max), + ) + }) + .collect(); + + let path_d = points + .iter() + .enumerate() + .map(|(i, (x, y))| { + if i == 0 { + format!("M {} {}", x, y) + } else { + format!("L {} {}", x, y) + } + }) + .collect::<Vec<_>>() + .join(" "); + + SeriesPath { + color: s.color.clone(), + path_d, + } + }) + .collect() +} diff --git a/bench-website/src/components/chart/scales.rs b/bench-website/src/components/chart/scales.rs new file mode 100644 index 00000000000..2e89a17fce8 --- /dev/null +++ b/bench-website/src/components/chart/scales.rs @@ -0,0 +1,40 @@ +//! Coordinate scaling functions for chart rendering. +//! +//! These functions transform data coordinates to SVG pixel coordinates. + +/// Chart dimension constants. +pub const WIDTH: f64 = 800.0; +pub const HEIGHT: f64 = 400.0; +pub const PADDING: f64 = 60.0; + +/// Returns the usable chart width (total width minus padding on both sides). +pub fn chart_width() -> f64 { + WIDTH - 2.0 * PADDING +} + +/// Returns the usable chart height (total height minus padding on both sides). +pub fn chart_height() -> f64 { + HEIGHT - 2.0 * PADDING +} + +/// Transforms a commit index to an X pixel coordinate. +/// +/// # Arguments +/// * `idx` - The commit index (0-based) +/// * `x_max` - The total number of commits +pub fn scale_x(idx: usize, x_max: f64) -> f64 { + PADDING + (idx as f64 / x_max) * chart_width() +} + +/// Transforms a data value to a Y pixel coordinate. +/// +/// Note: SVG Y coordinates increase downward, so this inverts the value +/// to place higher values at the top of the chart. +/// +/// # Arguments +/// * `val` - The data value (e.g., milliseconds) +/// * `y_min` - The minimum Y value in the data range +/// * `y_max` - The maximum Y value in the data range +pub fn scale_y(val: f64, y_min: f64, y_max: f64) -> f64 { + HEIGHT - PADDING - ((val - y_min) / (y_max - y_min)) * chart_height() +} diff --git a/bench-website/src/components/chart/ticks.rs b/bench-website/src/components/chart/ticks.rs new file mode 100644 index 00000000000..7cdaa014ddb --- /dev/null +++ b/bench-website/src/components/chart/ticks.rs @@ -0,0 +1,53 @@ +//! Axis tick mark computation for charts. + +use super::scales::scale_x; +use super::scales::scale_y; +use crate::db::CommitInfo; + +/// A tick mark with its pixel position and label text. +pub struct Tick { + /// Pixel coordinate (X for x-ticks, Y for y-ticks). + pub position: f64, + /// Human-readable label. + pub label: String, +} + +/// Computes Y-axis tick marks with evenly spaced values. +/// +/// # Arguments +/// * `y_min` - Minimum Y value +/// * `y_max` - Maximum Y value +/// * `count` - Number of tick marks (not including endpoints adds 1) +pub fn compute_y_ticks(y_min: f64, y_max: f64, count: usize) -> Vec<Tick> { + (0..=count) + .map(|i| { + let val = y_min + (y_max - y_min) * (i as f64 / count as f64); + Tick { + position: scale_y(val, y_min, y_max), + label: format!("{:.0}", val), + } + }) + .collect() +} + +/// Computes X-axis tick marks at evenly spaced commit intervals. +/// +/// Returns tick marks with date labels (MM/DD format). +/// +/// # Arguments +/// * `commits` - The commit data (for timestamps) +/// * `count` - Number of tick marks +pub fn compute_x_ticks(commits: &[CommitInfo], count: usize) -> Vec<Tick> { + let commit_count = commits.len(); + let x_max = commit_count as f64; + + (0..=count) + .filter_map(|i| { + let idx = (i * commit_count.saturating_sub(1)) / count; + commits.get(idx).map(|c| Tick { + position: scale_x(idx, x_max), + label: c.timestamp.format("%m/%d").to_string(), + }) + }) + .collect() +} diff --git a/bench-website/src/components/home.rs b/bench-website/src/components/home.rs new file mode 100644 index 00000000000..e4f8b1e6265 --- /dev/null +++ b/bench-website/src/components/home.rs @@ -0,0 +1,43 @@ +use leptos::prelude::*; + +use crate::components::Chart; +use crate::db::ChartData; + +#[component] +pub fn HomePage() -> impl IntoView { + // Server-side resource to fetch chart data + let chart_data = Resource::new(|| (), |_| get_chart_data()); + + view! { + <div class="container mx-auto py-8 px-4"> + <h1 class="text-3xl font-bold text-gray-900 mb-8"> + "Benchmark Results" + </h1> + + <Suspense fallback=move || view! { + <div class="animate-pulse bg-gray-200 rounded-lg h-96 w-full"></div> + }> + {move || Suspend::new(async move { + match chart_data.await { + Ok(data) => view! { <Chart data=data /> }.into_any(), + Err(e) => view! { + <div class="text-red-600 p-4 bg-red-50 rounded-lg"> + {format!("Error loading data: {}", e)} + </div> + }.into_any(), + } + })} + </Suspense> + </div> + } +} + +/// Server function to fetch chart data from DuckDB. +#[server(GetChartData)] +async fn get_chart_data() -> Result<ChartData, ServerFnError> { + use crate::db::DbPool; + use crate::db::get_random_access_data; + + let db = expect_context::<DbPool>(); + get_random_access_data(&db, 50).map_err(|e| ServerFnError::new(e.to_string())) +} diff --git a/bench-website/src/components/mod.rs b/bench-website/src/components/mod.rs new file mode 100644 index 00000000000..191e997caf3 --- /dev/null +++ b/bench-website/src/components/mod.rs @@ -0,0 +1,7 @@ +mod app; +mod chart; +mod home; + +pub use app::App; +pub use chart::Chart; +pub use home::HomePage; diff --git a/bench-website/src/db/connection.rs b/bench-website/src/db/connection.rs new file mode 100644 index 00000000000..748d8532239 --- /dev/null +++ b/bench-website/src/db/connection.rs @@ -0,0 +1,111 @@ +// Allow std::sync::Mutex for this standalone prototype (no parking_lot dependency) +#![allow(clippy::disallowed_types)] + +//! DuckDB connection management. +//! +//! While DuckDB supports concurrent operations at the database level, the Rust +//! `Connection` type uses `RefCell` internally (for statement caching) which +//! is not `Sync`. To share the connection across Leptos async contexts, we +//! wrap it in a `Mutex`. +//! +//! For this prototype with light load, this is sufficient. For production, +//! consider using a connection pool or multiple connections. + +use std::sync::Arc; +use std::sync::Mutex; + +use duckdb::Connection; +use duckdb::Result as DuckResult; + +/// Shared DuckDB connection for Leptos server functions. +/// +/// Uses `Arc<Mutex<Connection>>` because: +/// - `Arc` allows cheap cloning for sharing across contexts +/// - `Mutex` is required because `Connection` contains `RefCell` (not `Sync`) +/// +/// # Example +/// +/// ```ignore +/// let db = DbPool::new_with_mock_data()?; +/// let data = db.query(|conn| { +/// // Use conn to execute queries +/// })?; +/// ``` +#[derive(Clone)] +pub struct DbPool { + conn: Arc<Mutex<Connection>>, +} + +impl DbPool { + /// Creates a new in-memory DuckDB database with the benchmark schema. + /// + /// The schema includes: + /// - `commits` table for git commit metadata + /// - `random_access` table for benchmark results + pub fn new_in_memory() -> DuckResult<Self> { + let conn = Connection::open_in_memory()?; + Self::init_schema(&conn)?; + Ok(Self { + conn: Arc::new(Mutex::new(conn)), + }) + } + + /// Creates a new database populated with mock benchmark data. + /// + /// Useful for development and testing. Generates 100 commits over 100 days + /// with realistic benchmark patterns including gradual improvements and + /// occasional regressions. + pub fn new_with_mock_data() -> DuckResult<Self> { + let pool = Self::new_in_memory()?; + crate::mock_data::populate_mock_data(&pool)?; + Ok(pool) + } + + /// Initializes the database schema. + fn init_schema(conn: &Connection) -> DuckResult<()> { + conn.execute_batch( + r#" + CREATE TABLE IF NOT EXISTS commits ( + commit_hash VARCHAR PRIMARY KEY, + timestamp TIMESTAMP NOT NULL, + message VARCHAR, + author VARCHAR + ); + + CREATE INDEX IF NOT EXISTS idx_commits_timestamp + ON commits(timestamp DESC); + + CREATE TABLE IF NOT EXISTS random_access ( + commit_hash VARCHAR NOT NULL REFERENCES commits(commit_hash), + vortex_ns UBIGINT, + parquet_ns UBIGINT, + lance_ns UBIGINT, + PRIMARY KEY (commit_hash) + ); + "#, + )?; + Ok(()) + } + + /// Executes a read query against the database. + /// + /// Acquires the mutex lock for the duration of the closure. + pub fn query<T, F>(&self, f: F) -> DuckResult<T> + where + F: FnOnce(&Connection) -> DuckResult<T>, + { + let conn = self.conn.lock().expect("connection lock poisoned"); + f(&conn) + } + + /// Executes a write operation against the database. + /// + /// Acquires the mutex lock for the duration of the closure. + pub fn execute<F>(&self, f: F) -> DuckResult<()> + where + F: FnOnce(&Connection) -> DuckResult<()>, + { + let conn = self.conn.lock().expect("connection lock poisoned"); + f(&conn) + } +} diff --git a/bench-website/src/db/mod.rs b/bench-website/src/db/mod.rs new file mode 100644 index 00000000000..76bd0845c33 --- /dev/null +++ b/bench-website/src/db/mod.rs @@ -0,0 +1,14 @@ +//! Database layer for benchmark data storage and retrieval. +//! +//! This module provides: +//! - [`DbPool`]: Thread-safe DuckDB connection wrapper +//! - Data models ([`ChartData`], [`Series`], [`CommitInfo`], [`DataPoint`]) +//! - Query functions for fetching benchmark results + +mod connection; +mod models; +mod queries; + +pub use connection::DbPool; +pub use models::*; +pub use queries::*; diff --git a/bench-website/src/db/models.rs b/bench-website/src/db/models.rs new file mode 100644 index 00000000000..926f4a19cae --- /dev/null +++ b/bench-website/src/db/models.rs @@ -0,0 +1,59 @@ +use chrono::DateTime; +use chrono::Utc; +use serde::Deserialize; +use serde::Serialize; + +/// Git commit metadata. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct CommitInfo { + pub hash: String, + pub timestamp: DateTime<Utc>, + pub message: Option<String>, + pub author: Option<String>, +} + +/// A single data point on a chart. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct DataPoint { + pub commit_idx: usize, + pub value_ns: u64, +} + +impl DataPoint { + pub fn value_ms(&self) -> f64 { + self.value_ns as f64 / 1_000_000.0 + } +} + +/// A series of data points for one benchmark target. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Series { + pub name: String, + pub display_name: String, + pub color: String, + pub points: Vec<DataPoint>, +} + +/// Complete chart data for rendering a benchmark chart. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct ChartData { + pub title: String, + pub commits: Vec<CommitInfo>, + pub series: Vec<Series>, + pub unit: String, +} + +impl ChartData { + /// Find min/max Y values across all series (in ms). + pub fn y_range(&self) -> (f64, f64) { + let values: Vec<f64> = self + .series + .iter() + .flat_map(|s| s.points.iter().map(|p| p.value_ms())) + .collect(); + + let min = values.iter().copied().fold(f64::INFINITY, f64::min); + let max = values.iter().copied().fold(0.0, f64::max); + (min.min(0.0), max * 1.1) // Start at 0, add 10% headroom + } +} diff --git a/bench-website/src/db/queries.rs b/bench-website/src/db/queries.rs new file mode 100644 index 00000000000..99724ca7802 --- /dev/null +++ b/bench-website/src/db/queries.rs @@ -0,0 +1,143 @@ +// Allow std::collections::HashMap for this standalone prototype +#![allow(clippy::disallowed_types)] + +//! Query functions for fetching benchmark data from DuckDB. +//! +//! # Timestamp Handling +//! +//! DuckDB's timestamp type doesn't map directly to chrono types via the Rust +//! bindings. We work around this by casting timestamps to VARCHAR in SQL and +//! parsing them back to `DateTime<Utc>` in Rust. + +use std::collections::HashMap; + +use chrono::DateTime; +use chrono::NaiveDateTime; +use chrono::Utc; +use duckdb::Result as DuckResult; + +use super::DbPool; +use super::models::ChartData; +use super::models::CommitInfo; +use super::models::DataPoint; +use super::models::Series; + +/// Fetches random_access benchmark data for the most recent N commits. +/// +/// Returns a [`ChartData`] struct ready for rendering, with commits ordered +/// oldest-first (for left-to-right chart display) and series data for +/// Vortex, Parquet, and Lance. +pub fn get_random_access_data(db: &DbPool, limit: usize) -> DuckResult<ChartData> { + db.query(|conn| { + // First get commits (ordered newest first, then reversed for display) + // Cast timestamp to string for portable reading + let mut commits_stmt = conn.prepare( + r#" + SELECT commit_hash, CAST(timestamp AS VARCHAR), message, author + FROM commits + ORDER BY timestamp DESC + LIMIT ? + "#, + )?; + + let commits: Vec<CommitInfo> = commits_stmt + .query_map([limit], |row| { + Ok(CommitInfo { + hash: row.get(0)?, + timestamp: { + let ts_str: String = row.get(1)?; + // Parse the timestamp string + NaiveDateTime::parse_from_str(&ts_str, "%Y-%m-%d %H:%M:%S") + .map(|ts| DateTime::from_naive_utc_and_offset(ts, Utc)) + .unwrap_or_else(|_| Utc::now()) + }, + message: row.get(2)?, + author: row.get(3)?, + }) + })? + .collect::<Result<Vec<_>, _>>()?; + + // Reverse to get oldest-first for charting + let commits: Vec<_> = commits.into_iter().rev().collect(); + + // Create commit hash -> index map + let hash_to_idx: HashMap<String, usize> = commits + .iter() + .enumerate() + .map(|(i, c)| (c.hash.clone(), i)) + .collect(); + + // Fetch benchmark data + let mut bench_stmt = conn.prepare( + r#" + SELECT r.commit_hash, r.vortex_ns, r.parquet_ns, r.lance_ns + FROM random_access r + JOIN commits c ON r.commit_hash = c.commit_hash + ORDER BY c.timestamp DESC + LIMIT ? + "#, + )?; + + let mut vortex_points = Vec::new(); + let mut parquet_points = Vec::new(); + let mut lance_points = Vec::new(); + + let rows = bench_stmt.query_map([limit], |row| { + let hash: String = row.get(0)?; + let vortex: Option<u64> = row.get(1)?; + let parquet: Option<u64> = row.get(2)?; + let lance: Option<u64> = row.get(3)?; + Ok((hash, vortex, parquet, lance)) + })?; + + for row in rows { + let (hash, vortex, parquet, lance) = row?; + if let Some(&idx) = hash_to_idx.get(&hash) { + if let Some(v) = vortex { + vortex_points.push(DataPoint { + commit_idx: idx, + value_ns: v, + }); + } + if let Some(v) = parquet { + parquet_points.push(DataPoint { + commit_idx: idx, + value_ns: v, + }); + } + if let Some(v) = lance { + lance_points.push(DataPoint { + commit_idx: idx, + value_ns: v, + }); + } + } + } + + Ok(ChartData { + title: "Random Access".to_string(), + commits, + series: vec![ + Series { + name: "vortex".to_string(), + display_name: "Vortex".to_string(), + color: "#19a508".to_string(), + points: vortex_points, + }, + Series { + name: "parquet".to_string(), + display_name: "Parquet".to_string(), + color: "#ef7f1d".to_string(), + points: parquet_points, + }, + Series { + name: "lance".to_string(), + display_name: "Lance".to_string(), + color: "#2D936C".to_string(), + points: lance_points, + }, + ], + unit: "ms".to_string(), + }) + }) +} diff --git a/bench-website/src/lib.rs b/bench-website/src/lib.rs new file mode 100644 index 00000000000..cac53982ff9 --- /dev/null +++ b/bench-website/src/lib.rs @@ -0,0 +1,12 @@ +pub mod components; +pub mod db; +pub mod mock_data; + +pub use components::App; + +#[cfg(feature = "hydrate")] +#[wasm_bindgen::prelude::wasm_bindgen] +pub fn hydrate() { + console_error_panic_hook::set_once(); + leptos::mount::hydrate_body(App); +} diff --git a/bench-website/src/main.rs b/bench-website/src/main.rs new file mode 100644 index 00000000000..b2f5893c487 --- /dev/null +++ b/bench-website/src/main.rs @@ -0,0 +1,154 @@ +#[cfg(feature = "ssr")] +#[tokio::main] +async fn main() { + use std::net::SocketAddr; + + use axum::Router; + use bench_website::App; + use bench_website::db::DbPool; + use leptos::config::LeptosOptions; + use leptos::prelude::*; + use leptos_axum::LeptosRoutes; + use leptos_axum::generate_route_list; + use tokio::net::TcpListener; + + tracing_subscriber::fmt::init(); + + // Initialize database with mock data + let db = DbPool::new_with_mock_data().expect("Failed to initialize database"); + + // Build Leptos configuration manually (works from any directory) + let addr: SocketAddr = "127.0.0.1:3000".parse().unwrap(); + let leptos_options = LeptosOptions::builder() + .output_name("bench-website") + .site_root("target/site") + .site_pkg_dir("pkg") + .site_addr(addr) + .reload_port(3001) + .build(); + let routes = generate_route_list(App); + + // Build router with Leptos routes + let app = Router::new() + .leptos_routes_with_context( + &leptos_options, + routes, + { + let db = db.clone(); + move || provide_context(db.clone()) + }, + { + let leptos_options = leptos_options.clone(); + move || shell(leptos_options.clone()) + }, + ) + .with_state(leptos_options); + + let listener = TcpListener::bind(&addr).await.unwrap(); + tracing::info!("Listening on http://{}", addr); + axum::serve(listener, app.into_make_service()) + .await + .unwrap(); +} + +#[cfg(feature = "ssr")] +fn shell(options: leptos::config::LeptosOptions) -> impl leptos::prelude::IntoView { + use bench_website::App; + use leptos::prelude::*; + use leptos_meta::MetaTags; + + view! { + <!DOCTYPE html> + <html lang="en"> + <head> + <meta charset="utf-8"/> + <meta name="viewport" content="width=device-width, initial-scale=1"/> + <AutoReload options=options.clone()/> + <HydrationScripts options/> + <MetaTags/> + <style>{INLINE_CSS}</style> + </head> + <body> + <App/> + </body> + </html> + } +} + +/// Minimal Tailwind-style utility classes for Phase 1 prototype. +/// Phase 2 will use proper Tailwind CSS with PostCSS. +#[cfg(feature = "ssr")] +const INLINE_CSS: &str = r#" +/* === Reset & Base === */ +* { box-sizing: border-box; margin: 0; padding: 0; } +body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.5; color: #1f2937; } +a { text-decoration: none; color: inherit; } +a:hover { opacity: 0.8; } + +/* === Layout === */ +.min-h-screen { min-height: 100vh; } +.container { width: 100%; max-width: 1280px; margin: 0 auto; } +.mx-auto { margin-left: auto; margin-right: auto; } +.flex { display: flex; } +.items-center { align-items: center; } +.justify-between { justify-content: space-between; } +.justify-center { justify-content: center; } + +/* === Spacing === */ +.gap-2 { gap: 0.5rem; } +.gap-6 { gap: 1.5rem; } +.p-4 { padding: 1rem; } +.px-4 { padding-left: 1rem; padding-right: 1rem; } +.py-8 { padding-top: 2rem; padding-bottom: 2rem; } +.mb-4 { margin-bottom: 1rem; } +.mb-6 { margin-bottom: 1.5rem; } +.mb-8 { margin-bottom: 2rem; } +.mt-4 { margin-top: 1rem; } + +/* === Sizing === */ +.w-4 { width: 1rem; } +.w-full { width: 100%; } +.h-3 { height: 0.75rem; } +.h-96 { height: 24rem; } + +/* === Typography === */ +.text-sm { font-size: 0.875rem; } +.text-lg { font-size: 1.125rem; } +.text-xl { font-size: 1.25rem; } +.text-3xl { font-size: 1.875rem; } +.font-bold { font-weight: 700; } +.font-semibold { font-weight: 600; } + +/* === Colors === */ +.bg-white { background-color: #ffffff; } +.bg-gray-100 { background-color: #f3f4f6; } +.bg-gray-200 { background-color: #e5e7eb; } +.bg-gray-900 { background-color: #111827; } +.bg-red-50 { background-color: #fef2f2; } +.text-white { color: #ffffff; } +.text-gray-300 { color: #d1d5db; } +.text-gray-700 { color: #374151; } +.text-gray-800 { color: #1f2937; } +.text-gray-900 { color: #111827; } +.text-red-600 { color: #dc2626; } + +/* === Borders & Shadows === */ +.rounded-sm { border-radius: 0.125rem; } +.rounded-lg { border-radius: 0.5rem; } +.shadow-md { box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); } +.shadow-lg { box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); } + +/* === Transitions & Animations === */ +.transition-colors { transition: color 0.15s ease-in-out; } +@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } } +.animate-pulse { animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; } + +/* === Chart-specific === */ +.chart-container { max-width: 100%; overflow-x: auto; } +.chart-svg { display: block; max-width: 100%; height: auto; } +"#; + +#[cfg(not(feature = "ssr"))] +fn main() { + // Client-side only - hydration is handled by lib.rs +} diff --git a/bench-website/src/mock_data.rs b/bench-website/src/mock_data.rs new file mode 100644 index 00000000000..4e1f6b21b33 --- /dev/null +++ b/bench-website/src/mock_data.rs @@ -0,0 +1,89 @@ +//! Mock data generation for development and testing. + +use chrono::Duration; +use chrono::Utc; +use duckdb::Result as DuckResult; +use rand::Rng; + +use crate::db::DbPool; + +/// Populates the database with realistic mock benchmark data. +/// +/// Generates 100 commits over 100 days with benchmark results that simulate: +/// - Random variation (+/- 10%) in measurements +/// - Gradual Vortex performance improvements (2% every 10 commits) +/// - A regression at commit 50 that gets fixed at commit 55 +/// - ~20% of commits missing benchmark data (simulating CI gaps) +/// +/// Base performance values: +/// - Vortex: 50ms (improving over time) +/// - Parquet: 80ms (constant) +/// - Lance: 65ms (constant) +pub fn populate_mock_data(db: &DbPool) -> DuckResult<()> { + let num_commits = 100; + let mut rng = rand::rng(); + + // Generate commits starting from 100 days ago + let now = Utc::now(); + let start_time = now - Duration::days(100); + + db.execute(|conn| { + // Insert commits + let mut stmt = conn.prepare( + "INSERT INTO commits (commit_hash, timestamp, message, author) VALUES (?, ?, ?, ?)", + )?; + + for i in 0..num_commits { + let timestamp = start_time + Duration::hours((i as i64) * 24); + let hash = format!("{:040x}", i * 12345 + 67890); + let message = format!("commit message #{}", i); + let author = "developer@example.com"; + // Format timestamp as ISO 8601 string for DuckDB + let timestamp_str = timestamp.format("%Y-%m-%d %H:%M:%S").to_string(); + + stmt.execute(duckdb::params![hash, timestamp_str, message, author])?; + } + + // Insert random_access benchmark data + // Not all commits have benchmark data (simulate CI running on ~80% of commits) + let mut bench_stmt = conn.prepare( + "INSERT INTO random_access (commit_hash, vortex_ns, parquet_ns, lance_ns) VALUES (?, ?, ?, ?)", + )?; + + // Base performance values (in nanoseconds) + let mut vortex_base: f64 = 50_000_000.0; // 50ms + let parquet_base: f64 = 80_000_000.0; // 80ms + let lance_base: f64 = 65_000_000.0; // 65ms + + for i in 0..num_commits { + // Skip some commits (20% have no benchmark data) + if rng.random_ratio(2, 10) { + continue; + } + + let hash = format!("{:040x}", i * 12345 + 67890); + + // Add realistic variation (+/- 10%) + let vortex_ns = (vortex_base * (1.0 + rng.random_range(-0.1..0.1))) as u64; + let parquet_ns = (parquet_base * (1.0 + rng.random_range(-0.1..0.1))) as u64; + let lance_ns = (lance_base * (1.0 + rng.random_range(-0.1..0.1))) as u64; + + bench_stmt.execute(duckdb::params![hash, vortex_ns, parquet_ns, lance_ns])?; + + // Simulate performance trends over time + // Vortex gradually improves + if i % 10 == 0 { + vortex_base *= 0.98; // 2% improvement every 10 commits + } + // Occasional regression + if i == 50 { + vortex_base *= 1.15; // 15% regression at commit 50 + } + if i == 55 { + vortex_base *= 0.87; // Fixed at commit 55 + } + } + + Ok(()) + }) +} diff --git a/bench-website/style/main.css b/bench-website/style/main.css new file mode 100644 index 00000000000..8cf12c77a29 --- /dev/null +++ b/bench-website/style/main.css @@ -0,0 +1,105 @@ +/* Basic styles for Phase 1 - replace with TailwindCSS later */ + +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; + line-height: 1.5; + color: #1f2937; +} + +/* Layout utilities */ +.min-h-screen { min-height: 100vh; } +.container { width: 100%; max-width: 1280px; margin: 0 auto; } +.mx-auto { margin-left: auto; margin-right: auto; } + +/* Flexbox */ +.flex { display: flex; } +.items-center { align-items: center; } +.justify-between { justify-content: space-between; } +.justify-center { justify-content: center; } +.gap-2 { gap: 0.5rem; } +.gap-4 { gap: 1rem; } +.gap-6 { gap: 1.5rem; } + +/* Spacing */ +.p-4 { padding: 1rem; } +.px-4 { padding-left: 1rem; padding-right: 1rem; } +.py-8 { padding-top: 2rem; padding-bottom: 2rem; } +.mb-4 { margin-bottom: 1rem; } +.mb-6 { margin-bottom: 1.5rem; } +.mb-8 { margin-bottom: 2rem; } +.mt-4 { margin-top: 1rem; } + +/* Typography */ +.text-xs { font-size: 0.75rem; } +.text-sm { font-size: 0.875rem; } +.text-lg { font-size: 1.125rem; } +.text-xl { font-size: 1.25rem; } +.text-2xl { font-size: 1.5rem; } +.text-3xl { font-size: 1.875rem; } +.font-bold { font-weight: 700; } +.font-semibold { font-weight: 600; } +.text-center { text-align: center; } + +/* Colors */ +.bg-white { background-color: #ffffff; } +.bg-gray-100 { background-color: #f3f4f6; } +.bg-gray-200 { background-color: #e5e7eb; } +.bg-gray-900 { background-color: #111827; } +.bg-red-50 { background-color: #fef2f2; } +.text-white { color: #ffffff; } +.text-gray-300 { color: #d1d5db; } +.text-gray-500 { color: #6b7280; } +.text-gray-600 { color: #4b5563; } +.text-gray-700 { color: #374151; } +.text-gray-800 { color: #1f2937; } +.text-gray-900 { color: #111827; } +.text-red-600 { color: #dc2626; } +.fill-gray-500 { fill: #6b7280; } +.fill-gray-600 { fill: #4b5563; } + +/* Sizing */ +.w-4 { width: 1rem; } +.h-3 { height: 0.75rem; } +.h-96 { height: 24rem; } +.w-full { width: 100%; } + +/* Borders */ +.rounded { border-radius: 0.25rem; } +.rounded-sm { border-radius: 0.125rem; } +.rounded-lg { border-radius: 0.5rem; } + +/* Effects */ +.shadow-md { box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); } +.shadow-lg { box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); } +.transition-colors { transition: color 0.15s ease-in-out; } + +/* Animations */ +@keyframes pulse { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.5; } +} +.animate-pulse { animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; } + +/* Links */ +a { text-decoration: none; color: inherit; } +a:hover { opacity: 0.8; } +.hover\:text-white:hover { color: #ffffff; } +.hover\:text-gray-300:hover { color: #d1d5db; } + +/* Chart container */ +.chart-container { + max-width: 100%; + overflow-x: auto; +} + +.chart-svg { + display: block; + max-width: 100%; + height: auto; +}