Skip to content

Commit

Permalink
feat: support smol runtime (#129)
Browse files Browse the repository at this point in the history
* feat: support smol runtime

* chore: remove unless modules on smol example

* feat: add a trait for limited request body (#130)

* feat: add a trait for limited request body

* fix: clippy

* fix: export

* chore: renaming

* chore: remove redundance space lines

* feat: add viz-smol

* feat: add viz-smol

* fix: docs

* fix: docs

* fix: docs
  • Loading branch information
fundon authored Jan 12, 2024
1 parent 30e4849 commit 3392b2d
Show file tree
Hide file tree
Showing 23 changed files with 577 additions and 87 deletions.
14 changes: 14 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ members = [
"viz-macros",
"viz-router",
"viz-tower",
"viz-smol",
"viz-test",

"examples/hello-world",
Expand Down Expand Up @@ -34,6 +35,7 @@ members = [
"examples/databases/*",
"examples/htmlx",
"examples/tower",
"examples/smol",
]

[workspace.package]
Expand All @@ -55,6 +57,8 @@ viz-macros = { version = "0.2.0", path = "viz-macros" }
viz-test = { version = "0.2.0", path = "viz-test" }
viz-tower = { version = "0.1.0", path = "viz-tower" }

viz-smol = { version = "0.1.0", path = "viz-smol" }

anyhow = "1.0"
async-trait = "0.1"
bytes = "1.5"
Expand Down Expand Up @@ -113,6 +117,16 @@ tracing-subscriber = { version = "0.3", features = ["env-filter"] }
tower = "0.4"
tower-http = "0.5"

# soml
async-channel = "2.1"
async-executor = "1.8"
async-io = "2.2"
async-net = "2.0"
smol-hyper = "0.1.1"
smol-macros = "0.1"
macro_rules_attribute = "0.2"
futures-lite = { version = "2.1.0", default-features = false, features = ["std"] }

[workspace.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
Expand Down
12 changes: 12 additions & 0 deletions examples/smol/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "smol-example"
version = "0.1.0"
edition.workspace = true
publish = false

[dependencies]
viz-smol.workspace = true

async-net.workspace = true
smol-macros.workspace = true
macro_rules_attribute.workspace = true
23 changes: 23 additions & 0 deletions examples/smol/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use std::io;
use std::sync::Arc;

use async_net::TcpListener;
use macro_rules_attribute::apply;
use viz_smol::{IntoResponse, Request, Response, Result, Router};

#[apply(smol_macros::main!)]
async fn main(ex: &Arc<smol_macros::Executor<'_>>) -> io::Result<()> {
// Build our application with a route.
let app = Router::new().get("/", handler);

// Create a `smol`-based TCP listener.
let listener = TcpListener::bind(("127.0.0.1", 3000)).await.unwrap();
println!("listening on {}", listener.local_addr().unwrap());

// Run it
viz_smol::serve(ex.clone(), listener, app).await
}

async fn handler(_: Request) -> Result<Response> {
Ok("<h1>Hello, World!</h1>".into_response())
}
21 changes: 10 additions & 11 deletions viz-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,35 +17,34 @@ categories = ["asynchronous", "network-programming", "web-programming"]
default = [
"state",
"limits",
"params",
"json",
"form",
"query",
"form",
"json",
"multipart",
"websocket",
"params",
"cookie",
"session",
"fs",
]

state = []
limits = []

params = ["dep:serde"]
json = ["dep:serde", "dep:serde_json"]
form = ["dep:serde", "dep:serde_urlencoded"]
query = ["dep:serde", "dep:serde_urlencoded"]
form = ["dep:serde", "dep:serde_urlencoded"]
json = ["dep:serde", "dep:serde_json"]
multipart = ["dep:form-data"]
websocket = ["dep:tokio-tungstenite", "tokio/rt"]
sse = ["dep:tokio-stream", "tokio/time"]
fs = ["tokio-util/io", "tokio/fs"]
params = ["dep:serde"]

cookie = ["dep:cookie"]
cookie-private = ["cookie", "cookie?/private"]
cookie-signed = ["cookie", "cookie?/signed"]

session = ["cookie-private", "json", "dep:sessions-core"]

websocket = ["dep:tokio-tungstenite", "tokio/rt"]
sse = ["dep:tokio-stream", "tokio/time"]
fs = ["tokio-util/io", "tokio/fs"]

csrf = ["cookie-private", "dep:base64", "dep:getrandom"]
cors = []

Expand Down
11 changes: 8 additions & 3 deletions viz-core/src/response.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use http_body_util::Full;

use crate::{header, Body, BoxError, Bytes, Error, Future, Response, Result, StatusCode};
use crate::{header, Body, BoxError, Bytes, Response, Result, StatusCode};

/// The [`Response`] Extension.
pub trait ResponseExt: private::Sealed + Sized {
Expand Down Expand Up @@ -94,7 +94,10 @@ pub trait ResponseExt: private::Sealed + Sized {

/// Downloads transfers the file from path as an attachment.
#[cfg(feature = "fs")]
fn download<T>(path: T, name: Option<&str>) -> impl Future<Output = Result<Self>> + Send
fn download<T>(
path: T,
name: Option<&str>,
) -> impl std::future::Future<Output = Result<Self>> + Send
where
T: AsRef<std::path::Path> + Send;

Expand Down Expand Up @@ -231,7 +234,9 @@ impl ResponseExt for Response {

let mut resp = Self::attachment(&format!("attachment; filename=\"{value}\""));
*resp.body_mut() = Body::from_stream(tokio_util::io::ReaderStream::new(
tokio::fs::File::open(path).await.map_err(Error::from)?,
tokio::fs::File::open(path)
.await
.map_err(crate::Error::from)?,
));
Ok(resp)
}
Expand Down
85 changes: 85 additions & 0 deletions viz-smol/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
[package]
name = "viz-smol"
version = "0.1.0"
documentation = "https://docs.rs/viz-smol"
description = "An adapter for smol runtime"
readme = "README.md"
authors.workspace = true
edition.workspace = true
homepage.workspace = true
repository.workspace = true
license.workspace = true
rust-version.workspace = true

[features]
default = [
"state",
"limits",
"query",
"form",
"json",
"multipart",
"params",
"cookie",
"session",

"http1",
]

state = ["viz-core/state"]
limits = ["viz-core/limits"]

query = ["viz-core/query"]
form = ["viz-core/form"]
json = ["viz-core/json"]
multipart = ["viz-core/multipart"]
params = ["viz-core/params"]

cookie = ["viz-core/cookie"]
cookie-private = ["viz-core/cookie-private"]
cookie-signed = ["viz-core/cookie-signed"]

session = ["cookie", "cookie-private", "viz-core/session"]

csrf = ["cookie", "cookie-private", "viz-core/csrf"]
cors = ["viz-core/cors"]

http1 = ["hyper/http1"]
http2 = ["hyper/http2"]

unix-socket = []

macros = ["dep:viz-macros"]

handlers = ["dep:viz-handlers"]

otel = ["viz-core/otel"]
otel-tracing = ["otel", "viz-core/otel-tracing"]
otel-metrics = ["otel", "viz-core/otel-metrics"]
otel-prometheus = ["handlers", "viz-handlers?/prometheus"]

[dependencies]
viz-core.workspace = true
viz-router.workspace = true
viz-handlers = { workspace = true, optional = true }
viz-macros = { workspace = true, optional = true }

hyper.workspace = true
hyper-util.workspace = true
tracing.workspace = true

async-executor.workspace = true
async-net.workspace = true
smol-hyper.workspace = true
futures-lite.workspace = true

[dev-dependencies]
smol-macros.workspace = true
macro_rules_attribute.workspace = true

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]

[lints]
workspace = true
80 changes: 80 additions & 0 deletions viz-smol/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
//! Viz
//!
//! Fast, robust, flexible, lightweight web framework for Rust.
//!
//! # Features
//!
//! * **Safety** `#![forbid(unsafe_code)]`
//!
//! * Lightweight
//!
//! * Simple + Flexible [`Handler`](#handler) & [`Middleware`](#middleware)
//!
//! * Handy [`Extractors`](#extractors)
//!
//! * Robust [`Routing`](#routing)
//!
//! * Supports Tower [`Service`]
//!
//! # Hello Viz
//!
//! ```no_run
//! use std::io;
//! use std::sync::Arc;
//!
//! use async_net::TcpListener;
//! use macro_rules_attribute::apply;
//! use viz_smol::{Request, Result, Router};
//!
//! async fn index(_: Request) -> Result<&'static str> {
//! Ok("Hello, Viz!")
//! }
//!
//! #[apply(smol_macros::main!)]
//! async fn main(ex: &Arc<smol_macros::Executor<'_>>) -> io::Result<()> {
//! // Build our application with a route.
//! let app = Router::new().get("/", index);
//!
//! // Create a `smol`-based TCP listener.
//! let listener = TcpListener::bind(("127.0.0.1", 3000)).await.unwrap();
//! println!("listening on {}", listener.local_addr().unwrap());
//!
//! // Run it
//! viz_smol::serve(ex.clone(), listener, app).await
//! }
//! ```
//!
//! [`Service`]: https://docs.rs/tower-service/latest/tower_service/trait.Service.html
#![doc(html_logo_url = "https://viz.rs/logo.svg")]
#![doc(html_favicon_url = "https://viz.rs/logo.svg")]
#![doc(test(
no_crate_inject,
attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables))
))]
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]

mod responder;
pub use responder::Responder;

mod listener;
pub use listener::Listener;

mod server;
pub use server::serve;

#[cfg(any(feature = "native_tls", feature = "rustls"))]
pub use server::tls;

pub use viz_core::*;
pub use viz_router::*;

#[cfg(feature = "handlers")]
#[cfg_attr(docsrs, doc(cfg(feature = "handlers")))]
#[doc(inline)]
pub use viz_handlers as handlers;

#[cfg(feature = "macros")]
#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
#[doc(inline)]
pub use viz_macros::handler;
20 changes: 20 additions & 0 deletions viz-smol/src/listener.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/// A trait for a listener: `TcpListener` and `UnixListener`.
pub trait Listener {
/// The stream's type of this listener.
type Io;
/// The socket address type of this listener.
type Addr;

/// Accepts a new incoming connection from this listener.
fn accept(
&self,
) -> impl std::future::Future<Output = std::io::Result<(Self::Io, Self::Addr)>> + Send;

/// Returns the local address that this listener is bound to.
///
/// # Errors
///
/// An error will return if got the socket address of the local half of this connection is
/// failed.
fn local_addr(&self) -> std::io::Result<Self::Addr>;
}
Loading

0 comments on commit 3392b2d

Please sign in to comment.