Skip to content

Commit 6e243ac

Browse files
authored
activate Cow::Borrowed via IntoBody (#355)
* simplify `format::{Text, HTML}` bound: `Into<Cow<str>>` -> `Into<String>` * format: accept 'static body by `Cow::Borrowed` variant
1 parent 8cd2a0c commit 6e243ac

File tree

6 files changed

+44
-25
lines changed

6 files changed

+44
-25
lines changed

Diff for: ohkami/src/format/builtin/html.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
use crate::IntoBody;
2+
use std::borrow::Cow;
23

34
#[cfg(feature="openapi")]
45
use crate::openapi;
56

67

78
pub struct HTML<T = String>(pub T);
89

9-
impl<T: Into<std::borrow::Cow<'static, str>>> IntoBody for HTML<T> {
10+
impl<T: Into<Cow<'static, str>>> IntoBody for HTML<T> {
1011
const CONTENT_TYPE: &'static str = "text/html; charset=UTF-8";
11-
fn into_body(self) -> Result<Vec<u8>, impl std::fmt::Display> {
12-
let cow: std::borrow::Cow<'static, str> = self.0.into();
13-
Ok::<_, std::convert::Infallible>(cow.into_owned().into_bytes())
12+
13+
fn into_body(self) -> Result<Cow<'static, [u8]>, impl std::fmt::Display> {
14+
Result::<_, std::convert::Infallible>::Ok(match self.0.into() {
15+
Cow::Owned(s) => Cow::Owned(s.into_bytes()),
16+
Cow::Borrowed(s) => Cow::Borrowed(s.as_bytes()),
17+
})
1418
}
1519

1620
#[cfg(feature="openapi")]

Diff for: ohkami/src/format/builtin/json.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::{FromBody, IntoBody};
22
use super::bound::{self, Incoming, Outgoing};
3+
use std::borrow::Cow;
34

45
#[cfg(feature="openapi")]
56
use crate::openapi;
@@ -25,8 +26,8 @@ impl<T: Outgoing> IntoBody for JSON<T> {
2526
const CONTENT_TYPE: &'static str = "application/json";
2627

2728
#[inline]
28-
fn into_body(self) -> Result<Vec<u8>, impl std::fmt::Display> {
29-
serde_json::to_vec(&self.0)
29+
fn into_body(self) -> Result<Cow<'static, [u8]>, impl std::fmt::Display> {
30+
serde_json::to_vec(&self.0).map(Cow::Owned)
3031
}
3132

3233
#[cfg(feature="openapi")]

Diff for: ohkami/src/format/builtin/text.rs

+9-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::{FromBody, IntoBody};
2+
use std::borrow::Cow;
23

34
#[cfg(feature="openapi")]
45
use crate::openapi;
@@ -8,6 +9,7 @@ pub struct Text<T>(pub T);
89

910
impl<'req, T: From<&'req str>> FromBody<'req> for Text<T> {
1011
const MIME_TYPE: &'static str = "text/plain";
12+
1113
fn from_body(body: &'req [u8]) -> Result<Self, impl std::fmt::Display> {
1214
std::str::from_utf8(body).map(|s| Text(s.into()))
1315
}
@@ -18,11 +20,14 @@ impl<'req, T: From<&'req str>> FromBody<'req> for Text<T> {
1820
}
1921
}
2022

21-
impl<T: Into<std::borrow::Cow<'static, str>>> IntoBody for Text<T> {
23+
impl<T: Into<Cow<'static, str>>> IntoBody for Text<T> {
2224
const CONTENT_TYPE: &'static str = "text/plain; charset=UTF-8";
23-
fn into_body(self) -> Result<Vec<u8>, impl std::fmt::Display> {
24-
let cow: std::borrow::Cow<'static, str> = self.0.into();
25-
Ok::<_, std::convert::Infallible>(cow.into_owned().into_bytes())
25+
26+
fn into_body(self) -> Result<Cow<'static, [u8]>, impl std::fmt::Display> {
27+
Result::<_, std::convert::Infallible>::Ok(match self.0.into() {
28+
Cow::Owned(s) => Cow::Owned(s.into_bytes()),
29+
Cow::Borrowed(s) => Cow::Borrowed(s.as_bytes()),
30+
})
2631
}
2732

2833
#[cfg(feature="openapi")]

Diff for: ohkami/src/format/builtin/urlencoded.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::{FromBody, IntoBody};
22
use super::bound::{self, Incoming, Outgoing};
33
use ohkami_lib::serde_urlencoded;
4+
use std::borrow::Cow;
45

56
#[cfg(feature="openapi")]
67
use crate::openapi;
@@ -10,6 +11,7 @@ pub struct URLEncoded<T: bound::Schema>(pub T);
1011

1112
impl<'req, T: Incoming<'req>> FromBody<'req> for URLEncoded<T> {
1213
const MIME_TYPE: &'static str = "application/x-www-form-urlencoded";
14+
1315
fn from_body(body: &'req [u8]) -> Result<Self, impl std::fmt::Display> {
1416
serde_urlencoded::from_bytes(body).map(URLEncoded)
1517
}
@@ -22,8 +24,9 @@ impl<'req, T: Incoming<'req>> FromBody<'req> for URLEncoded<T> {
2224

