armature_core/
response_buffer.rs1use bytes::{BufMut, Bytes, BytesMut};
34use std::ops::Deref;
35
36pub const DEFAULT_RESPONSE_CAPACITY: usize = 512;
43
44pub const MEDIUM_RESPONSE_CAPACITY: usize = 4096;
48
49pub const LARGE_RESPONSE_CAPACITY: usize = 65536;
53
54#[derive(Debug)]
59pub struct ResponseBuffer {
60 inner: BytesMut,
61}
62
63impl ResponseBuffer {
64 #[inline]
66 pub fn new() -> Self {
67 Self {
68 inner: BytesMut::with_capacity(DEFAULT_RESPONSE_CAPACITY),
69 }
70 }
71
72 #[inline]
74 pub fn with_capacity(capacity: usize) -> Self {
75 Self {
76 inner: BytesMut::with_capacity(capacity),
77 }
78 }
79
80 #[inline]
82 pub fn medium() -> Self {
83 Self::with_capacity(MEDIUM_RESPONSE_CAPACITY)
84 }
85
86 #[inline]
88 pub fn large() -> Self {
89 Self::with_capacity(LARGE_RESPONSE_CAPACITY)
90 }
91
92 #[inline]
94 pub fn len(&self) -> usize {
95 self.inner.len()
96 }
97
98 #[inline]
100 pub fn is_empty(&self) -> bool {
101 self.inner.is_empty()
102 }
103
104 #[inline]
106 pub fn remaining_capacity(&self) -> usize {
107 self.inner.capacity() - self.inner.len()
108 }
109
110 #[inline]
112 pub fn capacity(&self) -> usize {
113 self.inner.capacity()
114 }
115
116 #[inline]
118 pub fn write(&mut self, data: &[u8]) {
119 self.inner.extend_from_slice(data);
120 }
121
122 #[inline]
124 pub fn write_str(&mut self, s: &str) {
125 self.inner.extend_from_slice(s.as_bytes());
126 }
127
128 #[inline]
130 pub fn put(&mut self, data: &[u8]) {
131 self.inner.put_slice(data);
132 }
133
134 #[inline]
136 pub fn reserve(&mut self, additional: usize) {
137 self.inner.reserve(additional);
138 }
139
140 #[inline]
142 pub fn clear(&mut self) {
143 self.inner.clear();
144 }
145
146 #[inline]
148 pub fn freeze(self) -> Bytes {
149 self.inner.freeze()
150 }
151
152 #[inline]
154 pub fn as_slice(&self) -> &[u8] {
155 &self.inner
156 }
157
158 #[inline]
160 pub fn inner_mut(&mut self) -> &mut BytesMut {
161 &mut self.inner
162 }
163
164 #[inline]
166 pub fn into_inner(self) -> BytesMut {
167 self.inner
168 }
169
170 #[inline]
172 pub fn split(&mut self) -> Bytes {
173 self.inner.split().freeze()
174 }
175}
176
177impl Default for ResponseBuffer {
178 #[inline]
179 fn default() -> Self {
180 Self::new()
181 }
182}
183
184impl Deref for ResponseBuffer {
185 type Target = [u8];
186
187 #[inline]
188 fn deref(&self) -> &Self::Target {
189 &self.inner
190 }
191}
192
193impl AsRef<[u8]> for ResponseBuffer {
194 #[inline]
195 fn as_ref(&self) -> &[u8] {
196 &self.inner
197 }
198}
199
200impl AsMut<BytesMut> for ResponseBuffer {
201 #[inline]
202 fn as_mut(&mut self) -> &mut BytesMut {
203 &mut self.inner
204 }
205}
206
207impl From<ResponseBuffer> for Bytes {
208 #[inline]
209 fn from(buf: ResponseBuffer) -> Self {
210 buf.freeze()
211 }
212}
213
214impl From<ResponseBuffer> for BytesMut {
215 #[inline]
216 fn from(buf: ResponseBuffer) -> Self {
217 buf.inner
218 }
219}
220
221impl std::io::Write for ResponseBuffer {
222 #[inline]
223 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
224 self.inner.extend_from_slice(buf);
225 Ok(buf.len())
226 }
227
228 #[inline]
229 fn flush(&mut self) -> std::io::Result<()> {
230 Ok(())
231 }
232}
233
234#[derive(Debug)]
255pub struct ResponseBuilder {
256 status: u16,
257 headers: Vec<(String, String)>,
258 body: ResponseBuffer,
259}
260
261impl ResponseBuilder {
262 #[inline]
264 pub fn new() -> Self {
265 Self {
266 status: 200,
267 headers: Vec::with_capacity(8), body: ResponseBuffer::new(),
269 }
270 }
271
272 #[inline]
274 pub fn with_capacity(capacity: usize) -> Self {
275 Self {
276 status: 200,
277 headers: Vec::with_capacity(8),
278 body: ResponseBuffer::with_capacity(capacity),
279 }
280 }
281
282 #[inline]
284 pub fn status(mut self, status: u16) -> Self {
285 self.status = status;
286 self
287 }
288
289 #[inline]
291 pub fn header(mut self, name: impl Into<String>, value: impl Into<String>) -> Self {
292 self.headers.push((name.into(), value.into()));
293 self
294 }
295
296 #[inline]
298 pub fn content_type(self, value: impl Into<String>) -> Self {
299 self.header("Content-Type", value)
300 }
301
302 #[inline]
304 pub fn body(mut self, data: &[u8]) -> Self {
305 self.body.write(data);
306 self
307 }
308
309 #[inline]
311 pub fn body_str(mut self, s: &str) -> Self {
312 self.body.write_str(s);
313 self
314 }
315
316 #[inline]
318 pub fn body_json<T: serde::Serialize>(mut self, value: &T) -> Result<Self, crate::Error> {
319 let json =
320 crate::json::to_vec(value).map_err(|e| crate::Error::Serialization(e.to_string()))?;
321 self.body.write(&json);
322 self.headers
323 .push(("Content-Type".to_string(), "application/json".to_string()));
324 Ok(self)
325 }
326
327 #[inline]
329 pub fn body_mut(&mut self) -> &mut ResponseBuffer {
330 &mut self.body
331 }
332
333 #[inline]
335 pub fn build(self) -> crate::HttpResponse {
336 let mut response = crate::HttpResponse::new(self.status);
337 for (name, value) in self.headers {
338 response.headers.insert(name, value);
339 }
340 if !self.body.is_empty() {
341 response = response.with_bytes_body(self.body.freeze());
342 }
343 response
344 }
345}
346
347impl Default for ResponseBuilder {
348 #[inline]
349 fn default() -> Self {
350 Self::new()
351 }
352}
353
354#[inline]
363pub fn response_builder() -> ResponseBuilder {
364 ResponseBuilder::new()
365}
366
367#[inline]
369pub fn response_builder_with_capacity(capacity: usize) -> ResponseBuilder {
370 ResponseBuilder::with_capacity(capacity)
371}
372
373#[cfg(test)]
378mod tests {
379 use super::*;
380
381 #[test]
382 fn test_response_buffer_new() {
383 let buf = ResponseBuffer::new();
384 assert_eq!(buf.capacity(), DEFAULT_RESPONSE_CAPACITY);
385 assert!(buf.is_empty());
386 }
387
388 #[test]
389 fn test_response_buffer_write() {
390 let mut buf = ResponseBuffer::new();
391 buf.write(b"Hello, ");
392 buf.write(b"World!");
393 assert_eq!(buf.as_slice(), b"Hello, World!");
394 }
395
396 #[test]
397 fn test_response_buffer_no_realloc_small() {
398 let mut buf = ResponseBuffer::new();
399 let initial_cap = buf.capacity();
400
401 buf.write(b"Small response");
403
404 assert_eq!(buf.capacity(), initial_cap);
406 }
407
408 #[test]
409 fn test_response_buffer_freeze() {
410 let mut buf = ResponseBuffer::new();
411 buf.write(b"test data");
412 let bytes = buf.freeze();
413 assert_eq!(&*bytes, b"test data");
414 }
415
416 #[test]
417 fn test_response_buffer_medium() {
418 let buf = ResponseBuffer::medium();
419 assert_eq!(buf.capacity(), MEDIUM_RESPONSE_CAPACITY);
420 }
421
422 #[test]
423 fn test_response_buffer_large() {
424 let buf = ResponseBuffer::large();
425 assert_eq!(buf.capacity(), LARGE_RESPONSE_CAPACITY);
426 }
427
428 #[test]
429 fn test_response_builder() {
430 let response = ResponseBuilder::new()
431 .status(201)
432 .header("X-Custom", "value")
433 .body_str("Created")
434 .build();
435
436 assert_eq!(response.status, 201);
437 assert_eq!(response.headers.get("X-Custom"), Some(&"value".to_string()));
438 }
439
440 #[test]
441 fn test_response_builder_json() {
442 #[derive(serde::Serialize)]
443 struct Data {
444 message: &'static str,
445 }
446
447 let response = ResponseBuilder::new()
448 .status(200)
449 .body_json(&Data { message: "ok" })
450 .unwrap()
451 .build();
452
453 assert_eq!(response.status, 200);
454 assert!(
455 response
456 .headers
457 .get("Content-Type")
458 .unwrap()
459 .contains("json")
460 );
461 }
462
463 #[test]
464 fn test_http_response_with_capacity() {
465 let response = crate::HttpResponse::with_capacity(200, 1024);
466 assert_eq!(response.status, 200);
467 assert!(response.body.capacity() >= 1024);
469 }
470
471 #[test]
472 fn test_http_response_preallocated() {
473 let response = crate::HttpResponse::ok_preallocated();
474 assert_eq!(response.status, 200);
475 assert!(response.body.capacity() >= 512);
476 }
477
478 #[test]
479 fn test_response_builder_standalone() {
480 let response = response_builder()
481 .status(404)
482 .content_type("text/plain")
483 .body_str("Not Found")
484 .build();
485
486 assert_eq!(response.status, 404);
487 }
488
489 #[test]
490 fn test_response_buffer_io_write() {
491 use std::io::Write;
492
493 let mut buf = ResponseBuffer::new();
494 write!(buf, "Hello, World!").unwrap();
495 assert_eq!(buf.as_slice(), b"Hello, World!");
496 }
497}