├── examples
├── databases
│ ├── postgres-diesel
│ │ ├── migrations
│ │ │ ├── .keep
│ │ │ ├── 2023-10-25-125915_create_todos
│ │ │ │ ├── down.sql
│ │ │ │ └── up.sql
│ │ │ └── 00000000000000_diesel_initial_setup
│ │ │ │ ├── down.sql
│ │ │ │ └── up.sql
│ │ ├── schema.rs
│ │ ├── diesel.toml
│ │ ├── Cargo.toml
│ │ ├── models.rs
│ │ ├── README.md
│ │ └── serve.rs
│ ├── postgres-seaorm
│ │ ├── entities
│ │ │ ├── mod.rs
│ │ │ ├── prelude.rs
│ │ │ └── todos.rs
│ │ ├── Cargo.toml
│ │ ├── README.md
│ │ ├── migrator.rs
│ │ └── serve.rs
│ ├── redis-driver
│ │ ├── Cargo.toml
│ │ ├── README.md
│ │ └── src
│ │ │ └── main.rs
│ ├── sqlite-turbosql
│ │ ├── Cargo.toml
│ │ ├── README.md
│ │ └── src
│ │ │ └── main.rs
│ ├── sqlite-sqlx
│ │ ├── build.rs
│ │ ├── migrations
│ │ │ └── 20220718111257_todos.sql
│ │ ├── Cargo.toml
│ │ ├── README.md
│ │ └── serve.rs
│ └── mongo-driver
│ │ ├── Cargo.toml
│ │ ├── README.md
│ │ └── src
│ │ └── main.rs
├── todo
│ ├── Cargo.toml
│ └── src
│ │ └── main.rs
├── todo-pwa
│ ├── build.rs
│ ├── Cargo.toml
│ ├── src
│ │ ├── lib.rs
│ │ └── main.rs
│ └── README.md
├── todo-pwa-auth
│ ├── build.rs
│ ├── Cargo.toml
│ ├── src
│ │ ├── lib.rs
│ │ └── main.rs
│ └── README.md
├── bench
│ ├── README.md
│ └── Cargo.toml
├── todo-pwa-auth-sync
│ ├── build.rs
│ ├── Cargo.toml
│ ├── src
│ │ ├── lib.rs
│ │ └── main.rs
│ └── README.md
├── blog
│ ├── build.rs
│ ├── package.json
│ ├── src
│ │ ├── prism.ts
│ │ ├── icons
│ │ │ ├── medium.svg
│ │ │ ├── email.svg
│ │ │ ├── docs.svg
│ │ │ ├── admin.svg
│ │ │ ├── github.svg
│ │ │ └── twitter.svg
│ │ └── main.rs
│ ├── README.md
│ └── Cargo.toml
├── polkadot
│ ├── runtime
│ │ ├── build.rs
│ │ └── Cargo.toml
│ ├── host
│ │ ├── build.rs
│ │ ├── main.rs
│ │ └── Cargo.toml
│ └── README.md
├── scraping
│ ├── Cargo.toml
│ ├── README.md
│ └── src
│ │ └── main.rs
├── llm-mistral
│ ├── Cargo.toml
│ ├── README.md
│ ├── serve.rs
│ └── llm.rs
└── solana
│ ├── Cargo.toml
│ ├── README.md
│ └── src
│ └── lib.rs
├── .gitattributes
├── ui
└── favicon.ico
├── cotton
├── src
│ ├── main.rs
│ ├── progress.rs
│ ├── cache.rs
│ ├── config.rs
│ └── lib.rs
└── Cargo.toml
├── .gitignore
├── serde_derive_fork
├── build.rs
├── src
│ ├── internals
│ │ ├── respan.rs
│ │ ├── mod.rs
│ │ ├── ctxt.rs
│ │ ├── symbol.rs
│ │ └── name.rs
│ ├── dummy.rs
│ ├── this.rs
│ ├── fragment.rs
│ └── lib.rs
└── Cargo.toml
├── package.json
├── embed
├── utils
│ └── Cargo.toml
└── macro
│ └── Cargo.toml
├── host
├── admin
│ ├── assets
│ │ ├── analytics.svg
│ │ ├── logs.svg
│ │ ├── admin.svg
│ │ ├── db.svg
│ │ └── loader.svg
│ ├── logs.rs
│ ├── analytics.rs
│ ├── schedule.rs
│ ├── mod.rs
│ └── db.rs
├── release-builder.Dockerfile
├── webview.rs
├── auth
│ ├── permissions.rs
│ ├── session.rs
│ ├── authn.rs
│ └── google_openid.rs
├── state.rs
├── db
│ ├── transaction.rs
│ └── snapshot.rs
├── sse.rs
├── docker.rs
└── server.rs
├── .env.example
├── init
└── Cargo.toml
├── db
├── macro
│ ├── Cargo.toml
│ ├── analyze.rs
│ ├── from_glue_value.rs
│ └── into_glue_expr.rs
└── key.rs
├── html
├── macro
│ ├── Cargo.toml
│ ├── escape.rs
│ ├── lib.rs
│ └── htmx.rs
├── escape.rs
└── htmx.rs
├── service_worker
└── state.rs
├── .cursor
└── rules
│ └── general.mdc
├── vals.rs
├── docs
├── TS_VS_RUST_FRONTEND.md
└── WHATS_NEXT.md
├── config.rs
└── lib.rs
/examples/databases/postgres-diesel/migrations/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | ui/preset.css linguist-vendored
2 | ui/htmx/** linguist-vendored
--------------------------------------------------------------------------------
/ui/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edezhic/prest/HEAD/ui/favicon.ico
--------------------------------------------------------------------------------
/cotton/src/main.rs:
--------------------------------------------------------------------------------
1 | fn main() {
2 | cotton_install::run().unwrap();
3 | }
4 |
--------------------------------------------------------------------------------
/examples/databases/postgres-diesel/migrations/2023-10-25-125915_create_todos/down.sql:
--------------------------------------------------------------------------------
1 | DROP TABLE todos
--------------------------------------------------------------------------------
/examples/todo/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "todo"
3 | edition = "2021"
4 |
5 | [dependencies]
6 | prest = { version = "0.5", path = "../../" }
--------------------------------------------------------------------------------
/examples/todo-pwa/build.rs:
--------------------------------------------------------------------------------
1 | use prest_build::*;
2 | fn main() {
3 | default_cfg_aliases();
4 | build_pwa(PWAOptions::new()).unwrap();
5 | }
6 |
--------------------------------------------------------------------------------
/examples/todo-pwa-auth/build.rs:
--------------------------------------------------------------------------------
1 | use prest_build::*;
2 | fn main() {
3 | default_cfg_aliases();
4 | build_pwa(PWAOptions::new()).unwrap();
5 | }
6 |
--------------------------------------------------------------------------------
/examples/bench/README.md:
--------------------------------------------------------------------------------
1 | DB load testing script which runs tons of queries concurrently. Configured by a bunch of const values at the top:
2 |
3 | {src/main.rs}
--------------------------------------------------------------------------------
/examples/databases/postgres-seaorm/entities/mod.rs:
--------------------------------------------------------------------------------
1 | //! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.4
2 |
3 | pub mod prelude;
4 |
5 | pub mod todos;
6 |
--------------------------------------------------------------------------------
/examples/databases/postgres-seaorm/entities/prelude.rs:
--------------------------------------------------------------------------------
1 | //! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.4
2 |
3 | pub use super::todos::Entity as Todos;
4 |
--------------------------------------------------------------------------------
/examples/databases/redis-driver/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "redis-driver"
3 | edition = "2021"
4 |
5 | [dependencies]
6 | prest = "0.5"
7 | redis = "0.23.3"
--------------------------------------------------------------------------------
/examples/todo-pwa-auth-sync/build.rs:
--------------------------------------------------------------------------------
1 | use prest_build::*;
2 | fn main() {
3 | default_cfg_aliases();
4 | build_pwa(PWAOptions::new()).unwrap();
5 | }
6 |
--------------------------------------------------------------------------------
/examples/blog/build.rs:
--------------------------------------------------------------------------------
1 | use prest_build::*;
2 | fn main() {
3 | default_cfg_aliases();
4 | bundle_ts();
5 | build_pwa(PWAOptions::new()).unwrap();
6 | }
7 |
--------------------------------------------------------------------------------
/examples/databases/sqlite-turbosql/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "sqlite-turbosql"
3 | edition = "2021"
4 |
5 | [dependencies]
6 | prest = "0.5"
7 | turbosql = "0.9"
--------------------------------------------------------------------------------
/examples/blog/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "exports": {
3 | "prism": "./src/prism.ts"
4 | },
5 | "dependencies": {
6 | "prismjs": "^1.29.0"
7 | }
8 | }
--------------------------------------------------------------------------------
/examples/polkadot/runtime/build.rs:
--------------------------------------------------------------------------------
1 | fn main() {
2 | #[cfg(feature = "std")]
3 | {
4 | polkadot_sdk::substrate_wasm_builder::WasmBuilder::build_using_defaults();
5 | }
6 | }
--------------------------------------------------------------------------------
/examples/blog/src/prism.ts:
--------------------------------------------------------------------------------
1 | import "prismjs";
2 | import "prismjs/components/prism-rust";
3 | import "prismjs/components/prism-toml";
4 | import "prismjs/components/prism-bash";
5 |
--------------------------------------------------------------------------------
/examples/databases/sqlite-sqlx/build.rs:
--------------------------------------------------------------------------------
1 | fn main() {
2 | // https://docs.rs/sqlx/latest/sqlx/macro.migrate.html
3 | println!("cargo:rerun-if-changed=migrations");
4 | }
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .env
2 | cert.pem
3 | key.pem
4 | Cargo.lock
5 | target
6 | prest_storage
7 | .DS_Store
8 | migrations.toml
9 | node_modules
10 | bun.lock
11 | bun.lockb
12 | cotton.lock
13 | .cotton
--------------------------------------------------------------------------------
/examples/databases/postgres-diesel/migrations/2023-10-25-125915_create_todos/up.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE todos (
2 | uuid uuid PRIMARY KEY,
3 | task TEXT NOT NULL,
4 | done BOOLEAN NOT NULL DEFAULT FALSE
5 | )
--------------------------------------------------------------------------------
/examples/databases/mongo-driver/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "mongo-driver"
3 | edition = "2021"
4 |
5 | [dependencies]
6 | prest = "0.5"
7 | mongodb = { version = "2.7.0", features = ["bson-uuid-1"] }
8 |
--------------------------------------------------------------------------------
/examples/polkadot/host/build.rs:
--------------------------------------------------------------------------------
1 | use polkadot_sdk::substrate_build_script_utils::{generate_cargo_keys, rerun_if_git_head_changed};
2 |
3 | fn main() {
4 | generate_cargo_keys();
5 | rerun_if_git_head_changed();
6 | }
--------------------------------------------------------------------------------
/examples/bench/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "bench"
3 | edition = "2021"
4 |
5 | [dependencies]
6 | prest = { path = "../../", features = ["experimental"] }
7 | fastrand = "2"
8 |
9 | [package.metadata]
10 | domain = "prest.blog"
11 |
--------------------------------------------------------------------------------
/examples/databases/postgres-diesel/schema.rs:
--------------------------------------------------------------------------------
1 | // @generated automatically by Diesel CLI.
2 |
3 | diesel::table! {
4 | todos (uuid) {
5 | uuid -> Uuid,
6 | task -> Text,
7 | done -> Bool,
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/examples/scraping/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "scraping"
3 | edition = "2021"
4 |
5 | [dependencies]
6 | prest = { version = "0.5", path = "../../" }
7 | reqwest = { version = "0.12", default-features=false, features = ["rustls-tls"] }
8 | scraper = "0.22"
9 |
--------------------------------------------------------------------------------
/examples/databases/sqlite-sqlx/migrations/20220718111257_todos.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE IF NOT EXISTS todos
2 | (
3 | uuid TEXT PRIMARY KEY NOT NULL,
4 | task TEXT NOT NULL,
5 | done BOOLEAN NOT NULL DEFAULT 0
6 | );
--------------------------------------------------------------------------------
/examples/todo-pwa/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "todo-pwa"
3 | edition = "2021"
4 |
5 | [dependencies]
6 | prest = { version = "0.5", path = "../../" }
7 | wasm-bindgen = "0.2"
8 |
9 | [build-dependencies]
10 | prest-build = { version = "0.4", path = "../../build" }
11 |
12 |
--------------------------------------------------------------------------------
/examples/blog/src/icons/medium.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/databases/sqlite-sqlx/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "sqlite-sqlx"
3 | edition = "2021"
4 |
5 | [[bin]]
6 | name = "serve"
7 | path = "./serve.rs"
8 |
9 | [dependencies]
10 | prest = "0.5"
11 | sqlx = { version = "0.7", features = [ "runtime-tokio", "tls-rustls", "sqlite", "macros" ] }
12 |
--------------------------------------------------------------------------------
/examples/llm-mistral/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "llm-mistral"
3 | edition = "2021"
4 |
5 | [[bin]]
6 | name = "serve"
7 | path = "./serve.rs"
8 |
9 | [dependencies]
10 | prest = "0.5"
11 |
12 | hf-hub = "0.3"
13 | tokenizers = "0.15"
14 | candle-core = "0.3"
15 | candle-transformers = "0.3"
16 |
--------------------------------------------------------------------------------
/examples/todo-pwa-auth/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "todo-pwa-auth"
3 | edition = "2021"
4 |
5 | [dependencies]
6 | prest = { version = "0.5", features = ["auth"], path = "../../" }
7 | wasm-bindgen = "0.2"
8 |
9 | [build-dependencies]
10 | prest-build = { version = "0.4", path = "../../build" }
11 |
--------------------------------------------------------------------------------
/examples/todo-pwa-auth-sync/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "todo-pwa-auth-sync"
3 | edition = "2021"
4 |
5 | [dependencies]
6 | prest = { version = "0.5", features = ["auth"], path = "../../" }
7 | wasm-bindgen = "0.2"
8 |
9 | [build-dependencies]
10 | prest-build = { version = "0.4", path = "../../build" }
11 |
--------------------------------------------------------------------------------
/serde_derive_fork/build.rs:
--------------------------------------------------------------------------------
1 | fn main() {
2 | // Warning: build.rs is not published to crates.io.
3 |
4 | println!("cargo:rerun-if-changed=build.rs");
5 | println!("cargo:rustc-cfg=check_cfg");
6 | println!("cargo:rustc-check-cfg=cfg(check_cfg)");
7 | println!("cargo:rustc-check-cfg=cfg(exhaustive)");
8 | }
9 |
--------------------------------------------------------------------------------
/examples/blog/README.md:
--------------------------------------------------------------------------------
1 | Built from repo's markdown files as a proof-of-concept for prest and maintained to prettify documentation. Served at [prest.blog](https://prest.blog). Here goes all it's source code:
2 |
3 | {Cargo.toml}
4 |
5 | {build.rs}
6 |
7 | {src/main.rs}
8 |
9 | {src/lib.rs}
10 |
11 | {src/content.rs}
12 |
--------------------------------------------------------------------------------
/examples/databases/postgres-diesel/diesel.toml:
--------------------------------------------------------------------------------
1 | # For documentation on how to configure this file,
2 | # see https://diesel.rs/guides/configuring-diesel-cli
3 |
4 | [print_schema]
5 | file = "./schema.rs"
6 | custom_type_derives = ["diesel::query_builder::QueryId"]
7 |
8 | [migrations_directory]
9 | dir = "./migrations"
10 |
--------------------------------------------------------------------------------
/examples/databases/postgres-diesel/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "postgres-diesel"
3 | edition = "2021"
4 |
5 | [[bin]]
6 | name = "serve"
7 | path = "./serve.rs"
8 |
9 | [dependencies]
10 | prest = "0.5"
11 | diesel = { version = "2.1.0", features = ["uuid"] }
12 | diesel-async = { version = "0.3.1", features = ["deadpool", "postgres"] }
13 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "exports": {
3 | "preset": "./ui/preset.ts",
4 | "stats": "./ui/stats.tsx",
5 | "traces": "./ui/traces.tsx",
6 | "db": "./ui/db.tsx"
7 | },
8 | "dependencies": {
9 | "chart.js": "^4.4.7",
10 | "htmx.org": "2.0.6",
11 | "hyperscript.org": "^0.9.14",
12 | "preact": "^10.25.4"
13 | }
14 | }
--------------------------------------------------------------------------------
/embed/utils/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "prest-embed-utils"
3 | version = "0.2.0"
4 | edition = "2021"
5 | description = "fork of embed utils from rust-embed"
6 | license = "MIT OR Apache-2.0"
7 |
8 | [lib]
9 | path = "lib.rs"
10 |
11 | [dependencies]
12 | walkdir = "2.3.1"
13 | sha2 = "0.10.5"
14 | mime_guess = "2.0.4"
15 | globset = "0.4.8"
16 |
--------------------------------------------------------------------------------
/examples/databases/postgres-seaorm/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "postgres-seaorm"
3 | edition = "2021"
4 |
5 | [[bin]]
6 | name = "serve"
7 | path = "./serve.rs"
8 |
9 | [dependencies]
10 | prest = "0.5"
11 | sea-orm = { version = "0.12", features = [ "sqlx-postgres", "runtime-tokio-rustls", "macros", "with-uuid"] }
12 | sea-orm-migration = "0.12"
13 |
--------------------------------------------------------------------------------
/host/admin/assets/analytics.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/blog/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "blog"
3 | edition = "2021"
4 |
5 | [dependencies]
6 | prest = { version = "0.5.1", path = "../../" }
7 | wasm-bindgen = "0.2"
8 | markdown = "1.0.0-alpha.16"
9 | toml = "0.8.8"
10 |
11 | [build-dependencies]
12 | prest-build = { version = "0.4", path = "../../build", features = ["typescript", "sass"] }
13 |
14 | [package.metadata]
15 | domain = "prest.blog"
16 |
--------------------------------------------------------------------------------
/examples/databases/postgres-diesel/migrations/00000000000000_diesel_initial_setup/down.sql:
--------------------------------------------------------------------------------
1 | -- This file was automatically created by Diesel to setup helper functions
2 | -- and other internal bookkeeping. This file is safe to edit, any future
3 | -- changes will be added to existing projects as new migrations.
4 |
5 | DROP FUNCTION IF EXISTS diesel_manage_updated_at(_tbl regclass);
6 | DROP FUNCTION IF EXISTS diesel_set_updated_at();
7 |
--------------------------------------------------------------------------------
/.env.example:
--------------------------------------------------------------------------------
1 | # (optional) port that will be used to serve requests; defaults to 80
2 | PORT=80
3 | # (optional) for PWA builds in debug mode. Use "release" or no value to build only when cfg(not(debug_assertions))
4 | PWA=debug
5 | # (optional) google openid auth
6 | GOOGLE_CLIENT_ID=XXX
7 | GOOGLE_CLIENT_SECRET=XXX
8 | # (optional) host credentials
9 | SSH_ADDR=123.232.111.222
10 | SSH_USER=root
11 | SSH_PASSWORD=verystrongpassword
--------------------------------------------------------------------------------
/examples/databases/redis-driver/README.md:
--------------------------------------------------------------------------------
1 | Minimalistic todo app powered by the [redis client](https://github.com/redis-rs/redis-rs). Created just to showcase how to connect to a redis instance from rust and use that connection in handlers. But overall redis is not designed for this type of apps at all. To get it started locally you can use the official redis docker image: `docker run -p 6379:6379 -d redis:latest`
2 |
3 | {Cargo.toml}
4 |
5 | {src/main.rs}
--------------------------------------------------------------------------------
/examples/databases/mongo-driver/README.md:
--------------------------------------------------------------------------------
1 | Minimalistic todo app powered by the [official rust mongo driver](https://github.com/mongodb/mongo-rust-driver). To get it running you can use the official mongo docker container: `docker run -p 27017:27017 -d mongo:latest`. In general working with mongo in rust is fairly straightforward thanks to the integration with serde's auto (de)serialization tools and driver's utility macros:
2 |
3 | {Cargo.toml}
4 |
5 | {src/main.rs}
--------------------------------------------------------------------------------
/init/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "prest-init-macro"
3 | version = "0.1.0"
4 | edition = "2021"
5 | description = "prest init macro"
6 | license = "MIT OR Apache-2.0"
7 | authors = ["Egor Dezhic "]
8 |
9 | [lib]
10 | path = "lib.rs"
11 | proc-macro = true
12 |
13 | [dependencies]
14 | syn = { version = "2", features = ["derive", "parsing", "proc-macro", "printing", "full"] }
15 | quote = "1"
16 | proc-macro2 = "1"
17 | toml = "0.8"
18 |
--------------------------------------------------------------------------------
/examples/blog/src/icons/email.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/databases/sqlite-sqlx/README.md:
--------------------------------------------------------------------------------
1 | Minimalistic todo app powered by [SQLx](https://github.com/launchbadge/sqlx)-based connection to the [SQLite](https://www.sqlite.org/index.html) DB. The core feature of sqlx is that it's macros can run queries during the build time to test their overall correctness. Also, it's a pretty good choice if you prefer good old sql.
2 |
3 | {Cargo.toml}
4 |
5 | {build.rs}
6 |
7 | {migrations/20220718111257_todos.sql}
8 |
9 | {serve.rs}
--------------------------------------------------------------------------------
/examples/databases/postgres-diesel/models.rs:
--------------------------------------------------------------------------------
1 | use diesel::{pg::Pg, prelude::*};
2 | use prest::{Deserialize, Serialize, Uuid};
3 |
4 | #[derive(Queryable, Selectable, Insertable, Serialize, Deserialize)]
5 | #[diesel(table_name = crate::schema::todos)]
6 | #[diesel(check_for_backend(Pg))]
7 | pub struct Todo {
8 | #[serde(default = "Uuid::now_v7")]
9 | pub uuid: Uuid,
10 | #[serde(default)]
11 | pub task: String,
12 | #[serde(default)]
13 | pub done: bool,
14 | }
15 |
--------------------------------------------------------------------------------
/db/macro/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "prest-db-macro"
3 | version = "0.4.0"
4 | edition = "2021"
5 | authors = ["edezhic@gmail.com"]
6 | description = "macro that derives Storage trait to work with gluesql db"
7 | license = "MIT OR Apache-2.0"
8 |
9 | [lib]
10 | path = "lib.rs"
11 | proc-macro = true
12 |
13 | [dependencies]
14 | syn = { version = "2", default-features = false, features = ["derive", "parsing", "proc-macro", "printing"] }
15 | quote = "1"
16 | proc-macro2 = "1"
17 | gluesql-core = "0.16.3"
--------------------------------------------------------------------------------
/host/release-builder.Dockerfile:
--------------------------------------------------------------------------------
1 | FROM rust:1.88.0
2 | ARG ZIG_VERSION=0.10.1
3 |
4 | # Install Zig
5 | RUN curl -L "https://ziglang.org/download/${ZIG_VERSION}/zig-linux-$(uname -m)-${ZIG_VERSION}.tar.xz" | tar -J -x -C /usr/local && \
6 | ln -s "/usr/local/zig-linux-$(uname -m)-${ZIG_VERSION}/zig" /usr/local/bin/zig
7 |
8 | # Install Rust targets
9 | RUN rustup target add x86_64-unknown-linux-musl
10 | RUN rustup target add wasm32-unknown-unknown
11 |
12 | # Install cargo-zigbuild
13 | RUN cargo install cargo-zigbuild
14 |
--------------------------------------------------------------------------------
/examples/databases/sqlite-turbosql/README.md:
--------------------------------------------------------------------------------
1 | Showcasing probably the easiest library that allows using local sqlite instance with just a couple of lines of code - [turbosql](https://github.com/trevyn/turbosql). Ideaologically similar to the GlueSQL integration and the `Storage` macro of prest. All you need to get started is to derive `Turbosql` on the struct that you want to use as a table and make sure that the struct's types are compatible (all columns are optional, first goes the rowid with i64 and then others):
2 |
3 | {Cargo.toml}
4 |
5 | {src/main.rs}
--------------------------------------------------------------------------------
/serde_derive_fork/src/internals/respan.rs:
--------------------------------------------------------------------------------
1 | use proc_macro2::{Group, Span, TokenStream, TokenTree};
2 |
3 | pub(crate) fn respan(stream: TokenStream, span: Span) -> TokenStream {
4 | stream
5 | .into_iter()
6 | .map(|token| respan_token(token, span))
7 | .collect()
8 | }
9 |
10 | fn respan_token(mut token: TokenTree, span: Span) -> TokenTree {
11 | if let TokenTree::Group(g) = &mut token {
12 | *g = Group::new(g.delimiter(), respan(g.stream(), span));
13 | }
14 | token.set_span(span);
15 | token
16 | }
17 |
--------------------------------------------------------------------------------
/serde_derive_fork/src/internals/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod ast;
2 | pub mod attr;
3 | pub mod name;
4 |
5 | mod case;
6 | mod check;
7 | mod ctxt;
8 | mod receiver;
9 | mod respan;
10 | mod symbol;
11 |
12 | use syn::Type;
13 |
14 | pub use self::ctxt::Ctxt;
15 | pub use self::receiver::replace_receiver;
16 |
17 | #[derive(Copy, Clone)]
18 | pub enum Derive {
19 | Serialize,
20 | Deserialize,
21 | }
22 |
23 | pub fn ungroup(mut ty: &Type) -> &Type {
24 | while let Type::Group(group) = ty {
25 | ty = &group.elem;
26 | }
27 | ty
28 | }
29 |
--------------------------------------------------------------------------------
/host/admin/assets/logs.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/databases/postgres-seaorm/entities/todos.rs:
--------------------------------------------------------------------------------
1 | //! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.4
2 |
3 | use prest::*;
4 | use sea_orm::entity::prelude::*;
5 |
6 | #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
7 | #[sea_orm(table_name = "todos")]
8 | pub struct Model {
9 | #[sea_orm(primary_key, auto_increment = false)]
10 | pub uuid: Uuid,
11 | pub task: String,
12 | pub done: bool,
13 | }
14 |
15 | #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
16 | pub enum Relation {}
17 |
18 | impl ActiveModelBehavior for ActiveModel {}
19 |
--------------------------------------------------------------------------------
/embed/macro/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "prest-embed-macro"
3 | version = "0.3.0"
4 | edition = "2021"
5 | description = "fork of embed macro from rust-embed"
6 | license = "MIT OR Apache-2.0"
7 | authors = ["pyros2097 ", "Egor Dezhic "]
8 |
9 | [lib]
10 | path = "lib.rs"
11 | proc-macro = true
12 |
13 | [dependencies]
14 | prest-embed-utils = { path = "../utils", version = "0.2" }
15 | syn = { version = "2", default-features = false, features = ["derive", "parsing", "proc-macro", "printing"] }
16 | quote = "1"
17 | proc-macro2 = "1"
18 | walkdir = "2.3.1"
19 | shellexpand = "3"
20 |
--------------------------------------------------------------------------------
/examples/scraping/README.md:
--------------------------------------------------------------------------------
1 | Simple [scraper](https://github.com/causal-agent/scraper-based)-based parser that collects posts from [AP News](https://apnews.com). Beside scraper it uses [reqwest](https://github.com/seanmonstar/reqwest) which is a standard option in tokio ecosystem to make requests:
2 |
3 | {Cargo.toml}
4 |
5 | This example spawns the `scrape` function which fetches the provided url, extracts links to other pages from it (but using only 5 of them later to limit the load), then using `join_all` function from the `futures` crate to get all these pages concurrently, then awaits their bodies, then extracts titles and contents and saves the results:
6 |
7 | {src/main.rs}
--------------------------------------------------------------------------------
/examples/polkadot/README.md:
--------------------------------------------------------------------------------
1 | !Currently broken!
2 |
3 | This example is aimed to create a full-stack todo app with a built-in polkadot-based blockchain as a database. Such database can be easily customizable, contain logic written also in Rust, has strong consistency guarantees, easily replicable and optionally publicly verifiable. These features can be interesting for mission-critical data including finances etc. As of now even code copypasted from polkadot-sdk repo produces compilations errors and the amount of required apis for a minimal example is relatively huge so I've set it aside until things improve. Also, no real work on the client side has been done and subxt is probably the best option.
--------------------------------------------------------------------------------
/serde_derive_fork/src/dummy.rs:
--------------------------------------------------------------------------------
1 | use proc_macro2::TokenStream;
2 | use quote::quote;
3 |
4 | pub fn wrap_in_const(serde_path: Option<&syn::Path>, code: TokenStream) -> TokenStream {
5 | let use_serde = match serde_path {
6 | Some(path) => quote! {
7 | use #path as _serde;
8 | },
9 | None => quote! {
10 | #[allow(unused_extern_crates, clippy::useless_attribute)]
11 | extern crate serde as _serde;
12 | },
13 | };
14 |
15 | quote! {
16 | #[doc(hidden)]
17 | #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
18 | const _: () = {
19 | #use_serde
20 | #code
21 | };
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/html/macro/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "prest-html-macro"
3 | version = "0.3.0"
4 | authors = ["Chris Wong ", "Egor Dezhic "]
5 | license = "MIT/Apache-2.0"
6 | documentation = "https://docs.rs/maud_macros/"
7 | homepage = "https://maud.lambda.xyz/"
8 | repository = "https://github.com/lambda-fairy/maud"
9 | description = "Compile-time HTML templates."
10 | edition = "2021"
11 | keywords = ["maud", "prest", "tailwind"]
12 |
13 | #[workspace]
14 |
15 | [dependencies]
16 | syn = "2"
17 | quote = "1.0.7"
18 | proc-macro2 = "1.0.23"
19 | proc-macro-error = { version = "1.0.0", default-features = false }
20 | lazy_static = "1.4.0"
21 | rand = "0.8"
22 | hex = "0.4"
23 | regex = "1"
24 |
25 | [lib]
26 | path = "lib.rs"
27 | proc-macro = true
28 |
--------------------------------------------------------------------------------
/examples/blog/src/icons/docs.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/service_worker/state.rs:
--------------------------------------------------------------------------------
1 | #[macro_export]
2 | macro_rules! state {
3 | ($struct_name:ident: $type:ty = $init:block) => {
4 | pub static $struct_name: prest::Lazy<$type> = prest::Lazy::new(|| {
5 | fn init() -> Result<$type, Box> {
6 | let v = { $init };
7 | Ok(v)
8 | }
9 | init().unwrap()
10 | });
11 | };
12 | ($struct_name:ident: $type:ty = async $init:block) => {
13 | pub static $struct_name: prest::Lazy<$type> = prest::Lazy::new(|| {
14 | async fn init() -> Result<$type, Box> {
15 | let v = { $init };
16 | Ok(v)
17 | }
18 | prest::block_on(init()).unwrap()
19 | });
20 | };
21 | }
22 |
--------------------------------------------------------------------------------
/examples/blog/src/main.rs:
--------------------------------------------------------------------------------
1 | use prest::*;
2 |
3 | embed_build_output_as!(BuiltAssets);
4 |
5 | #[derive(Debug, Storage, Default, Serialize, Deserialize)]
6 | struct Todo {
7 | pub id: Uuid,
8 | pub custom: Inner,
9 | pub done: bool,
10 | }
11 |
12 | #[derive(Debug, Default, Serialize, Deserialize, PartialEq)]
13 | struct Inner {
14 | a: String,
15 | b: NaiveDateTime,
16 | }
17 |
18 | #[init]
19 | async fn main() -> Result {
20 | // example table with data to showcase in the admin panel
21 | Todo {
22 | id: Uuid::now_v7(),
23 | custom: Inner {
24 | a: "v5 release".to_owned(),
25 | b: Default::default(),
26 | },
27 | done: false,
28 | }
29 | .save()
30 | .await?;
31 |
32 | blog::routes().embed(BuiltAssets).run().await
33 | }
34 |
--------------------------------------------------------------------------------
/examples/todo-pwa/src/lib.rs:
--------------------------------------------------------------------------------
1 | use prest::*;
2 |
3 | pub fn shared_routes() -> Router {
4 | route("/", get(home))
5 | }
6 |
7 | async fn home() -> Markup {
8 | into_page(html!(
9 | a get="/todos" trigger="load" push-url
10 | after-request="if (!event.detail.successful) { document.getElementById('error').style.display = 'flex'; this.remove() }" {}
11 | div #"error" style="display: none;" {"Couldn't connect to the server :("}
12 | ))
13 | .await
14 | }
15 |
16 | pub async fn into_page(content: Markup) -> Markup {
17 | html! { html { (Head::with_title("Todo PWA app"))
18 | body $"max-w-screen-sm px-8 mx-auto mt-12 flex flex-col items-center" {
19 | (content)
20 | (Scripts::default())
21 | }
22 | }}
23 | }
24 |
25 | #[cfg(wasm)]
26 | #[wasm_bindgen(start)]
27 | pub fn main() {
28 | shared_routes().handle_fetch_events()
29 | }
30 |
--------------------------------------------------------------------------------
/examples/todo-pwa-auth/src/lib.rs:
--------------------------------------------------------------------------------
1 | use prest::*;
2 |
3 | pub fn shared_routes() -> Router {
4 | route("/", get(home))
5 | }
6 |
7 | async fn home() -> Markup {
8 | into_page(html!(
9 | a get="/todos" trigger="load" push-url
10 | after-request="if (!event.detail.successful) { document.getElementById('error').style.display = 'flex'; this.remove() }" {}
11 | div #"error" style="display: none;" {"Couldn't connect to the server :("}
12 | ))
13 | .await
14 | }
15 |
16 | pub async fn into_page(content: Markup) -> Markup {
17 | html! { html { (Head::with_title("Todo PWA app with auth"))
18 | body $"max-w-screen-sm mx-auto px-8 mt-12 flex flex-col items-center" {
19 | (content)
20 | (Scripts::default())
21 | }
22 | }}
23 | }
24 |
25 | #[cfg(sw)]
26 | #[wasm_bindgen(start)]
27 | pub fn main() {
28 | shared_routes().handle_fetch_events()
29 | }
30 |
--------------------------------------------------------------------------------
/examples/todo-pwa-auth-sync/src/lib.rs:
--------------------------------------------------------------------------------
1 | use prest::*;
2 |
3 | pub fn shared_routes() -> Router {
4 | route("/", get(home))
5 | }
6 |
7 | async fn home() -> Markup {
8 | into_page(html!(
9 | a get="/todos" trigger="load" push-url
10 | after-request="if (!event.detail.successful) { document.getElementById('error').style.display = 'flex'; this.remove() }" {}
11 | div #"error" style="display: none;" {"Couldn't connect to the server :("}
12 | ))
13 | .await
14 | }
15 |
16 | pub async fn into_page(content: Markup) -> Markup {
17 | html! { html { (Head::with_title("Todo PWA app with auth and sync"))
18 | body $"max-w-screen-sm mx-auto px-8 mt-12 flex flex-col items-center" {
19 | (content)
20 | (Scripts::default())
21 | }
22 | }}
23 | }
24 |
25 | #[cfg(sw)]
26 | #[wasm_bindgen(start)]
27 | pub fn main() {
28 | shared_routes().handle_fetch_events()
29 | }
30 |
--------------------------------------------------------------------------------
/host/admin/assets/admin.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/cotton/src/progress.rs:
--------------------------------------------------------------------------------
1 | use std::time::Duration;
2 |
3 | use indicatif::{ProgressBar, ProgressStyle};
4 | use once_cell::sync::Lazy;
5 | use owo_colors::OwoColorize;
6 |
7 | pub static PROGRESS_BAR: Lazy = Lazy::new(|| {
8 | let pb = ProgressBar::new(0).with_style(
9 | ProgressStyle::with_template("{spinner:.blue} {wide_msg} +{pos:.green} ~{len:.magenta}")
10 | .unwrap()
11 | .progress_chars("#>-")
12 | .tick_chars("⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏"),
13 | );
14 | pb.enable_steady_tick(Duration::from_millis(200));
15 | pb
16 | });
17 |
18 | pub fn log_verbose(text: &str) {
19 | // if ARGS.verbose {
20 | PROGRESS_BAR.suspend(|| println!("{} {}", " VERBOSE ".on_white(), text));
21 | // }
22 | }
23 |
24 | pub fn log_warning(text: &str) {
25 | PROGRESS_BAR.suspend(|| println!("{} {}", " WARNING ".on_yellow(), text));
26 | }
27 |
28 | pub fn log_progress(text: &str) {
29 | PROGRESS_BAR.set_message(text.to_string());
30 | log_verbose(text);
31 | }
32 |
--------------------------------------------------------------------------------
/examples/blog/src/icons/admin.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/host/webview.rs:
--------------------------------------------------------------------------------
1 | use crate::*;
2 |
3 | use tao::{
4 | dpi::LogicalSize,
5 | event::{Event, WindowEvent},
6 | event_loop::{ControlFlow, EventLoop},
7 | platform::macos::WindowBuilderExtMacOS,
8 | window::WindowBuilder,
9 | };
10 | use wry::WebViewBuilder;
11 |
12 | pub fn init_webview(url: &str) -> Result {
13 | let size: LogicalSize = LogicalSize::from((1280., 720.));
14 | let event_loop = EventLoop::new();
15 | let window = WindowBuilder::new()
16 | .with_title_hidden(true)
17 | .with_inner_size(size)
18 | .build(&event_loop)?;
19 | let _webview = WebViewBuilder::new(&window)
20 | .with_devtools(true)
21 | .with_url(url)?
22 | .build()?;
23 |
24 | event_loop.run(move |event, _, control_flow| {
25 | *control_flow = ControlFlow::Wait;
26 | if let Event::WindowEvent {
27 | event: WindowEvent::CloseRequested,
28 | ..
29 | } = event
30 | {
31 | *control_flow = ControlFlow::Exit
32 | }
33 | });
34 | }
35 |
--------------------------------------------------------------------------------
/html/escape.rs:
--------------------------------------------------------------------------------
1 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2 | // !!!!! PLEASE KEEP THIS IN SYNC WITH `macro/escape.rs` !!!!!
3 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
4 |
5 | extern crate alloc;
6 |
7 | use alloc::string::String;
8 |
9 | pub fn escape_to_string(input: &str, output: &mut String) {
10 | for b in input.bytes() {
11 | match b {
12 | b'&' => output.push_str("&"),
13 | b'<' => output.push_str("<"),
14 | b'>' => output.push_str(">"),
15 | b'"' => output.push_str("""),
16 | _ => unsafe { output.as_mut_vec().push(b) },
17 | }
18 | }
19 | }
20 |
21 | #[cfg(test)]
22 | mod test {
23 | extern crate alloc;
24 |
25 | use super::escape_to_string;
26 | use alloc::string::String;
27 |
28 | #[test]
29 | fn it_works() {
30 | let mut s = String::new();
31 | escape_to_string("", &mut s);
32 | assert_eq!(s, "<script>launchMissiles()</script>");
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/html/macro/escape.rs:
--------------------------------------------------------------------------------
1 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2 | // !!!!!!!! PLEASE KEEP THIS IN SYNC WITH `maud/src/escape.rs` !!!!!!!!!
3 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
4 |
5 | extern crate alloc;
6 |
7 | use alloc::string::String;
8 |
9 | pub fn escape_to_string(input: &str, output: &mut String) {
10 | for b in input.bytes() {
11 | match b {
12 | b'&' => output.push_str("&"),
13 | b'<' => output.push_str("<"),
14 | b'>' => output.push_str(">"),
15 | b'"' => output.push_str("""),
16 | _ => unsafe { output.as_mut_vec().push(b) },
17 | }
18 | }
19 | }
20 |
21 | #[cfg(test)]
22 | mod test {
23 | extern crate alloc;
24 |
25 | use super::escape_to_string;
26 | use alloc::string::String;
27 |
28 | #[test]
29 | fn it_works() {
30 | let mut s = String::new();
31 | escape_to_string("", &mut s);
32 | assert_eq!(s, "<script>launchMissiles()</script>");
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/serde_derive_fork/src/this.rs:
--------------------------------------------------------------------------------
1 | use crate::internals::ast::Container;
2 | use syn::{Path, PathArguments, Token};
3 |
4 | pub fn this_type(cont: &Container) -> Path {
5 | if let Some(remote) = cont.attrs.remote() {
6 | let mut this = remote.clone();
7 | for segment in &mut this.segments {
8 | if let PathArguments::AngleBracketed(arguments) = &mut segment.arguments {
9 | arguments.colon2_token = None;
10 | }
11 | }
12 | this
13 | } else {
14 | Path::from(cont.ident.clone())
15 | }
16 | }
17 |
18 | pub fn this_value(cont: &Container) -> Path {
19 | if let Some(remote) = cont.attrs.remote() {
20 | let mut this = remote.clone();
21 | for segment in &mut this.segments {
22 | if let PathArguments::AngleBracketed(arguments) = &mut segment.arguments {
23 | if arguments.colon2_token.is_none() {
24 | arguments.colon2_token = Some(Token);
25 | }
26 | }
27 | }
28 | this
29 | } else {
30 | Path::from(cont.ident.clone())
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/host/admin/assets/db.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/databases/postgres-seaorm/README.md:
--------------------------------------------------------------------------------
1 | Minimalistic todo app powered by [SeaORM](https://www.sea-ql.org/SeaORM/)-based connection to Postgres. Seaorm is async-first, dynamic and includes powerful tools for testing. Also it supports [Seaography](https://www.sea-ql.org/SeaORM/docs/seaography/seaography-intro/) - library that can automatically build graphql endpoints from seaorm entities. Overall [SeaQL](https://www.sea-ql.org/) provides pretty much everything necessary to work with postgres, mysql and sqlite, and currently it is the main competitor of [diesel](https://prest.blog/postgres-diesel).
2 |
3 | To work with it you'll need the [sea-orm-cli](https://www.sea-ql.org/SeaORM/docs/generate-entity/sea-orm-cli/), running postgres instance and a connection string defined in `.env` or environment variables. Usually entities are generated using the cli from the database schema - you write migrations, run them, invoke cli and get the entities. A command to do that:
4 |
5 | (`cd examples/databases/postgres-seaorm`)
6 | `sea-orm-cli generate entity -u postgres://postgres:password@localhost/prest -o ./entities --with-serde both`
7 |
8 | Source code of the example:
9 |
10 | {Cargo.toml}
11 |
12 | {migrator.rs}
13 |
14 | {serve.rs}
--------------------------------------------------------------------------------
/serde_derive_fork/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "prest-serde-derive-fork"
3 | version = "1.0.216"
4 | authors = ["Erick Tryzelaar ", "David Tolnay "]
5 | categories = ["no-std", "no-std::no-alloc"]
6 | description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
7 | documentation = "https://serde.rs/derive.html"
8 | edition = "2015"
9 | exclude = ["build.rs"]
10 | homepage = "https://serde.rs"
11 | keywords = ["serde", "serialization", "no_std", "derive"]
12 | license = "MIT OR Apache-2.0"
13 | repository = "https://github.com/serde-rs/serde"
14 | rust-version = "1.61"
15 |
16 | [features]
17 | default = []
18 | deserialize_in_place = []
19 |
20 | [lib]
21 | name = "serde_derive"
22 | proc-macro = true
23 |
24 | [dependencies]
25 | proc-macro2 = { version = "1.0.74", default-features = false, features = ["proc-macro"] }
26 | quote = { version = "1.0.35", default-features = false, features = ["proc-macro"] }
27 | syn = { version = "2.0.46", default-features = false, features = ["clone-impls", "derive", "parsing", "printing", "proc-macro"] }
28 |
29 | [package.metadata.docs.rs]
30 | targets = ["x86_64-unknown-linux-gnu"]
31 | rustdoc-args = ["--generate-link-to-definition"]
32 |
--------------------------------------------------------------------------------
/.cursor/rules/general.mdc:
--------------------------------------------------------------------------------
1 | ---
2 | description:
3 | globs:
4 | alwaysApply: true
5 | ---
6 | This is the PREST (Progressive REST) framework. It's a full-stack project aiming for development of full-cycle app development in Rust. It's most distinctive feature is cross-compilation of some of the code into both regular server-side endpoints and service worker capabilities to render static pages on the client side. Another major focus is batteries-included simplicity of development - it comes with a built-in (sled + gluesql)-based DB (`./db/`), templating (`./html`) based on HTMX with special abbreviations to make code cleaner and compilation of tailwind classes directly into in-page styles, npm package manager (`./cotton`) for FE scripts, build system (`./build`) for service workers, TypeScript scripts and SASS styles, file embedding for both host and SW (`./embed`), host tools (`./host`) for serving, logging, auth, admin panel, deployment and monitoring utilities. As well as a whole bunch of other utilities. Instead of tests for now it's focused on providing runnable examples (`./examples`), and specifically `./examples/blog` serves as both live example and documentation website.
7 |
8 | After making changes run `cargo check` for modified projects to make sure they compile fine.
--------------------------------------------------------------------------------
/host/auth/permissions.rs:
--------------------------------------------------------------------------------
1 | use std::collections::HashSet;
2 |
3 | use axum_login::AuthzBackend;
4 |
5 | use crate::*;
6 |
7 | pub type Permission = String;
8 |
9 | #[async_trait]
10 | impl AuthzBackend for Prest {
11 | type Permission = Permission;
12 |
13 | async fn get_user_permissions(
14 | &self,
15 | user: &Self::User,
16 | ) -> std::result::Result, Self::Error> {
17 | Ok(user.permissions.iter().map(|s| s.to_owned()).collect())
18 | }
19 |
20 | async fn get_group_permissions(
21 | &self,
22 | user: &Self::User,
23 | ) -> std::result::Result, Self::Error> {
24 | Ok(user.permissions.iter().map(|s| s.to_owned()).collect())
25 | }
26 |
27 | async fn get_all_permissions(
28 | &self,
29 | user: &Self::User,
30 | ) -> std::result::Result, Self::Error> {
31 | Ok(user.permissions.iter().map(|s| s.to_owned()).collect())
32 | }
33 |
34 | async fn has_perm(
35 | &self,
36 | user: &Self::User,
37 | perm: Self::Permission,
38 | ) -> std::result::Result {
39 | Ok(user.permissions.iter().find(|p| **p == perm).is_some())
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/vals.rs:
--------------------------------------------------------------------------------
1 | use crate::*;
2 |
3 | /// Utility that deserializes from either [`Query`] (GET) or [`Json`] (others) based on request method
4 | pub struct Vals(pub T);
5 | #[async_trait]
6 | impl FromRequest for Vals
7 | where
8 | T: serde::de::DeserializeOwned + Send,
9 | S: Send + Sync,
10 | {
11 | type Rejection = Error;
12 |
13 | async fn from_request(req: Request, state: &S) -> Result {
14 | if req.method() == Method::GET || req.method() == Method::HEAD {
15 | let (mut parts, _) = req.into_parts();
16 | match axum::extract::Query::::from_request_parts(&mut parts, state).await {
17 | Ok(axum::extract::Query(params)) => Ok(Vals(params)),
18 | Err(e) => Err(e.into()),
19 | }
20 | } else {
21 | match Json::::from_request(req, state).await {
22 | Ok(Json(params)) => Ok(Vals(params)),
23 | Err(e) => Err(e.into()),
24 | }
25 | }
26 | }
27 | }
28 |
29 | impl std::ops::Deref for Vals {
30 | type Target = T;
31 |
32 | fn deref(&self) -> &Self::Target {
33 | &self.0
34 | }
35 | }
36 |
37 | impl std::ops::DerefMut for Vals {
38 | fn deref_mut(&mut self) -> &mut Self::Target {
39 | &mut self.0
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/examples/databases/postgres-diesel/migrations/00000000000000_diesel_initial_setup/up.sql:
--------------------------------------------------------------------------------
1 | -- This file was automatically created by Diesel to setup helper functions
2 | -- and other internal bookkeeping. This file is safe to edit, any future
3 | -- changes will be added to existing projects as new migrations.
4 |
5 |
6 |
7 |
8 | -- Sets up a trigger for the given table to automatically set a column called
9 | -- `updated_at` whenever the row is modified (unless `updated_at` was included
10 | -- in the modified columns)
11 | --
12 | -- # Example
13 | --
14 | -- ```sql
15 | -- CREATE TABLE users (id SERIAL PRIMARY KEY, updated_at TIMESTAMP NOT NULL DEFAULT NOW());
16 | --
17 | -- SELECT diesel_manage_updated_at('users');
18 | -- ```
19 | CREATE OR REPLACE FUNCTION diesel_manage_updated_at(_tbl regclass) RETURNS VOID AS $$
20 | BEGIN
21 | EXECUTE format('CREATE TRIGGER set_updated_at BEFORE UPDATE ON %s
22 | FOR EACH ROW EXECUTE PROCEDURE diesel_set_updated_at()', _tbl);
23 | END;
24 | $$ LANGUAGE plpgsql;
25 |
26 | CREATE OR REPLACE FUNCTION diesel_set_updated_at() RETURNS trigger AS $$
27 | BEGIN
28 | IF (
29 | NEW IS DISTINCT FROM OLD AND
30 | NEW.updated_at IS NOT DISTINCT FROM OLD.updated_at
31 | ) THEN
32 | NEW.updated_at := current_timestamp;
33 | END IF;
34 | RETURN NEW;
35 | END;
36 | $$ LANGUAGE plpgsql;
37 |
--------------------------------------------------------------------------------
/examples/solana/Cargo.toml:
--------------------------------------------------------------------------------
1 | [workspace]
2 | members = ["."]
3 | resolver = "2"
4 |
5 | [package]
6 | name = "todo-solana"
7 | edition = "2021"
8 |
9 | [lib]
10 | crate-type = ["cdylib", "lib"]
11 |
12 | [target.'cfg(target_os = "solana")'.dependencies]
13 | anchor-lang = { version = "0.30.1", features = ["init-if-needed"] }
14 |
15 | [target.'cfg(not(target_os = "solana"))'.dependencies]
16 | anchor-lang = { version = "0.30.1", features = ["init-if-needed"] }
17 | anchor-client = { version = "0.30.1", features = ["async"] }
18 | prest = "0.5"
19 |
20 | [profile.release]
21 | overflow-checks = true
22 | lto = "fat"
23 | codegen-units = 1
24 | [profile.release.build-override]
25 | opt-level = 3
26 | incremental = false
27 | codegen-units = 1
28 |
29 | # until https://github.com/coral-xyz/anchor/pull/3057 is released
30 | [patch.crates-io.anchor-client]
31 | git = "https://github.com/coral-xyz/anchor.git"
32 | rev = "f677742a978ffdf7bc321746b4119394f6654b7c"
33 | [patch.crates-io.anchor-lang]
34 | git = "https://github.com/coral-xyz/anchor.git"
35 | rev = "f677742a978ffdf7bc321746b4119394f6654b7c"
36 |
37 | # dependencies conflicts, should be resolved with solana-program v2
38 | [patch.crates-io.curve25519-dalek]
39 | git = "https://github.com/solana-labs/curve25519-dalek.git"
40 | rev = "b500cdc2a920cd5bff9e2dd974d7b97349d61464"
41 | [patch.crates-io.aes-gcm-siv]
42 | git = "https://github.com/edezhic/AEADs"
43 |
--------------------------------------------------------------------------------
/examples/blog/src/icons/github.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/databases/postgres-seaorm/migrator.rs:
--------------------------------------------------------------------------------
1 | use sea_orm_migration::prelude::*;
2 |
3 | pub struct Migrator;
4 |
5 | #[async_trait::async_trait]
6 | impl MigratorTrait for Migrator {
7 | fn migrations() -> Vec> {
8 | vec![Box::new(MigrationCreateTodos)]
9 | }
10 | }
11 | struct MigrationCreateTodos;
12 | impl MigrationName for MigrationCreateTodos {
13 | fn name(&self) -> &str {
14 | "m_20231106_000001_create_todos_table"
15 | }
16 | }
17 | #[async_trait::async_trait]
18 | impl MigrationTrait for MigrationCreateTodos {
19 | async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
20 | manager
21 | .create_table(
22 | Table::create()
23 | .table(Todos::Storage)
24 | .col(ColumnDef::new(Todos::Uuid).uuid().not_null().primary_key())
25 | .col(ColumnDef::new(Todos::Task).string().not_null())
26 | .col(ColumnDef::new(Todos::Done).boolean().not_null())
27 | .to_owned(),
28 | )
29 | .await
30 | }
31 | async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
32 | manager
33 | .drop_table(Table::drop().table(Todos::Storage).to_owned())
34 | .await
35 | }
36 | }
37 |
38 | #[derive(Iden)]
39 | pub enum Todos {
40 | Storage,
41 | Uuid,
42 | Task,
43 | Done,
44 | }
45 |
--------------------------------------------------------------------------------
/examples/blog/src/icons/twitter.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/db/key.rs:
--------------------------------------------------------------------------------
1 | use crate::*;
2 |
3 | use sql::Key;
4 |
5 | pub trait IntoSqlKey {
6 | fn into_sql_key(self) -> Key;
7 | }
8 |
9 | macro_rules! into_key {
10 | ($type:tt, $variant:tt) => {
11 | impl IntoSqlKey for $type {
12 | fn into_sql_key(self) -> Key {
13 | Key::$variant(self)
14 | }
15 | }
16 | };
17 | }
18 |
19 | into_key!(bool, Bool);
20 | into_key!(i8, I8);
21 | into_key!(i16, I16);
22 | into_key!(i32, I32);
23 | into_key!(i64, I64);
24 | into_key!(i128, I128);
25 | into_key!(u8, U8);
26 | into_key!(u16, U16);
27 | into_key!(u32, U32);
28 | into_key!(u64, U64);
29 | into_key!(u128, U128);
30 | into_key!(String, Str);
31 | into_key!(NaiveDateTime, Timestamp);
32 | into_key!(NaiveDate, Date);
33 | into_key!(NaiveTime, Time);
34 |
35 | impl IntoSqlKey for Uuid {
36 | fn into_sql_key(self) -> Key {
37 | Key::Uuid(self.as_u128())
38 | }
39 | }
40 |
41 | impl IntoSqlKey for Vec {
42 | fn into_sql_key(self) -> Key {
43 | Key::Bytea(self)
44 | }
45 | }
46 |
47 | impl IntoSqlKey for f32 {
48 | fn into_sql_key(self) -> Key {
49 | Key::F32(sql::OrderedFloat(self))
50 | }
51 | }
52 |
53 | impl IntoSqlKey for f64 {
54 | fn into_sql_key(self) -> Key {
55 | Key::F64(sql::OrderedFloat(self))
56 | }
57 | }
58 |
59 | // TODO: remaining possible key types
60 | // Decimal(v) => Ok(Key::Decimal(v)),
61 | // Inet(v) => Ok(Key::Inet(v)),
62 | // Interval(v) => Ok(Key::Interval(v)),
63 |
--------------------------------------------------------------------------------
/examples/solana/README.md:
--------------------------------------------------------------------------------
1 | Example of a todo application that is using Solana blockchain for storage. One of the cool things about Solana is that it supports writing onchain programs in Rust so we can reuse program's types in the offchain prest code to simplify interactions. Also, there is an [Anchor](https://www.anchor-lang.com/) framework that simplifies smart contract development by abstracting onchain accounts so that we don't have to worry all technical details. To get started we'll need to add anchor dependencies and some patches to make it compatible with prest:
2 |
3 | {Cargo.toml}
4 |
5 | You might also notice profile overrides which are needed to make program's code as small as possible because onchain storage is quite expensive.
6 |
7 | Next comes the program's code:
8 |
9 | {src/lib.rs}
10 |
11 | Here we have definitions for the onchain data and available instructions. Each instruction requires a context which defines accounts that are needed for the execution. Some of them like `Signer` and `System` are built-in, but `TodoList` is defined by this program.
12 |
13 | Last piece is the application which will prepare and deploy the program to the local network and allow us to interact with it:
14 |
15 | {src/main.rs}
16 |
17 | This example is hardcoded for an easy local setup and demo purposes, but overall solana interactions aren't much different. However, in a real project you'll probably want to run transactions from the frontend signed by users' keys, and current solana sdks do not support doing that in rust, so you'll probably need to add some javascript.
--------------------------------------------------------------------------------
/examples/databases/postgres-diesel/README.md:
--------------------------------------------------------------------------------
1 | Minimalistic todo app with storage based on [PostgreSQL](https://www.postgresql.org/) DB with [Diesel](https://github.com/launchbadge/sqlx) ORM - probably the first mature rust orm, currently used in [crates.io](https://crates.io/) and many other projects.
2 |
3 | It has a number of advantages - stability, feature-completeness, plenty of configs and utility crates, and easy to use once you've set it up. High-performance and low-risk choice for lots of projects. However, the initial setup might be tricky because diesel crates link to host-provided db client libraries.
4 |
5 | This example is using [diesel-async](https://github.com/weiznich/diesel_async) because the rest of the server is async, and it's intended to showcase basic apis with a UI similar to other DB examples to easily compare their usage. To get started with this one you'll need:
6 |
7 | 1. `cargo install diesel_cli --no-default-features --features postgres` - install diesel CLI that you'll need for common diesel-related ops
8 | 2. `docker run -p 5432:5432 -e POSTGRES_PASSWORD=password -d postgres` - start a postgres instance in a docker container
9 | 3. `cd examples/databases/postgres-diesel && diesel setup --migration-dir="./migrations/"` - setup database & migrations
10 | 4. `cargo run -p postgres-diesel` - to start the example
11 |
12 | It's powered by a few additional dependencies in the manifest:
13 |
14 | {Cargo.toml}
15 |
16 | A separate manifest for the diesel configuration:
17 |
18 | {diesel.toml}
19 |
20 | A model that defines the auto-generated schema:
21 |
22 | {models.rs}
23 |
24 | And a prest app that uses all of the above to manage todos:
25 |
26 | {serve.rs}
27 |
--------------------------------------------------------------------------------
/examples/llm-mistral/README.md:
--------------------------------------------------------------------------------
1 | Simple example that runs [Mistral](https://mistral.ai/news/announcing-mistral-7b/) model using [candle](https://github.com/huggingface/candle) framework. Adopted from [candle's mistral example](https://github.com/huggingface/candle/tree/main/candle-examples/examples/mistral), but without platform-dependent optimizations and with UI for the easiest start.
2 |
3 | Candle is a framework developed by [Hugging Face](https://huggingface.co/) - leading AI platform in the world. They started to build it because Python, common choice for AI development, introduces significant performance and devops overhead, while rust solves these problems, enchances reliability and provides direct access to WASM and WebGPU ecosystems to easily run models on the client side. As of now it's not as easy to use as PyTorch and missing some important features, but the future is bright and it already supports a lot of modern models like the one used in this example.
4 |
5 | As always let's start with the manifest:
6 |
7 | {Cargo.toml}
8 |
9 | It includes `hf-hub` that simplifies model loading, `tokenizers` - another hugging face utility for efficient text pre- and postprocessing for LLMs, and `candle-*` crates which run calculations of the models.
10 |
11 | The core example's code is in:
12 |
13 | {llm.rs}
14 |
15 | It defines how the model is initialized, encodes, performs inference and decodes. Prest-based service that works with this model is defined here:
16 |
17 | {serve.rs}
18 |
19 | Beware that it's a simple and naive implementation designed to check it out locally. For real-world SaaS or other types of services model should be managed differently, but this example is enough to demonstrate core building blocks.
--------------------------------------------------------------------------------
/cotton/src/cache.rs:
--------------------------------------------------------------------------------
1 | use std::{fmt::Debug, hash::Hash, sync::Arc};
2 |
3 | use dashmap::DashMap;
4 | use futures::{
5 | future::{BoxFuture, Shared},
6 | Future, FutureExt,
7 | };
8 |
9 | use crate::progress::PROGRESS_BAR;
10 |
11 | type SharedBoxFuture = Shared>;
12 |
13 | pub struct Cache {
14 | loader: Box BoxFuture<'static, V> + Send + Sync + 'static>,
15 | map: DashMap>,
16 | }
17 |
18 | impl Cache {
19 | pub fn new(loader: T) -> Self
20 | where
21 | F: Future