From ad867e9d7352963fc3ab12e61491c4c49802ba38 Mon Sep 17 00:00:00 2001 From: dvdmgl Date: Thu, 18 Sep 2025 03:22:19 +0100 Subject: [PATCH 1/4] Add support for Ntex * feat: add ntex support --- docs/content/web-frameworks.md | 41 ++++++++++++++++++++++++++++++- doctest/Cargo.toml | 3 ++- maud/Cargo.toml | 2 ++ maud/src/lib.rs | 45 ++++++++++++++++++++++++++++++++++ 4 files changed, 89 insertions(+), 2 deletions(-) diff --git a/docs/content/web-frameworks.md b/docs/content/web-frameworks.md index 4b6db2a2..377f07e4 100644 --- a/docs/content/web-frameworks.md +++ b/docs/content/web-frameworks.md @@ -1,6 +1,6 @@ # Web framework integration -Maud includes support for these web frameworks: [Actix], [Rocket], [Rouille], [Tide], [Axum], [Poem], and [Salvo]. +Maud includes support for these web frameworks: [Actix], [Rocket], [Rouille], [Tide], [Axum], [Poem], [Salvo], and [Ntex]. [Actix]: https://actix.rs/ [Rocket]: https://rocket.rs/ @@ -11,6 +11,7 @@ Maud includes support for these web frameworks: [Actix], [Rocket], [Rouille], [T [Submillisecond]: https://github.com/lunatic-solutions/submillisecond [Poem]: https://github.com/poem-web/poem [Salvo]: https://salvo.rs +[Ntex]: https://ntex.rs/ # Actix @@ -304,3 +305,41 @@ async fn main() { Server::new(listener).serve(app).await; } ``` + +# Ntex + +ntex support is available with the "ntex" feature: + +```toml +# ... +[dependencies] +maud = { version = "*", features = ["ntex"] } +# ... +``` + +Actix request handlers can use a `Markup` that implements the `ntex::web::Responder` trait. + +```rust,no_run +use ntex::web::{get, App, HttpServer, Responder}; +use maud::{html, Markup}; +use std::io; + +#[get("/")] +async fn index() -> impl Responder { + html! { + html { + body { + h1 { "Hello World!" } + } + } + } +} + +#[ntex::main] +async fn main() -> io::Result<()> { + HttpServer::new(|| App::new().service(index)) + .bind(("127.0.0.1", 8080))? + .run() + .await +} +``` diff --git a/doctest/Cargo.toml b/doctest/Cargo.toml index 8dd7c47c..20f2fceb 100644 --- a/doctest/Cargo.toml +++ b/doctest/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] actix-web = { version = "4.0.0-rc.2", default-features = false, features = ["macros"] } ammonia = "3" -maud = { path = "../maud", features = ["actix-web", "rocket", "tide", "axum", "warp", "submillisecond", "poem", "salvo"] } +maud = { path = "../maud", features = ["actix-web", "rocket", "tide", "axum", "warp", "submillisecond", "poem", "salvo", "ntex"] } pulldown-cmark = "0.8" rocket = "0.5" rouille = "3" @@ -18,6 +18,7 @@ axum = "0.8" warp = "0.3.6" poem = "3" salvo = "0.78.0" +ntex = { version = "2" } [dependencies.async-std] version = "1.9.0" diff --git a/maud/Cargo.toml b/maud/Cargo.toml index 74eaa467..00809234 100644 --- a/maud/Cargo.toml +++ b/maud/Cargo.toml @@ -21,6 +21,7 @@ default = [] actix-web = ["actix-web-dep", "futures-util"] axum = ["axum-core", "http"] salvo = ["salvo_core", "http"] +ntex = ["dep:ntex"] [dependencies] maud_macros = { version = "0.27.0", path = "../maud_macros" } @@ -35,6 +36,7 @@ http = { version = "1", optional = true } warp = { version = "0.3.6", optional = true } poem = { version = "3", optional = true } salvo_core = { version = "0.78.0", optional = true } +ntex = { version = "2.0", optional = true, default-features = false } [dev-dependencies] trybuild = { version = "1.0.33", features = ["diff"] } diff --git a/maud/src/lib.rs b/maud/src/lib.rs index 67ce9c6f..02b8c12f 100644 --- a/maud/src/lib.rs +++ b/maud/src/lib.rs @@ -343,6 +343,51 @@ mod actix_support { } } +#[cfg(feature = "ntex")] +mod ntex_support { + use core::{ + error::Error, + mem, + task::{Context, Poll}, + }; + use ntex::{ + http::{ + body::{BodySize, MessageBody}, + header, StatusCode, + }, + util::Bytes, + web::{ErrorRenderer, HttpRequest, HttpResponse, Responder}, + }; + + use crate::PreEscaped; + use alloc::{rc::Rc, string::String}; + + impl MessageBody for PreEscaped { + fn size(&self) -> BodySize { + self.0.size() + } + + fn poll_next_chunk( + &mut self, + _: &mut Context<'_>, + ) -> Poll>>> { + if self.0.is_empty() { + Poll::Ready(None) + } else { + Poll::Ready(Some(Ok(Bytes::from(mem::take(&mut self.0).into_bytes())))) + } + } + } + + impl Responder for PreEscaped { + async fn respond_to(self, _: &HttpRequest) -> HttpResponse { + HttpResponse::build(StatusCode::OK) + .header(header::CONTENT_TYPE, "text/html; charset=utf-8") + .body(self.0) + } + } +} + #[cfg(feature = "tide")] mod tide_support { use crate::PreEscaped; From d7b5cb15cd41a796cd25551e8f0dfa5f5a2ee213 Mon Sep 17 00:00:00 2001 From: David Miguel Date: Sun, 28 Sep 2025 16:53:14 +0100 Subject: [PATCH 2/4] Update docs/content/web-frameworks.md Co-authored-by: Chris Wong --- docs/content/web-frameworks.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/web-frameworks.md b/docs/content/web-frameworks.md index 377f07e4..ee7abb2f 100644 --- a/docs/content/web-frameworks.md +++ b/docs/content/web-frameworks.md @@ -317,7 +317,7 @@ maud = { version = "*", features = ["ntex"] } # ... ``` -Actix request handlers can use a `Markup` that implements the `ntex::web::Responder` trait. +ntex request handlers can use a `Markup` that implements the `ntex::web::Responder` trait. ```rust,no_run use ntex::web::{get, App, HttpServer, Responder}; From 5fc59fcbd6e7af840b1d797a5280f9e69b4169a7 Mon Sep 17 00:00:00 2001 From: dvdmgl Date: Sun, 28 Sep 2025 18:38:46 +0100 Subject: [PATCH 3/4] Use ntex String.poll_next_chunk --- maud/src/lib.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/maud/src/lib.rs b/maud/src/lib.rs index 02b8c12f..f7c6807a 100644 --- a/maud/src/lib.rs +++ b/maud/src/lib.rs @@ -347,7 +347,6 @@ mod actix_support { mod ntex_support { use core::{ error::Error, - mem, task::{Context, Poll}, }; use ntex::{ @@ -369,13 +368,9 @@ mod ntex_support { fn poll_next_chunk( &mut self, - _: &mut Context<'_>, + cx: &mut Context<'_>, ) -> Poll>>> { - if self.0.is_empty() { - Poll::Ready(None) - } else { - Poll::Ready(Some(Ok(Bytes::from(mem::take(&mut self.0).into_bytes())))) - } + self.0.poll_next_chunk(cx) } } From 5392d5151c750aba5f0b5fc16739673e7f637d43 Mon Sep 17 00:00:00 2001 From: dvdmgl Date: Sat, 4 Oct 2025 00:46:41 +0100 Subject: [PATCH 4/4] Add PreEscaped for ntex Body --- maud/src/lib.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/maud/src/lib.rs b/maud/src/lib.rs index f7c6807a..3e28ff23 100644 --- a/maud/src/lib.rs +++ b/maud/src/lib.rs @@ -351,7 +351,7 @@ mod ntex_support { }; use ntex::{ http::{ - body::{BodySize, MessageBody}, + body::{Body, BodySize, MessageBody}, header, StatusCode, }, util::Bytes, @@ -374,6 +374,18 @@ mod ntex_support { } } + impl From> for Body { + fn from(s: PreEscaped) -> Body { + s.0.into_bytes().into() + } + } + + impl<'a> From<&'a PreEscaped> for Body { + fn from(s: &'a PreEscaped) -> Body { + Body::Bytes(Bytes::copy_from_slice(AsRef::<[u8]>::as_ref(&s.0))) + } + } + impl Responder for PreEscaped { async fn respond_to(self, _: &HttpRequest) -> HttpResponse { HttpResponse::build(StatusCode::OK)