Skip to content

Commit 8682e30

Browse files
KodrAusrusscam
authored andcommitted
Tweak Body trait impls to forward and support non-copy bodies (#42)
* tweak Body trait impls to forward and support non-copy bodies * make shell scripts executable
1 parent 4db5167 commit 8682e30

File tree

4 files changed

+61
-21
lines changed

4 files changed

+61
-21
lines changed

.ci/run-elasticsearch.sh

100644100755
File mode changed.

.ci/run-tests

100644100755
File mode changed.

elasticsearch/src/http/request.rs

Lines changed: 48 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,31 @@ use serde::Serialize;
99
/// expect JSON, however, there are some APIs that expect newline-delimited JSON (NDJSON).
1010
/// The [Body] trait allows modelling different API body implementations.
1111
pub trait Body {
12+
/// A ready-made immutable buffer that can be used to avoid writing
13+
///
14+
/// If this method returns `Some`, the bytes must be the same as
15+
/// what would be written by `write`.
16+
fn bytes(&self) -> Option<Bytes> {
17+
None
18+
}
19+
1220
/// Write to a buffer that will be written to the request stream
1321
fn write(&self, bytes: &mut BytesMut) -> Result<(), Error>;
1422
}
1523

24+
impl<'a, B: ?Sized> Body for &'a B
25+
where
26+
B: Body,
27+
{
28+
fn bytes(&self) -> Option<Bytes> {
29+
(**self).bytes()
30+
}
31+
32+
fn write(&self, bytes: &mut BytesMut) -> Result<(), Error> {
33+
(**self).write(bytes)
34+
}
35+
}
36+
1637
/// A JSON body of an API call.
1738
pub struct JsonBody<T>(pub(crate) T);
1839

@@ -78,42 +99,38 @@ where
7899
}
79100

80101
impl Body for Bytes {
102+
fn bytes(&self) -> Option<Bytes> {
103+
Some(self.clone())
104+
}
105+
81106
fn write(&self, bytes: &mut BytesMut) -> Result<(), Error> {
82-
bytes.resize(self.len(), 0);
83-
bytes.copy_from_slice(&self[..]);
84-
Ok(())
107+
self.as_ref().write(bytes)
85108
}
86109
}
87110

88111
impl Body for Vec<u8> {
89112
fn write(&self, bytes: &mut BytesMut) -> Result<(), Error> {
90-
bytes.resize(self.len(), 0);
91-
bytes.copy_from_slice(&self[..]);
92-
Ok(())
113+
self.as_slice().write(bytes)
93114
}
94115
}
95116

96-
impl Body for &'static [u8] {
117+
impl<'a> Body for &'a [u8] {
97118
fn write(&self, bytes: &mut BytesMut) -> Result<(), Error> {
98-
bytes.resize(self.len(), 0);
99-
bytes.copy_from_slice(&self[..]);
119+
bytes.reserve(self.len());
120+
bytes.put_slice(*self);
100121
Ok(())
101122
}
102123
}
103124

104125
impl Body for String {
105126
fn write(&self, bytes: &mut BytesMut) -> Result<(), Error> {
106-
bytes.resize(self.len(), 0);
107-
bytes.copy_from_slice(self.as_bytes());
108-
Ok(())
127+
self.as_bytes().write(bytes)
109128
}
110129
}
111130

112-
impl Body for &'static str {
131+
impl<'a> Body for &'a str {
113132
fn write(&self, bytes: &mut BytesMut) -> Result<(), Error> {
114-
bytes.resize(self.len(), 0);
115-
bytes.copy_from_slice(self.as_bytes());
116-
Ok(())
133+
self.as_bytes().write(bytes)
117134
}
118135
}
119136

@@ -131,7 +148,7 @@ mod tests {
131148

132149
#[test]
133150
fn serialize_into_jsonbody_writes_to_bytes() -> Result<(), failure::Error> {
134-
let mut bytes = BytesMut::with_capacity(21);
151+
let mut bytes = BytesMut::new();
135152
let body: JsonBody<_> = json!({"foo":"bar","baz":1}).into();
136153
let _ = body.write(&mut bytes)?;
137154
// NOTE: serde_json writes properties lexicographically
@@ -142,7 +159,7 @@ mod tests {
142159

143160
#[test]
144161
fn bodies_into_ndbody_writes_to_bytes() -> Result<(), failure::Error> {
145-
let mut bytes = BytesMut::with_capacity(22);
162+
let mut bytes = BytesMut::new();
146163
let mut bodies: Vec<JsonBody<_>> = Vec::with_capacity(2);
147164
bodies.push(json!({"item":1}).into());
148165
bodies.push(json!({"item":2}).into());
@@ -164,6 +181,19 @@ mod tests {
164181
Ok(())
165182
}
166183

184+
#[test]
185+
fn bytes_body_returns_usable_buf() -> Result<(), failure::Error> {
186+
let mut bytes_mut = BytesMut::with_capacity(21);
187+
let buf = bytes::Bytes::from(&b"{\"foo\":\"bar\",\"baz\":1}"[..]);
188+
189+
let bytes = buf.bytes().expect("bytes always returns Some");
190+
let _ = buf.write(&mut bytes_mut)?;
191+
assert_eq!(&buf[..], &bytes_mut[..]);
192+
assert_eq!(&bytes[..], &bytes_mut[..]);
193+
194+
Ok(())
195+
}
196+
167197
#[test]
168198
fn vec_body_writes_to_bytes_mut() -> Result<(), failure::Error> {
169199
let mut bytes_mut = BytesMut::with_capacity(21);

elasticsearch/src/http/transport.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,11 @@ impl Transport {
213213
}
214214
}
215215

216+
fn bytes_mut(&self) -> BytesMut {
217+
// NOTE: These could be pooled or re-used
218+
BytesMut::with_capacity(1024)
219+
}
220+
216221
/// Creates a new instance of a [Transport] configured with a
217222
/// [SingleNodeConnectionPool].
218223
pub fn single_node(url: &str) -> Result<Transport, Error> {
@@ -259,9 +264,14 @@ impl Transport {
259264
request_builder = request_builder.headers(headers);
260265

261266
if let Some(b) = body {
262-
let mut bytes_mut = BytesMut::with_capacity(1024);
263-
b.write(&mut bytes_mut)?;
264-
let bytes = bytes_mut.freeze();
267+
let bytes = if let Some(bytes) = b.bytes() {
268+
bytes
269+
} else {
270+
let mut bytes_mut = self.bytes_mut();
271+
b.write(&mut bytes_mut)?;
272+
bytes_mut.split().freeze()
273+
};
274+
265275
request_builder = request_builder.body(bytes);
266276
};
267277

0 commit comments

Comments
 (0)