2325
impl<T: Outgoing> IntoBody for URLEncoded<T> {
2426
const CONTENT_TYPE: &'static str = "application/x-www-form-urlencoded";
25-
fn into_body(self) -> Result<Vec<u8>, impl std::fmt::Display> {
26-
serde_urlencoded::to_string(&self.0).map(String::into_bytes)
27+
28+
fn into_body(self) -> Result<Cow<'static, [u8]>, impl std::fmt::Display> {
29+
serde_urlencoded::to_string(&self.0).map(|s| Cow::Owned(s.into_bytes()))
2730
}
2831

2932
#[cfg(feature="openapi")]

Diff for: ohkami/src/request/from_request.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ use crate::openapi;
1515
///
1616
/// <br>
1717
///
18-
/// ---
1918
/// *example.rs*
2019
/// ```
2120
/// use ohkami::prelude::*;
@@ -31,11 +30,12 @@ use crate::openapi;
3130
/// }
3231
/// }
3332
/// ```
34-
/// ---
3533
///
3634
/// <br>
3735
///
38-
/// NOTE: *MUST NOT impl both `FromRequest` and `FromParam` or `FromHeader`*.
36+
/// ### Note
37+
///
38+
/// *MUST NOT impl both `FromRequest` and `FromParam`*.
3939
pub trait FromRequest<'req>: Sized {
4040
/// If this extraction never fails, `std::convert::Infallible` is recomended.
4141
type Error: IntoResponse;

Diff for: ohkami/src/response/into_response.rs

+16-10
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ use crate::{Response, Status};
55
#[cfg(feature="openapi")]
66
use crate::openapi;
77

8+
use std::borrow::Cow;
9+
810

911
/// A trait implemented to be a returned value of a handler
1012
///
@@ -47,15 +49,15 @@ pub trait IntoBody {
4749
/// e.g. `text/html; charset=UTF-8`
4850
const CONTENT_TYPE: &'static str;
4951

50-
fn into_body(self) -> Result<Vec<u8>, impl std::fmt::Display>;
52+
fn into_body(self) -> Result<Cow<'static, [u8]>, impl std::fmt::Display>;
5153

5254
#[cfg(feature="openapi")]
5355
fn openapi_responsebody() -> impl Into<openapi::schema::SchemaRef>;
5456
}
5557
impl<B: IntoBody> IntoResponse for B {
5658
#[inline]
5759
fn into_response(self) -> Response {
58-
if Self::CONTENT_TYPE == "" {// removed by optimization if it's not ""
60+
if const {Self::CONTENT_TYPE.is_empty()} {// removed by optimization if it's not ""
5961
return Response::OK()
6062
}
6163

@@ -141,9 +143,9 @@ impl IntoBody for () {
141143
const CONTENT_TYPE: &'static str = "";
142144

143145
#[cold] #[inline(never)]
144-
fn into_body(self) -> Result<Vec<u8>, impl std::fmt::Display> {
146+
fn into_body(self) -> Result<Cow<'static, [u8]>, impl std::fmt::Display> {
145147
#[allow(unreachable_code)]
146-
{unreachable!("`into_body` of `()`") as Result<Vec<u8>, std::convert::Infallible>}
148+
{unreachable!("`into_body` of `()`") as Result<Cow<'static, [u8]>, std::convert::Infallible>}
147149
}
148150

149151
#[cfg(feature="openapi")]
@@ -155,13 +157,14 @@ impl IntoBody for () {
155157
}
156158

157159
macro_rules! text_response {
158-
($( $t:ty )*) => {$(
160+
($( $t:ty: $this:ident => $conv:expr ),*) => {$(
159161
impl IntoBody for $t {
160162
const CONTENT_TYPE: &'static str = "text/plain; charset=UTF-8";
161163

162164
#[inline(always)]
163-
fn into_body(self) -> Result<Vec<u8>, impl std::fmt::Display> {
164-
Ok::<_, std::convert::Infallible>(String::from(self).into_bytes())
165+
fn into_body(self) -> Result<Cow<'static, [u8]>, impl std::fmt::Display> {
166+
let $this = self;
167+
Ok::<_, std::convert::Infallible>($conv)
165168
}
166169

167170
#[cfg(feature="openapi")]
@@ -171,9 +174,12 @@ macro_rules! text_response {
171174
}
172175
)*};
173176
} text_response! {
174-
&'static str
175-
String
176-
std::borrow::Cow<'static, str>
177+
&'static str: s => Cow::Borrowed(s.as_bytes()),
178+
String: s => Cow::Owned(s.into_bytes()),
179+
Cow<'static, str>: s => match s {
180+
Cow::Owned(s) => Cow::Owned(s.into_bytes()),
181+
Cow::Borrowed(s) => Cow::Borrowed(s.as_bytes()),
182+
}
177183
}
178184

179185
#[cfg(feature="rt_worker")]

0 commit comments

Comments
 (0)