Skip to content

Commit 84f6124

Browse files
committed
feat(volo-http): support convert linkedbytes to body without copy
1 parent 370f852 commit 84f6124

4 files changed

Lines changed: 99 additions & 40 deletions

File tree

Cargo.lock

Lines changed: 25 additions & 25 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,3 +152,6 @@ codegen-units = 1
152152
panic = 'unwind'
153153
incremental = false
154154
overflow-checks = false
155+
156+
[patch.crates-io]
157+
linkedbytes = { git = "https://github.com/Ggiggle/linkedbytes.git", branch = "feat/into_iter" }

volo-http/Cargo.toml

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "volo-http"
3-
version = "0.3.1"
3+
version = "0.3.2"
44
edition.workspace = true
55
homepage.workspace = true
66
repository.workspace = true
@@ -22,6 +22,7 @@ maintenance = { status = "actively-developed" }
2222
volo = { version = "0.10", path = "../volo" }
2323

2424
ahash.workspace = true
25+
async-stream.workspace = true
2526
bytes.workspace = true
2627
faststr.workspace = true
2728
futures.workspace = true
@@ -32,6 +33,7 @@ http-body-util.workspace = true
3233
hyper.workspace = true
3334
hyper-util = { workspace = true, features = ["tokio"] }
3435
itoa.workspace = true
36+
linkedbytes.workspace = true
3537
metainfo.workspace = true
3638
mime.workspace = true
3739
motore.workspace = true
@@ -55,14 +57,14 @@ url.workspace = true
5557
# =====optional=====
5658

5759
# server optional
58-
ipnet = { workspace = true, optional = true } # client ip
59-
matchit = { workspace = true, optional = true } # route matching
60-
memchr = { workspace = true, optional = true } # sse
60+
ipnet = { workspace = true, optional = true } # client ip
61+
matchit = { workspace = true, optional = true } # route matching
62+
memchr = { workspace = true, optional = true } # sse
6163
scopeguard = { workspace = true, optional = true } # defer
6264

6365
# client optional
64-
async-broadcast = { workspace = true, optional = true } # service discover
65-
chrono = { workspace = true, optional = true } # stat
66+
async-broadcast = { workspace = true, optional = true } # service discover
67+
chrono = { workspace = true, optional = true } # stat
6668
hickory-resolver = { workspace = true, optional = true } # dns resolver
6769
mime_guess = { workspace = true, optional = true }
6870

@@ -100,24 +102,37 @@ default-client = ["client", "json"]
100102
default-server = ["server", "query", "form", "json", "multipart"]
101103

102104
full = [
103-
"client", "server", # core
104-
"query", "form", "json", # serde
105-
"tls", # https
106-
"cookie", "multipart", "ws", # exts
105+
"client",
106+
"server", # core
107+
"query",
108+
"form",
109+
"json", # serde
110+
"tls", # https
111+
"cookie",
112+
"multipart",
113+
"ws", # exts
107114
]
108115

109116
http1 = ["hyper/http1", "hyper-util/http1"]
110117

111118
client = [
112-
"http1", "hyper/client",
113-
"dep:async-broadcast", "dep:chrono", "dep:hickory-resolver",
119+
"http1",
120+
"hyper/client",
121+
"dep:async-broadcast",
122+
"dep:chrono",
123+
"dep:hickory-resolver",
114124
] # client core
115125
server = [
116-
"http1", "hyper-util/server",
117-
"dep:ipnet", "dep:matchit", "dep:memchr", "dep:scopeguard", "dep:mime_guess",
126+
"http1",
127+
"hyper-util/server",
128+
"dep:ipnet",
129+
"dep:matchit",
130+
"dep:memchr",
131+
"dep:scopeguard",
132+
"dep:mime_guess",
118133
] # server core
119134

120-
__serde = ["dep:serde"] # a private feature for enabling `serde` by `serde_xxx`
135+
__serde = ["dep:serde"] # a private feature for enabling `serde` by `serde_xxx`
121136
query = ["__serde", "dep:serde_urlencoded"]
122137
form = ["__serde", "dep:serde_urlencoded"]
123138
json = ["__serde", "dep:sonic-rs"]

volo-http/src/body.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use futures_util::stream::Stream;
1616
use http_body::{Frame, SizeHint};
1717
use http_body_util::{combinators::BoxBody, BodyExt, Full, StreamBody};
1818
use hyper::body::Incoming;
19+
use linkedbytes::{LinkedBytes, Node};
1920
use pin_project::pin_project;
2021
#[cfg(feature = "json")]
2122
use serde::de::DeserializeOwned;
@@ -332,3 +333,43 @@ impl From<String> for Body {
332333
}
333334
}
334335
}
336+
337+
impl From<LinkedBytes> for Body {
338+
fn from(value: LinkedBytes) -> Self {
339+
let stream = async_stream::stream! {
340+
for node in value.into_iter_list() {
341+
match node {
342+
Node::Bytes(bytes) => {
343+
yield Ok(Frame::data(bytes));
344+
}
345+
Node::BytesMut(bytes) => {
346+
yield Ok(Frame::data(bytes.freeze()));
347+
}
348+
Node::FastStr(faststr) => {
349+
yield Ok(Frame::data(faststr.into_bytes()));
350+
}
351+
}
352+
}
353+
};
354+
Self {
355+
repr: BodyRepr::Stream(StreamBody::new(Box::pin(stream))),
356+
}
357+
}
358+
}
359+
360+
#[cfg(test)]
361+
mod tests {
362+
use super::*;
363+
364+
#[tokio::test]
365+
async fn test_from_linked_bytes() {
366+
let mut bytes = LinkedBytes::new();
367+
bytes.insert(Bytes::from_static(b"Hello,"));
368+
bytes.insert_faststr(FastStr::new(" world!"));
369+
let body = Body::from(bytes);
370+
assert_eq!(
371+
body.into_bytes().await.unwrap(),
372+
Bytes::from_static(b"Hello, world!")
373+
);
374+
}
375+
}

0 commit comments

Comments
 (0)