rubedo/
http.rs

1//! This module provides extensions to the [HTTP](https://crates.io/crates/http),
2//! [Hyper](https://crates.io/crates/hyper), and [Axum](https://crates.io/crates/axum)
3//! crates.
4//! 
5//! Hyper and Axum are built on top of the HTTP crate, and Axum uses parts of
6//! Hyper, so it makes sense to combine all of these in one module.
7
8
9
10//		Modules																											
11
12#[cfg(test)]
13#[path = "tests/http.rs"]
14mod tests;
15
16
17
18//		Packages																										
19
20use base64::{DecodeError, engine::{Engine as _, general_purpose::STANDARD as BASE64}};
21use bytes::Bytes;
22use core::{
23	cmp::Ordering,
24	convert::Infallible,
25	error::Error,
26	fmt::{Debug, Display, Write, self},
27	ops::{Add, AddAssign},
28	str::FromStr,
29};
30use futures::executor;
31use futures_util::FutureExt as _;
32use http::{Response, StatusCode};
33use http_body_util::{BodyExt as _, Collected, Full};
34use hyper::{
35	body::Incoming,
36	HeaderMap,
37	header::HeaderValue,
38};
39use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as DeError};
40use serde_json::Value as Json;
41use std::borrow::Cow;
42use thiserror::Error as ThisError;
43
44#[cfg(feature = "axum")]
45use ::{
46	axum::body::{Body as AxumBody, to_bytes},
47	core::mem,
48};
49
50
51
52//		Enums																											
53
54//		ContentType																
55/// The content type of an HTTP response, for use by [`UnpackedResponseBody`].
56/// 
57/// The content type is used to determine how to represent and interpret the
58/// response body when performing serialisation and deserialisation, including
59/// for display.
60/// 
61/// The default content type is [`Text`](ContentType::Text).
62/// 
63/// This enum is exhaustive and will never have any additional variants added
64/// to it, as all possibilities are already covered.
65/// 
66#[expect(clippy::exhaustive_enums, reason = "Exhaustive")]
67#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
68pub enum ContentType {
69	/// The response body is text. It will be represented as an ordinary
70	/// [`String`] when serialised.
71	#[default]
72	Text,
73	
74	/// The response body is binary. It will be represented as a [`String`]
75	/// in base64 format when serialised.
76	Binary,
77}
78
79//		ResponseError															
80/// The possible errors that can occur when working with an HTTP response.
81#[derive(Debug, ThisError)]
82#[non_exhaustive]
83pub enum ResponseError {
84	/// An error encountered while converting the response body to bytes.
85	#[error("Error encountered while converting response body to bytes: {0}")]
86	ConversionError(Box<dyn Error>),
87}
88
89
90
91//		Structs																											
92
93//		UnpackedResponse														
94/// An HTTP response in comparison-friendly form for interrogation.
95/// 
96/// Data in [`hyper::Response`] (and indeed [`http::Response`] as well) is
97/// stored in a specific form, made up of a header map object and a generic body
98/// type, which can be empty, a [`String`], or a streaming body future. This
99/// struct provides a way to use the data in a more accessible form, to allow it
100/// to be checked and compared. This is useful for testing, as the entire set of
101/// headers plus body can be checked all at once, and also for printing/logging.
102/// 
103/// If specific headers or body content needs to be checked, it is recommended
104/// to use the standard functions as they will be more efficient and performant.
105/// 
106/// Note that the [`body`](UnpackedResponse::body) property, which is stored as
107/// a vector of bytes, will get converted to a [`String`] if it is run through
108/// the standard [`Debug`] or [`Display`] formatters. This is because
109/// human-readable output is the intuitively-expected outcome in this situation.
110/// The behaviour can be controlled with the [`ContentType`] enum, which is used
111/// to determine whether the data is binary or text. If [`Text`](ContentType::Text),
112/// then the conversion uses [`from_utf8_lossy()`](String::from_utf8_lossy()),
113/// so no errors will occur, but if the body is not valid UTF8 then the
114/// resulting [`String`] will not be exactly the same. If an accurate
115/// representation of the body is required then it should be set to [`Binary`](ContentType::Binary),
116/// or else it should be extracted and converted to a `Vec<u8>` and then run
117/// through the [`Debug`] or [`Display`] formatters directly.
118/// 
119/// # See also
120/// 
121/// * [`axum::response`](https://docs.rs/axum/latest/axum/response/index.html)
122/// * [`axum::response::Response`](https://docs.rs/axum/latest/axum/response/type.Response.html)
123/// * [`http::Response`]
124/// * [`hyper::Response`]
125/// * [`ResponseExt`]
126/// * [`ResponseExt::unpack()`]
127/// * [`UnpackedResponseHeader`]
128/// 
129#[derive(Debug, Deserialize, Serialize)]
130#[non_exhaustive]
131pub struct UnpackedResponse {
132	//		Public properties													
133	/// The response status code. This is an enum, so is not directly comparable
134	/// to a number. The standard [`Display`] formatter will convert it to a
135	/// string in the format `"200 OK"`, but the standard [`FromStr`]
136	/// implementation will error if this is given back to it, as it expects
137	/// only `"200"`. Because this round-trip is basically broken, this struct
138	/// provides custom serialisation and deserialisation functions to convert
139	/// the status code to and from an actual number (a [`u16`]). This allows
140	/// the struct to be serialised and deserialised in a round-trip without
141	/// error, and is also the more intuitive representation of the status code
142	/// in serialised form such as JSON.
143	#[serde(serialize_with = "serialize_status_code", deserialize_with = "deserialize_status_code")]
144	pub status: StatusCode,
145	
146	/// The response headers. These are in a vector rather than a hashmap
147	/// because there may be multiple headers with the same name. They are
148	/// sorted by name, and then by value, allowing for reliable comparison.
149	/// Sorting does break the original order of the headers, but this should
150	/// only very rarely matter, even when logging, and sorting allows
151	/// duplicates to be spotted by eye more easily in logs.
152	pub headers: Vec<UnpackedResponseHeader>,
153	
154	/// The response body. This originates from the response body as a [`Bytes`]
155	/// container, but gets stored here as a vector of bytes for convenience.
156	/// This may not be valid UTF8, so is not converted to a [`String`]. That
157	/// step is left as optional for the caller, if required (and happens when
158	/// running the [`UnpackedResponse`] struct through the [`Debug`] or
159	/// [`Display`] formatters).
160	pub body:    UnpackedResponseBody,
161}
162
163//󰭅		UnpackedResponse														
164impl UnpackedResponse {
165	//		new																	
166	/// Creates a new unpacked response instance.
167	/// 
168	/// This constructor builds a new [`UnpackedResponse`] instance from the
169	/// response status code, header data, and body data. This is useful when
170	/// the parts 
171	/// 
172	/// # Parameters
173	/// 
174	/// * `status`  - The response status code. See [`status`](UnpackedResponse::status).
175	/// * `headers` - The response headers. See [`headers`](UnpackedResponse::headers).
176	/// * `body`    - The response body. See [`body`](UnpackedResponse::body).
177	/// 
178	#[must_use]
179	pub fn new<T: Into<UnpackedResponseBody>>(
180		status:  StatusCode,
181		headers: Vec<(String, String)>,
182		body:    T
183	) -> Self {
184		Self::new_from_parts(
185			status,
186			headers.into_iter().map(|(name, value)| UnpackedResponseHeader::new(name, value)).collect(),
187			body.into(),
188		)
189	}
190	
191	//		new_from_parts														
192	/// Creates a new unpacked response instance from existing parts.
193	/// 
194	/// This constructor builds a new [`UnpackedResponse`] instance from
195	/// constituent part instances that are already in the correct form. This is
196	/// useful when the parts are already available.
197	/// 
198	/// # Parameters
199	/// 
200	/// * `status`  - The response status code. See [`status`](UnpackedResponse::status).
201	/// * `headers` - The response headers. See [`headers`](UnpackedResponse::headers).
202	/// * `body`    - The response body. See [`body`](UnpackedResponse::body).
203	/// 
204	#[must_use]
205	pub const fn new_from_parts(
206		status:  StatusCode,
207		headers: Vec<UnpackedResponseHeader>,
208		body:    UnpackedResponseBody
209	) -> Self {
210		Self {
211			status,
212			headers,
213			body,
214		}
215	}
216}
217
218//󰭅		PartialEq																
219impl PartialEq for UnpackedResponse {
220	//		eq																	
221    fn eq(&self, other: &Self) -> bool {
222        self.status == other.status && self.headers == other.headers && self.body == other.body
223    }
224}
225
226//		UnpackedResponseHeader													
227/// An HTTP response header.
228/// 
229/// A simple representation of an HTTP response header as a key-value pair. The
230/// purpose of this struct is to formalise the data structure used by
231/// [`UnpackedResponse`] for storing headers.
232/// 
233/// No other properties are planned or logically considerable at present, and so
234/// this struct is seen as being exhaustive.
235/// 
236/// # See also
237/// 
238/// * [`UnpackedResponse`]
239/// 
240#[expect(clippy::exhaustive_structs, reason = "Exhaustive")]
241#[derive(Debug, Deserialize, Serialize)]
242pub struct UnpackedResponseHeader {
243	//		Public properties													
244	/// The response header name.
245	pub name:  String,
246	
247	/// The response header value.
248	pub value: String,
249}
250
251//󰭅		UnpackedResponseHeader													
252impl UnpackedResponseHeader {
253	//		new																	
254	/// Creates a new response header instance.
255	/// 
256	/// # Parameters
257	/// 
258	/// * `name`  - The response header name.
259	/// * `value` - The response header value.
260	/// 
261	#[must_use]
262	pub const fn new(name: String, value: String) -> Self {
263		Self {
264			name,
265			value,
266		}
267	}
268}
269
270//󰭅		PartialEq																
271impl PartialEq for UnpackedResponseHeader {
272	//		eq																	
273	fn eq(&self, other: &Self) -> bool {
274		self.name == other.name && self.value == other.value
275	}
276}
277
278//		UnpackedResponseBody													
279/// An HTTP response body.
280/// 
281/// A simple representation of an HTTP response body as a vector of bytes. The
282/// purpose of this struct is to formalise the data structure used by
283/// [`UnpackedResponse`] for storing the body.
284///
285/// The data originates from the response body as a [`Bytes`] container, but
286/// gets stored here as a vector of bytes for convenience. This may not be valid
287/// UTF8, so is not converted to a [`String`]. That step is left as optional for
288/// the caller, if required (and happens when running through the [`Debug`] or
289/// [`Display`] formatters).
290/// 
291/// The conversion to a [`String`] when run through the [`Debug`] and
292/// [`Display`] formatters is because human-readable output is the
293/// intuitively-expected outcome in this situation. The behaviour can be
294/// controlled with the [`ContentType`] enum, which is used to determine whether
295/// the data is binary or text. If [`Text`](ContentType::Text), then the
296/// conversion uses [`from_utf8_lossy()`](String::from_utf8_lossy()), so no
297/// errors will occur, but if the body is not valid UTF8 then the resulting
298/// [`String`] will not be exactly the same. If an accurate representation of
299/// the body is required then it should be set to [`Binary`](ContentType::Binary),
300/// or else it should be extracted and converted to a `Vec<u8>` and then run
301/// through the [`Debug`] or [`Display`] formatters directly.
302///
303/// This struct is very similar in nature to the standard Rust [`String`]
304/// struct, in that it is a wrapper around a vector of bytes, and so its design
305/// and function names are modelled after it. The main difference is that it
306/// does not require its contents to be valid UTF8, and also that it is a tuple
307/// struct rather than a regular struct.
308///
309/// Note that serialisation/deserialisation of this struct directly will produce
310/// and expect a [`String`], not a vector of bytes. This is because this is the
311/// most useful and fitting behaviour for the intended purpose, as with the
312/// implementations of [`Display`] and [`FromStr`]. As noted above, this is
313/// lossy if the [`ContentType`] is [`Text`](ContentType::Text) and the data is
314/// not valid UTF8, but not if set to [`Binary`](ContentType::Binary).
315/// 
316/// # See also
317/// 
318/// * [`UnpackedResponse`]
319/// 
320#[derive(Default)]
321#[non_exhaustive]
322pub struct UnpackedResponseBody {
323	//		Private properties													
324	/// The response body as a vector of bytes. The data originates from the
325	/// response body as a [`Bytes`] container, but gets stored here as a vector
326	/// of bytes for convenience. This may not be valid UTF8, so is not
327	/// converted to a [`String`]. That step is left as optional for the caller,
328	/// if required (and happens when running through the [`Debug`] or
329	/// [`Display`] formatters).
330	body:         Vec<u8>,
331	
332	/// The content type of the response body. This is used to determine how to
333	/// represent and interpret the response body when performing serialisation
334	/// and deserialisation, including for display. The default content type is
335	/// [`Text`](ContentType::Text).
336	content_type: ContentType,
337}
338
339//󰭅		UnpackedResponseBody													
340impl UnpackedResponseBody {
341	//		new																	
342	/// Creates a new response body instance.
343	/// 
344	/// # Parameters
345	/// 
346	/// * `data` - The response body as any type for which there is a [`From`]
347	///            implementation.
348	/// 
349	pub fn new<T: Into<Self>>(data: T) -> Self {
350		data.into()
351	}
352	
353	//		content_type														
354	/// Returns the content type of the response body.
355	/// 
356	/// # See also
357	///
358	/// * [`ContentType`]
359	/// * [`UnpackedResponseBody::is_binary()`]
360	/// * [`UnpackedResponseBody::is_text()`]
361	/// * [`UnpackedResponseBody::set_content_type()`]
362	/// 
363	#[must_use]
364	pub const fn content_type(&self) -> ContentType {
365		self.content_type
366	}
367	
368	//		set_content_type													
369	/// Sets the content type of the response body.
370	/// 
371	/// This method is chainable, as it returns a mutable reference to the
372	/// response body instance.
373	/// 
374	/// # See also
375	///
376	/// * [`ContentType`]
377	/// * [`UnpackedResponseBody::content_type()`]
378	/// 
379	pub const fn set_content_type(&mut self, content_type: ContentType) -> &mut Self {
380		self.content_type = content_type;
381		self
382	}
383	
384	//		is_binary															
385	/// Returns whether the response body is binary.
386	/// 
387	/// # See also
388	/// 
389	/// * [`ContentType`]
390	/// * [`UnpackedResponseBody::content_type()`]
391	/// * [`UnpackedResponseBody::is_text()`]
392	/// 
393	#[must_use]
394	pub fn is_binary(&self) -> bool {
395		self.content_type == ContentType::Binary
396	}
397	
398	//		is_text																
399	/// Returns whether the response body is text.
400	/// 
401	/// # See also
402	/// 
403	/// * [`ContentType`]
404	/// * [`UnpackedResponseBody::content_type()`]
405	/// * [`UnpackedResponseBody::is_binary()`]
406	/// 
407	#[must_use]
408	pub fn is_text(&self) -> bool {
409		self.content_type == ContentType::Text
410	}
411	
412	//		as_bytes															
413	/// Returns a byte slice of the response body's contents.
414	/// 
415	/// Provides a read-only view of the byte data within the response body,
416	/// without consuming the data. The returned slice is a reference to the
417	/// actual data stored in the response body, not a copy. Because of this, it
418	/// is not possible to mutate the contents of the response body through the
419	/// returned slice. It does not allocate new memory or change the ownership
420	/// of the byte data. This method is useful when you need to work with the
421	/// bytes of the response body in a read-only fashion, or when you want to
422	/// avoid copying the data.
423	/// 
424	///   - This method returns a slice (`&[u8]`) referencing the bytes of the
425	///     response body contents.
426	///   - The original response body value remains intact, and can still be
427	///     used afterward.
428	///   - No reallocation or copying of data occurs since it's just providing
429	///     a view into the original memory.
430	/// 
431	/// Use this method when you need to work with the byte data in a
432	/// non-destructive, read-only manner while keeping the original response
433	/// body intact.
434	///
435	/// # See also
436	/// 
437	/// * [`UnpackedResponseBody::as_mut_bytes()`]
438	/// * [`UnpackedResponseBody::into_bytes()`]
439	/// * [`UnpackedResponseBody::to_bytes()`]
440	/// 
441	#[must_use]
442	pub fn as_bytes(&self) -> &[u8] {
443		&self.body
444	}
445	
446	//		as_mut_bytes														
447	/// Returns a mutable referenced to the response body's contents.
448	/// 
449	/// Provides a mutable view of the byte data within the response body,
450	/// without consuming the data. The returned vector is a reference to the
451	/// actual data stored in the response body, not a copy. This method is
452	/// useful when you need to work with, and modify, the bytes of the response
453	/// body directly, without copying the data.
454	/// 
455	///   - This method returns a mutable vector (`&mut Vec<u8>`) referencing
456	///     the bytes of the response body contents.
457	///   - The original response body value remains intact, and can still be
458	///     used afterward.
459	///   - No reallocation or copying of data occurs since it's just providing
460	///     a reference to the original memory.
461	/// 
462	/// Use this method when you need to work directly with the byte data in a
463	/// mutable manner.
464	/// 
465	/// Note that unlike the function's [`String::as_mut_vec()`] counterpart,
466	/// this method is not unsafe. This is because the response body is not
467	/// required to be valid UTF8, so there is no risk of invalid UTF8 being
468	/// created.
469	/// 
470	/// Note also that a better name for this method could be `as_mut_vec()`,
471	/// which would be consistent with the standard library's
472	/// [`String::as_mut_vec()`] method, which this method is modelled after,
473	/// but that would break consistency with the other methods on this struct.
474	/// In addition, there is another method called [`str::as_bytes_mut()`],
475	/// which appears to be named quite inconsistently with other comparable
476	/// methods, and so calling this method `as_mut_bytes()` might cause
477	/// confusion, but is at least self-consistent.
478	/// 
479	/// # See also
480	/// 
481	/// * [`UnpackedResponseBody::as_bytes()`]
482	/// * [`UnpackedResponseBody::into_bytes()`]
483	/// * [`UnpackedResponseBody::to_bytes()`]
484	/// 
485	pub const fn as_mut_bytes(&mut self) -> &mut Vec<u8> {
486		&mut self.body
487	}
488	
489	//		into_bytes															
490	/// Returns the response body as a vector of bytes.
491	/// 
492	/// This consumes the response body, without cloning or copying, and returns
493	/// a new vector containing the bytes of the response body. It transfers
494	/// ownership of the byte data from the response body to the new vector.
495	/// This method is useful when you need to move the byte data out of the
496	/// response body, for example to pass it to a function that expects a
497	/// `Vec<u8>`, or when you want to modify the byte data in-place without
498	/// affecting the original response body.
499	/// 
500	///   - This method consumes the response body contents and returns a
501	///     `Vec<u8>` containing its bytes.
502	///   - After calling this method, the original response body value is no
503	///     longer available for use, because it has been moved.
504	///   - Transforms the response body into a vector of bytes without any
505	///     copying.
506	/// 
507	/// Use this method when you want to consume the response body and obtain
508	/// ownership of its byte data in the form of a `Vec<u8>`. This is useful
509	/// when you need to modify or move the byte data, or when you want to pass
510	/// it to functions that expect a `Vec<u8>`.
511	/// 
512	/// Note that a better name for this method might be `into_vec()`, but that
513	/// would be inconsistent with the standard library's
514	/// [`String::into_bytes()`] method, which this method is modelled after.
515	///
516	/// # See also
517	/// 
518	/// * [`UnpackedResponseBody::as_bytes()`]
519	/// * [`UnpackedResponseBody::as_mut_bytes()`]
520	/// * [`UnpackedResponseBody::to_bytes()`]
521	/// 
522	#[must_use]
523	pub fn into_bytes(self) -> Vec<u8> {
524		self.body
525	}
526	
527	//		to_bytes															
528	/// Returns a copy of the response body data converted to a vector of bytes.
529	/// 
530	/// This does not consume the response body, but clones it. Following Rust's
531	/// naming conventions and idioms, this method "converts" the data content
532	/// of the response body into a byte representation, in a `Vec<u8>`. (No
533	/// actual conversion takes place because the data is already stored
534	/// internally as a vector of bytes, but this is academic and could change
535	/// in future, so "conversion" is implied and expected as a theoretical
536	/// behaviour.) Ownership of the cloned and converted byte data is
537	/// transferred to the caller, and there are no side effects on the internal
538	/// state of the [`UnpackedResponseBody`] instance.
539	/// 
540	///   - This method returns a `Vec<u8>` vector of bytes without consuming
541	///     the response body contents.
542	///   - The original response body value remains intact, and can still be
543	///     used afterward.
544	///   - The response body data is copied, and converted/transformed into
545	///     the output value returned.
546	/// 
547	/// Use this method when you need to obtain a copy of the response body's
548	/// byte data in the form of a `Vec<u8>`, without consuming the response
549	/// body itself. This is useful when you need to pass the byte data to a
550	/// function that expects a `Vec<u8>`, or when you want to modify the byte
551	/// data without affecting the original response body.
552	/// 
553	/// Note that a better name for this method might be `to_vec()`, but that
554	/// would be inconsistent with the standard library's
555	/// [`String::into_bytes()`] method.
556	/// 
557	/// # See also
558	/// 
559	/// * [`UnpackedResponseBody::as_bytes()`]
560	/// * [`UnpackedResponseBody::as_mut_bytes()`]
561	/// * [`UnpackedResponseBody::into_bytes()`]
562	/// 
563	#[must_use]
564	pub fn to_bytes(&self) -> Vec<u8> {
565		self.body.clone()
566	}
567	
568	//		to_base64															
569	/// Returns the response body data converted to a base64-encoded [`String`].
570	/// 
571	/// This does not consume the response body, but clones it, as is necessary
572	/// to perform the conversion to base64. It converts straight from bytes to
573	/// base64, without converting to a [`String`] first, because the response
574	/// body is binary data.
575	/// 
576	/// # See also
577	/// 
578	/// * [`UnpackedResponseBody::from_base64()`]
579	/// 
580	#[must_use]
581	pub fn to_base64(&self) -> String {
582		BASE64.encode(&self.body)
583	}
584	
585	//		from_base64															
586	/// Converts a base64-encoded [`String`] to an [`UnpackedResponseBody`].
587	/// 
588	/// This method does not consume the input string, but clones it, as is
589	/// necessary to perform the conversion from [`base64`]. It converts
590	/// straight from base64 to bytes, without converting to a [`String`] first,
591	/// because the response body is binary data. This means that no UTF8
592	/// validation is performed.
593	/// 
594	/// Note that unlike the [`From`] type conversion implementations, this
595	/// returns a [`Result`].
596	/// 
597	/// # Errors
598	/// 
599	/// This method will return an error if the input string is not valid
600	/// base64. Such an error will be returned as a [`DecodeError`], which is
601	/// passed through from the [`base64`] crate.
602	/// 
603	/// # See also
604	/// 
605	/// * [`UnpackedResponseBody::to_base64()`]
606	/// 
607	pub fn from_base64(encoded: &str) -> Result<Self, DecodeError> {
608		let decoded = BASE64.decode(encoded)?;
609		Ok(Self { body: decoded, content_type: ContentType::Binary })
610	}
611	
612	//		clear																
613	/// Removes all contents from the response body.
614	/// 
615	/// This method removes all data from the response body, resetting it to an
616	/// empty state. This method has no effect on the capacity of the response
617	/// body, and so does not affect any allocation.
618	/// 
619	pub fn clear(&mut self) {
620		self.body.clear();
621	}
622	
623	//		empty																
624	/// Returns an empty response body.
625	/// 
626	/// This method returns an empty response body. This is equivalent to
627	/// creating a new response body with [`UnpackedResponseBody::new()`], but
628	/// without having to supply any parameters.
629	/// 
630	#[must_use]
631	pub fn empty() -> Self {
632		Self { body: Vec::new(), ..Default::default() }
633	}
634	
635	//		is_empty															
636	/// Returns whether the response body is empty.
637	/// 
638	/// This method returns whether the response body is empty. This is
639	/// equivalent to checking whether the length of the response body is zero.
640	/// 
641	#[must_use]
642	pub fn is_empty(&self) -> bool {
643		self.body.is_empty()
644	}
645	
646	//		len																	
647	/// Returns the length of the response body.
648	/// 
649	/// This method returns the length of the response body, in bytes. This is
650	/// equivalent to the length of the vector of bytes that the response body
651	/// contains.
652	/// 
653	#[must_use]
654	pub fn len(&self) -> usize {
655		self.body.len()
656	}
657	
658	//		push																
659	/// Appends a byte to the response body.
660	/// 
661	/// Appends a given byte onto the end of the response body's existing byte
662	/// data. The response body is not required to be valid UTF8, so this method
663	/// does not check the validity of the byte before appending it.
664	/// 
665	/// This method accepts a [`u8`] instead of a [`char`] because a [`char`]
666	/// represents a single Unicode scalar value. In Rust, a [`char`] is always
667	/// 4 bytes long because it can represent any Unicode scalar value,
668	/// including those outside the Basic Multilingual Plane. If `push()`
669	/// accepted a [`char`], it would be signaling that [`UnpackedResponseBody`]
670	/// is Unicode-aware and can handle any Unicode character — which is not the
671	/// case. A [`u8`], on the other hand, represents a single byte. By having
672	/// `push()` accept a [`u8`], it's signaling that [`UnpackedResponseBody`]
673	/// is byte-oriented. A specific [`push_char()`](UnpackedResponseBody::push_char())
674	/// method is also available, but `push()` is the most general method for
675	/// appending bytes to the response body.
676	/// 
677	/// # Parameters
678	/// 
679	/// * `byte` - The byte to append to the response body.
680	/// 
681	/// # See also
682	/// 
683	/// * [`UnpackedResponseBody::push_bytes()`]
684	/// * [`UnpackedResponseBody::push_char()`]
685	/// * [`UnpackedResponseBody::push_str()`]
686	/// 
687	pub fn push(&mut self, byte: u8) {
688		self.body.push(byte);
689	}
690	
691	//		push_bytes															
692	/// Appends a byte slice to the response body.
693	///
694	/// Appends a given byte slice onto the end of the response body. The byte
695	/// slice is appended to the end of the response body's existing byte data.
696	/// The response body is not required to be valid UTF8, so this method does
697	/// not check the validity of the byte slice before appending it.
698	///
699	/// # Parameters
700	///
701	/// * `bytes` - The byte slice to append to the response body.
702	///
703	/// # See also
704	///
705	/// * [`UnpackedResponseBody::push()`]
706	/// * [`UnpackedResponseBody::push_char()`]
707	/// * [`UnpackedResponseBody::push_str()`]
708	///
709	pub fn push_bytes(&mut self, bytes: &[u8]) {
710		self.body.extend_from_slice(bytes);
711	}
712	
713	//		push_char															
714	/// Appends a [`char`] to the response body.
715	///
716	/// Appends a given character onto the end of the response body. The
717	/// [`char`] is converted to bytes and then appended to the end of the
718	/// response body's existing byte data.
719	///
720	/// # Parameters
721	///
722	/// * `char` - The [`char`] to append to the response body.
723	///
724	/// # See also
725	///
726	/// * [`UnpackedResponseBody::push()`]
727	/// * [`UnpackedResponseBody::push_bytes()`]
728	/// * [`UnpackedResponseBody::push_str()`]
729	///
730	pub fn push_char(&mut self, char: &char) {
731		let mut bytes = [0; 4];
732		let used      = char.encode_utf8(&mut bytes).len();
733		#[expect(clippy::indexing_slicing, reason = "Infallible")]
734		self.body.extend(&bytes[..used]);
735	}
736	
737	//		push_str															
738	/// Appends a string slice to the response body.
739	/// 
740	/// Appends a given string slice onto the end of the response body. The
741	/// string slice is converted to bytes and then appended to the end of the
742	/// response body's existing byte data.
743	/// 
744	/// # Parameters
745	/// 
746	/// * `string` - The string slice to append to the response body.
747	/// 
748	/// # See also
749	/// 
750	/// * [`UnpackedResponseBody::push()`]
751	/// * [`UnpackedResponseBody::push_char()`]
752	/// * [`UnpackedResponseBody::push_bytes()`]
753	/// 
754	pub fn push_str(&mut self, string: &str) {
755		self.body.extend_from_slice(string.as_bytes());
756	}
757}
758
759//󰭅		Add &[u8]																
760impl Add<&[u8]> for UnpackedResponseBody {
761	type Output = Self;
762	
763	//		add																	
764	/// Adds a [`&[u8]`](https://doc.rust-lang.org/std/primitive.slice.html) to
765	/// an [`UnpackedResponseBody`].
766	fn add(mut self, rhs: &[u8]) -> Self {
767		self.push_bytes(rhs);
768		self
769	}
770}
771
772//󰭅		Add &[u8; N]															
773impl<const N: usize> Add<&[u8; N]> for UnpackedResponseBody {
774	type Output = Self;
775	
776	//		add																	
777	/// Adds a [`&[u8; N]`](https://doc.rust-lang.org/std/primitive.slice.html)
778	/// to an [`UnpackedResponseBody`].
779	fn add(mut self, rhs: &[u8; N]) -> Self {
780		self.push_bytes(rhs);
781		self
782	}
783}
784
785//󰭅		Add char																
786impl Add<char> for UnpackedResponseBody {
787	type Output = Self;
788	
789	//		add																	
790	/// Adds a [`char`] to an [`UnpackedResponseBody`].
791	fn add(mut self, rhs: char) -> Self {
792		self.push_char(&rhs);
793		self
794	}
795}
796
797//󰭅		Add &char																
798impl Add<&char> for UnpackedResponseBody {
799	type Output = Self;
800	
801	//		add																	
802	/// Adds a [`&char`](char) to an [`UnpackedResponseBody`].
803	fn add(mut self, rhs: &char) -> Self {
804		self.push_char(rhs);
805		self
806	}
807}
808
809//󰭅		Add &str																
810impl Add<&str> for UnpackedResponseBody {
811	type Output = Self;
812	
813	//		add																	
814	/// Adds a [`&str`](str) to an [`UnpackedResponseBody`].
815	fn add(mut self, rhs: &str) -> Self {
816		self.push_str(rhs);
817		self
818	}
819}
820
821//󰭅		Add String																
822impl Add<String> for UnpackedResponseBody {
823	type Output = Self;
824	
825	//		add																	
826	/// Adds a [`String`] to an [`UnpackedResponseBody`].
827	fn add(mut self, rhs: String) -> Self {
828		self.push_str(&rhs);
829		self
830	}
831}
832
833//󰭅		Add &String																
834impl Add<&String> for UnpackedResponseBody {
835	type Output = Self;
836	
837	//		add																	
838	/// Adds a [`&String`](String) to an [`UnpackedResponseBody`].
839	fn add(mut self, rhs: &String) -> Self {
840		self.push_str(rhs);
841		self
842	}
843}
844
845//󰭅		Add Box<str>															
846impl Add<Box<str>> for UnpackedResponseBody {
847	type Output = Self;
848	
849	//		add																	
850	/// Adds a [boxed](Box) [string](str) slice to an [`UnpackedResponseBody`].
851	fn add(mut self, rhs: Box<str>) -> Self::Output {
852		self.push_str(&rhs);
853		self
854	}
855}
856
857//󰭅		Add Cow<str>															
858impl<'a> Add<Cow<'a, str>> for UnpackedResponseBody {
859	type Output = Self;
860	
861	//		add																	
862	/// Adds a [clone-on-write](Cow) [string](str) to an
863	/// [`UnpackedResponseBody`].
864	fn add(mut self, rhs: Cow<'a, str>) -> Self::Output {
865		self.push_str(&rhs);
866		self
867	}
868}
869
870//󰭅		Add u8																	
871impl Add<u8> for UnpackedResponseBody {
872	type Output = Self;
873	
874	//		add																	
875	/// Adds a [`u8`] to an [`UnpackedResponseBody`].
876	fn add(mut self, rhs: u8) -> Self {
877		self.push(rhs);
878		self
879	}
880}
881
882//󰭅		Add Vec<u8>																
883impl Add<Vec<u8>> for UnpackedResponseBody {
884	type Output = Self;
885	
886	//		add																	
887	/// Adds a [`Vec[u8]`](Vec) to an [`UnpackedResponseBody`].
888	fn add(mut self, rhs: Vec<u8>) -> Self {
889		self.push_bytes(&rhs);
890		self
891	}
892}
893
894//󰭅		Add &Vec<u8>															
895impl Add<&Vec<u8>> for UnpackedResponseBody {
896	type Output = Self;
897	
898	//		add																	
899	/// Adds a [`&Vec[u8]`](Vec) to an [`UnpackedResponseBody`].
900	fn add(mut self, rhs: &Vec<u8>) -> Self {
901		self.push_bytes(rhs);
902		self
903	}
904}
905
906//󰭅		Add Self																
907impl Add<Self> for UnpackedResponseBody {
908	type Output = Self;
909	
910	//		add																	
911	/// Adds an [`UnpackedResponseBody`] to an [`UnpackedResponseBody`].
912	fn add(mut self, rhs: Self) -> Self {
913		self.push_bytes(&rhs.body);
914		self
915	}
916}
917
918//󰭅		Add &Self																
919impl Add<&Self> for UnpackedResponseBody {
920	type Output = Self;
921	
922	//		add																	
923	/// Adds an [`&UnpackedResponseBody`](UnpackedResponseBody) to an
924	/// [`UnpackedResponseBody`].
925	fn add(mut self, rhs: &Self) -> Self {
926		self.push_bytes(rhs.as_bytes());
927		self
928	}
929}
930
931//󰭅		AddAssign &[u8]															
932impl AddAssign<&[u8]> for UnpackedResponseBody {
933	//		add_assign															
934	/// Adds a [`&[u8]`](https://doc.rust-lang.org/std/primitive.slice.html) to
935	/// an [`UnpackedResponseBody`].
936	fn add_assign(&mut self, rhs: &[u8]) {
937		self.push_bytes(rhs);
938	}
939}
940
941//󰭅		AddAssign &[u8; N]														
942impl<const N: usize> AddAssign<&[u8; N]> for UnpackedResponseBody {
943	//		add_assign															
944	/// Adds a [`&[u8; N]`](https://doc.rust-lang.org/std/primitive.slice.html)
945	/// to an [`UnpackedResponseBody`].
946	fn add_assign(&mut self, rhs: &[u8; N]) {
947		self.push_bytes(rhs);
948	}
949}
950
951//󰭅		AddAssign char															
952impl AddAssign<char> for UnpackedResponseBody {
953	//		add_assign															
954	/// Adds a [`char`] to an [`UnpackedResponseBody`].
955	fn add_assign(&mut self, rhs: char) {
956		self.push_char(&rhs);
957	}
958}
959
960//󰭅		AddAssign &char															
961impl AddAssign<&char> for UnpackedResponseBody {
962	//		add_assign															
963	/// Adds a [`&char`](char) to an [`UnpackedResponseBody`].
964	fn add_assign(&mut self, rhs: &char) {
965		self.push_char(rhs);
966	}
967}
968
969//󰭅		AddAssign &str															
970impl AddAssign<&str> for UnpackedResponseBody {
971	//		add_assign															
972	/// Adds a [`&str`](str) to an [`UnpackedResponseBody`].
973	fn add_assign(&mut self, rhs: &str) {
974		self.push_str(rhs);
975	}
976}
977
978//󰭅		AddAssign String														
979impl AddAssign<String> for UnpackedResponseBody {
980	//		add_assign															
981	/// Adds a [`String`] to an [`UnpackedResponseBody`].
982	fn add_assign(&mut self, rhs: String) {
983		self.push_str(&rhs);
984	}
985}
986
987//󰭅		AddAssign &String														
988impl AddAssign<&String> for UnpackedResponseBody {
989	//		add_assign															
990	/// Adds a [`&String`](String) to an [`UnpackedResponseBody`].
991	fn add_assign(&mut self, rhs: &String) {
992		self.push_str(rhs);
993	}
994}
995
996//󰭅		AddAssign Box<str>														
997impl AddAssign<Box<str>> for UnpackedResponseBody {
998	//		add_assign															
999	/// Adds a [boxed](Box) [string](str) slice to an [`UnpackedResponseBody`].
1000	fn add_assign(&mut self, rhs: Box<str>) {
1001		self.push_str(&rhs);
1002	}
1003}
1004
1005//󰭅		AddAssign Cow<str>														
1006impl<'a> AddAssign<Cow<'a, str>> for UnpackedResponseBody {
1007	//		add_assign															
1008	/// Adds a [clone-on-write](Cow) [string](str) to an
1009	/// [`UnpackedResponseBody`].
1010	fn add_assign(&mut self, rhs: Cow<'a, str>){
1011		self.push_str(&rhs);
1012	}
1013}
1014
1015//󰭅		AddAssign u8															
1016impl AddAssign<u8> for UnpackedResponseBody {
1017	//		add_assign															
1018	/// Adds a [`u8`] to an [`UnpackedResponseBody`].
1019	fn add_assign(&mut self, rhs: u8) {
1020		self.push(rhs);
1021	}
1022}
1023
1024//󰭅		AddAssign Vec<u8>														
1025impl AddAssign<Vec<u8>> for UnpackedResponseBody {
1026	//		add_assign															
1027	/// Adds a [`Vec[u8]`](Vec) to an [`UnpackedResponseBody`].
1028	fn add_assign(&mut self, rhs: Vec<u8>) {
1029		self.push_bytes(&rhs);
1030	}
1031}
1032
1033//󰭅		AddAssign &Vec<u8>														
1034impl AddAssign<&Vec<u8>> for UnpackedResponseBody {
1035	//		add_assign															
1036	/// Adds a [`&Vec[u8]`](Vec) to an [`UnpackedResponseBody`].
1037	fn add_assign(&mut self, rhs: &Vec<u8>) {
1038		self.push_bytes(rhs);
1039	}
1040}
1041
1042//󰭅		AddAssign Self															
1043impl AddAssign<Self> for UnpackedResponseBody {
1044	//		add_assign															
1045	/// Adds an [`UnpackedResponseBody`] to an [`UnpackedResponseBody`].
1046	fn add_assign(&mut self, rhs: Self) {
1047		self.push_bytes(&rhs.body);
1048	}
1049}
1050
1051//󰭅		AddAssign &Self															
1052impl AddAssign<&Self> for UnpackedResponseBody {
1053	//		add_assign															
1054	/// Adds an [`&UnpackedResponseBody`](UnpackedResponseBody) to an
1055	/// [`UnpackedResponseBody`].
1056	fn add_assign(&mut self, rhs: &Self) {
1057		self.push_bytes(rhs.as_bytes());
1058	}
1059}
1060
1061//󰭅		AsMut [u8]																
1062impl AsMut<[u8]> for UnpackedResponseBody {
1063	//		as_mut																
1064	fn as_mut(&mut self) -> &mut [u8] {
1065		self.as_mut_bytes()
1066	}
1067}
1068
1069//󰭅		AsRef [u8]																
1070impl AsRef<[u8]> for UnpackedResponseBody {
1071	//		as_ref																
1072	fn as_ref(&self) -> &[u8] {
1073		self.as_bytes()
1074	}
1075}
1076
1077//󰭅		Clone																	
1078impl Clone for UnpackedResponseBody {
1079	//		clone																
1080	fn clone(&self) -> Self {
1081		Self { body: self.body.clone(), ..Default::default() }
1082	}
1083	
1084	//		clone_from															
1085	fn clone_from(&mut self, source: &Self) {
1086		self.body.clone_from(&source.body);
1087	}
1088}
1089
1090//󰭅		Debug																	
1091impl Debug for UnpackedResponseBody {
1092	//		fmt																	
1093	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1094		f.debug_struct("UnpackedResponseBody")
1095			.field("body",         &self.to_string())
1096			.field("content_type", &self.content_type)
1097			.finish()
1098	}
1099}
1100
1101//󰭅		Display																	
1102impl Display for UnpackedResponseBody {
1103	//		fmt																	
1104	/// Formats the response body for display.
1105	///
1106	/// This method serialises the response body based on the content type. If
1107	/// the content type is [`ContentType::Text`], then the response body is
1108	/// serialised to an ordinary [`String`]. If the content type is
1109	/// [`ContentType::Binary`], then the response body is serialised to a
1110	/// base64-encoded [`String`].
1111	///
1112	/// Note that as no validation checks are performed on the response body
1113	/// contents, it is not guaranteed to be UTF8, and therefore if not
1114	/// specified as binary it is possible that the serialised string will not
1115	/// totally match the original response body contents. This is because the
1116	/// conversion of the response body bytes to a UTF8 string will be lossy if
1117	/// there are invalid characters.
1118	/// 
1119	/// # See also
1120	/// 
1121	/// * [`UnpackedResponseBody::serialize()`]
1122	/// * [`UnpackedResponseBody::to_base64()`]
1123	/// 
1124	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1125		let body                =  match self.content_type {
1126			ContentType::Text   => String::from_utf8_lossy(&self.body),
1127			ContentType::Binary => Cow::Owned(self.to_base64()),
1128		};
1129		write!(f, "{body}")
1130	}
1131}
1132
1133//󰭅		From &[u8]																
1134impl From<&[u8]> for UnpackedResponseBody {
1135	//		from																
1136	/// Converts a [`&[u8]`](https://doc.rust-lang.org/std/primitive.slice.html)
1137	/// to an [`UnpackedResponseBody`].
1138	fn from(b: &[u8]) -> Self {
1139		Self { body: b.to_vec(), ..Default::default() }
1140	}
1141}
1142
1143//󰭅		From &[u8; N]															
1144impl<const N: usize> From<&[u8; N]> for UnpackedResponseBody {
1145	//		from																
1146	/// Converts a [`&[u8; N]`](https://doc.rust-lang.org/std/primitive.slice.html)
1147	/// to an [`UnpackedResponseBody`].
1148	fn from(b: &[u8; N]) -> Self {
1149		Self { body: b.to_vec(), ..Default::default() }
1150	}
1151}
1152
1153//󰭅		From char																
1154impl From<char> for UnpackedResponseBody {
1155	//		from																
1156	/// Converts a [`char`] to an [`UnpackedResponseBody`].
1157	/// 
1158	/// Note that it does this in the way that is most compatible with
1159	/// [`String`] conversion. The [`char`] type in Rust represents a Unicode
1160	/// scalar value. That means a single [`char`] value corresponds to one
1161	/// Unicode character. But Unicode characters can have a wide range of
1162	/// values, from `0` to `0x10FFFF` (this range excludes the surrogate
1163	/// pairs), and this value range doesn't fit into a single byte. That's why
1164	/// [`char`] in Rust is 4 bytes, because it has to accommodate any possible
1165	/// Unicode scalar value. The UTF-8 encoded representation of the `ñ`
1166	/// character is `[195, 177]`, but in memory, a [`char`] containing `'ñ'`
1167	/// does not hold the bytes `[195, 177]`. Instead, it holds the Unicode
1168	/// scalar value for `ñ`, which is `U+00F1`, or in integer terms, `241`.
1169	/// When we convert a [`char`] to a [`u32`] directly, we're taking this
1170	/// scalar value (like `241` for `ñ`) and representing it in memory as a
1171	/// 4-byte integer. So using code such as
1172	/// `(c as u32).to_le_bytes().to_vec()` would result in [241, 0, 0, 0], and
1173	/// not [195, 177]. This behaviour would not match expectation and would not
1174	/// match the behaviour of [`String`] conversion. To get the UTF-8 encoded
1175	/// bytes of a [`char`], we need to use encoding methods because we're
1176	/// effectively translating from the Unicode scalar value to its UTF-8 byte
1177	/// sequence. This is what the [`encode_utf8()`](char::encode_utf8()) method
1178	/// provides. To put it another way: [`char`] isn't storing bytes, it's
1179	/// storing a Unicode scalar value. UTF-8 is one of the ways to represent
1180	/// that value (and the most common one in Rust).
1181	/// 
1182	fn from(c: char) -> Self {
1183		let mut bytes = [0; 4];
1184		let used      = c.encode_utf8(&mut bytes).len();
1185		#[expect(clippy::indexing_slicing, reason = "Infallible")]
1186		Self { body: bytes[..used].to_vec(), ..Default::default() }
1187	}
1188}
1189
1190//󰭅		From &char																
1191impl From<&char> for UnpackedResponseBody {
1192	//		from																
1193	/// Converts a [`&char`](char) to an [`UnpackedResponseBody`].
1194	fn from(c: &char) -> Self {
1195		Self::from(c.to_owned())
1196	}
1197}
1198
1199//󰭅		From AxumBody															
1200#[cfg(feature = "axum")]
1201impl From<AxumBody> for UnpackedResponseBody {
1202	//		from																
1203	fn from(b: AxumBody) -> Self {
1204		Self { body: executor::block_on(to_bytes(b, usize::MAX)).unwrap_or_default().to_vec(), ..Default::default() }
1205	}
1206}
1207
1208//󰭅		From Full<Bytes>														
1209impl From<Full<Bytes>> for UnpackedResponseBody {
1210	//		from																
1211	/// Converts a [`Full<Bytes>`](Full) to an [`UnpackedResponseBody`].
1212	fn from(b: Full<Bytes>) -> Self {
1213		//	Collect the body into Collected<Bytes>
1214		let collected = b.collect().now_or_never()
1215			.unwrap_or_else(|| Ok(Collected::default()))
1216			.unwrap_or_else(|_| Collected::default())
1217		;
1218		Self { body: collected.to_bytes().to_vec(), ..Default::default() }
1219	}
1220}
1221
1222//󰭅		From Incoming															
1223impl From<Incoming> for UnpackedResponseBody {
1224	//		from																
1225	/// Converts an [`Incoming`] to an [`UnpackedResponseBody`].
1226	fn from(b: Incoming) -> Self {
1227		//	Collect the body into Collected<Bytes>
1228		let collected = executor::block_on(b.collect()).unwrap_or_else(|_| Collected::default());
1229		Self { body: collected.to_bytes().to_vec(), ..Default::default() }
1230	}
1231}
1232
1233//󰭅		From Json																
1234impl From<Json> for UnpackedResponseBody {
1235	//		from																
1236	/// Converts a [`serde_json::Value`] to an [`UnpackedResponseBody`].
1237	fn from(j: Json) -> Self {
1238		Self { body: j.to_string().into_bytes(), ..Default::default() }
1239	}
1240}
1241
1242//󰭅		From &Json																
1243impl From<&Json> for UnpackedResponseBody {
1244	//		from																
1245	/// Converts a [`&serde_json::Value`](serde_json::Value) to an
1246	/// [`UnpackedResponseBody`].
1247	fn from(j: &Json) -> Self {
1248		Self { body: j.to_string().into_bytes(), ..Default::default() }
1249	}
1250}
1251
1252//󰭅		From &str																
1253impl From<&str> for UnpackedResponseBody {
1254	//		from																
1255	/// Converts a [`&str`](str) to an [`UnpackedResponseBody`].
1256	fn from(s: &str) -> Self {
1257		Self { body: s.to_owned().as_bytes().to_vec(), ..Default::default() }
1258	}
1259}
1260
1261//󰭅		From &mut str															
1262impl From<&mut str> for UnpackedResponseBody {
1263	//		from																
1264	/// Converts a [`&mut str`](str) to an [`UnpackedResponseBody`].
1265	fn from(s: &mut str) -> Self {
1266		Self { body: s.to_owned().as_bytes().to_vec(), ..Default::default() }
1267	}
1268}
1269
1270//󰭅		From String																
1271impl From<String> for UnpackedResponseBody {
1272	//		from																
1273	/// Converts a [`String`] to an [`UnpackedResponseBody`].
1274	fn from(s: String) -> Self {
1275		Self { body: s.into_bytes(), ..Default::default() }
1276	}
1277}
1278
1279//󰭅		From &String															
1280impl From<&String> for UnpackedResponseBody {
1281	//		from																
1282	/// Converts a [`&String`](String) to an [`UnpackedResponseBody`].
1283	fn from(s: &String) -> Self {
1284		Self { body: s.as_str().as_bytes().to_vec(), ..Default::default() }
1285	}
1286}
1287
1288//󰭅		From Box<str>															
1289impl From<Box<str>> for UnpackedResponseBody {
1290	//		from																
1291	/// Converts a [boxed](Box) [string](str) slice to an
1292	/// [`UnpackedResponseBody`].
1293	fn from(s: Box<str>) -> Self {
1294		Self { body: s.into_string().into_bytes(), ..Default::default() }
1295	}
1296}
1297
1298//󰭅		From Cow<str>															
1299impl<'a> From<Cow<'a, str>> for UnpackedResponseBody {
1300	//		from																
1301	/// Converts a [clone-on-write](Cow) [string](str) to an
1302	/// [`UnpackedResponseBody`].
1303	fn from(s: Cow<'a, str>) -> Self {
1304		Self { body: s.into_owned().into_bytes(), ..Default::default() }
1305	}
1306}
1307
1308//󰭅		From u8																	
1309impl From<u8> for UnpackedResponseBody {
1310	//		from																
1311	/// Converts a [`u8`] to an [`UnpackedResponseBody`].
1312	fn from(c: u8) -> Self {
1313		Self { body: Vec::from([c]), ..Default::default() }
1314	}
1315}
1316
1317//󰭅		From Vec<u8>															
1318impl From<Vec<u8>> for UnpackedResponseBody {
1319	//		from																
1320	/// Converts a [`Vec[u8]`](Vec) to an [`UnpackedResponseBody`].
1321	fn from(v: Vec<u8>) -> Self {
1322		Self { body: v, ..Default::default() }
1323	}
1324}
1325
1326//󰭅		From &Vec<u8>															
1327impl From<&Vec<u8>> for UnpackedResponseBody {
1328	//		from																
1329	/// Converts a [`&Vec[u8]`](Vec) to an [`UnpackedResponseBody`].
1330	fn from(v: &Vec<u8>) -> Self {
1331		Self { body: v.clone(), ..Default::default() }
1332	}
1333}
1334
1335//󰭅		FromStr																	
1336impl FromStr for UnpackedResponseBody {
1337	type Err = Infallible;
1338	
1339	//		from_str															
1340	fn from_str(s: &str) -> Result<Self, Self::Err> {
1341		Ok(Self { body: s.as_bytes().to_vec(), ..Default::default() })
1342	}
1343}
1344
1345//󰭅		PartialEq																
1346impl PartialEq for UnpackedResponseBody {
1347	//		eq																	
1348	fn eq(&self, other: &Self) -> bool {
1349		self.body == other.body
1350	}
1351}
1352
1353//󰭅		Serialize																
1354impl Serialize for UnpackedResponseBody {
1355	//		serialize															
1356	/// Serialises the response body to a [`String`].
1357	/// 
1358	/// This method serialises the response body based on the content type. If
1359	/// the content type is [`ContentType::Text`], then the response body is
1360	/// serialised to an ordinary [`String`]. If the content type is
1361	/// [`ContentType::Binary`], then the response body is serialised to a
1362	/// base64-encoded [`String`].
1363	/// 
1364	/// Note that as no validation checks are performed on the response body
1365	/// contents, it is not guaranteed to be UTF8, and therefore if not
1366	/// specified as binary it is possible that the serialised string will not
1367	/// totally match the original response body contents. This is because the
1368	/// conversion of the response body bytes to a UTF8 string will be lossy if
1369	/// there are invalid characters.
1370	/// 
1371	/// # See also
1372	/// 
1373	/// * [`UnpackedResponseBody::deserialize()`]
1374	/// * [`UnpackedResponseBody::<Display>fmt()`]
1375	/// * [`UnpackedResponseBody::to_base64()`]
1376	/// 
1377	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1378	where
1379		S: Serializer,
1380	{
1381		serializer.serialize_str(&self.to_string())
1382	}
1383}
1384
1385//󰭅		Deserialize																
1386impl <'de> Deserialize<'de> for UnpackedResponseBody {
1387	//		deserialize															
1388	/// Deserialises the response body from a [`String`].
1389	/// 
1390	/// This method deserialises the response body based on the content type.
1391	/// However, as this method is not an instance method and it is not possible
1392	/// to specify the content type in advance, it has to try to detect it. It
1393	/// does this by attempting to decode the string as base64. If this succeeds
1394	/// then it will set the content type as [`ContentType::Binary`]. If this
1395	/// fails then it will assume the content type is [`ContentType::Text`], and
1396	/// deserialises the string in standard fashion.
1397	/// 
1398	/// Note that as the incoming data is from a [`String`], and Rust strings
1399	/// are are all valid UTF8, the resulting deserialised response body is
1400	/// guaranteed to be UTF8 if the content type is determined to be
1401	/// [`ContentType::Text`]. If base64 is detected then the deserialised bytes
1402	/// are not guaranteed to be valid UTF8, as no validation checks of that
1403	/// nature are performed against the response body.
1404	///
1405	/// # See also
1406	///
1407	/// * [`UnpackedResponseBody::deserialize()`]
1408	/// * [`UnpackedResponseBody::from_base64()`]
1409	///
1410	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1411	where
1412		D: Deserializer<'de>,
1413	{
1414		let string = String::deserialize(deserializer)?;
1415		#[expect(clippy::option_if_let_else, reason = "Using map_or_else() here would not be as clear, and no more concise")]
1416		match BASE64.decode(&string) {
1417			Ok(decoded) => Ok(Self { body: decoded,             content_type: ContentType::Binary }),
1418			Err(_)      => Ok(Self { body: string.into_bytes(), content_type: ContentType::Text }),
1419		}
1420	}
1421}
1422
1423//󰭅		Write																	
1424impl Write for UnpackedResponseBody {
1425	//		write_str															
1426	fn write_str(&mut self, s: &str) -> fmt::Result {
1427		self.push_str(s);
1428		Ok(())
1429	}
1430}
1431
1432
1433
1434//		Traits																											
1435
1436//§		ResponseExt																
1437/// This trait provides additional functionality to [`Response`].
1438pub trait ResponseExt {
1439	//		unpack																
1440	/// Returns an [`UnpackedResponse`] containing the unpacked response data.
1441	/// 
1442	/// This will unpack the response and provide the headers and body in a
1443	/// more accessible form, to allow it to be checked and compared. This is
1444	/// useful for testing, as the entire set of headers plus body can be
1445	/// checked all at once, and also for printing/logging.
1446	/// 
1447	/// If specific headers or body content needs to be checked, it is
1448	/// recommended to use the standard functions as they will be more
1449	/// efficient and performant. Notably, this function will consume the
1450	/// response body, which is necessary because the response might be
1451	/// streamed. In order to provide the full response, the whole body must be
1452	/// read first. This will obviously use more memory than would be used under
1453	/// normal circumstances, so it is not recommended to use this function
1454	/// without considering purpose and effect. For tests, ensuring a response
1455	/// body matches, this is fine, as the data is known and constrained, and
1456	/// memory/performance is less of a concern.
1457	/// 
1458	/// # Errors
1459	/// 
1460	/// This function will potentially return an error if the response body
1461	/// cannot be converted to bytes. This should not happen under normal
1462	/// circumstances, but it may be possible if the response body is streamed
1463	/// and the stream cannot be read. Many implementations of this function are
1464	/// in fact infallible.
1465	/// 
1466	/// At present [`ResponseError`] only contains one error variant, but it is
1467	/// possible that more will be added.
1468	/// 
1469	/// # See also
1470	/// 
1471	/// * [`axum::response`](https://docs.rs/axum/latest/axum/response/index.html)
1472	/// * [`axum::response::Response`](https://docs.rs/axum/latest/axum/response/type.Response.html)
1473	/// * [`http::Response`]
1474	/// * [`hyper::Response`]
1475	/// * [`UnpackedResponse`]
1476	/// 
1477	fn unpack(&mut self) -> Result<UnpackedResponse, ResponseError>;
1478}
1479
1480//󰭅		Response<()>															
1481impl ResponseExt for Response<()> {
1482	//		unpack																
1483	fn unpack(&mut self) -> Result<UnpackedResponse, ResponseError> {
1484		Ok(convert_response(self.status(), self.headers(), &Bytes::new()))
1485	}
1486}
1487
1488//󰭅		Response<AxumBody>														
1489#[cfg(feature = "axum")]
1490impl ResponseExt for Response<AxumBody> {
1491	//		unpack																
1492	fn unpack(&mut self) -> Result<UnpackedResponse, ResponseError> {
1493		let status  = self.status();
1494		let headers = self.headers().clone();
1495		let bytes   = executor::block_on(to_bytes(mem::replace(self.body_mut(), AxumBody::empty()), usize::MAX))
1496			.map_err(|e| ResponseError::ConversionError(Box::new(e)))?
1497		;
1498		Ok(convert_response(status, &headers, &bytes))
1499	}
1500}
1501
1502//󰭅		Response<Full<Bytes>>													
1503impl ResponseExt for Response<Full<Bytes>> {
1504	//		unpack																
1505	fn unpack(&mut self) -> Result<UnpackedResponse, ResponseError> {
1506		//	Collect the body into Collected<Bytes>
1507		let collected = self.body().clone().collect().now_or_never()
1508			.unwrap_or_else(|| Ok(Collected::default()))
1509			.map_err(|e| ResponseError::ConversionError(Box::new(e)))?
1510		;
1511		Ok(convert_response(self.status(), self.headers(), &collected.to_bytes()))
1512	}
1513}
1514
1515//󰭅		Response<Incoming>														
1516impl ResponseExt for Response<Incoming> {
1517	//		unpack																
1518	fn unpack(&mut self) -> Result<UnpackedResponse, ResponseError> {
1519		//	Collect the body into Collected<Bytes>
1520		let collected = executor::block_on(self.body_mut().collect())
1521			.map_err(|e| ResponseError::ConversionError(Box::new(e)))?
1522		;
1523		Ok(convert_response(self.status(), self.headers(), &collected.to_bytes()))
1524	}
1525}
1526
1527//󰭅		Response<String>														
1528impl ResponseExt for Response<String> {
1529	//		unpack																
1530	fn unpack(&mut self) -> Result<UnpackedResponse, ResponseError> {
1531		Ok(convert_response(self.status(), self.headers(), &Bytes::from(self.body().clone())))
1532	}
1533}
1534
1535
1536
1537//		Functions																										
1538
1539//		convert_headers															
1540/// Returns a vector of unpacked response headers.
1541/// 
1542/// These are returned in a vector rather than a hashmap because there may be
1543/// multiple headers with the same name. They are sorted by name, and then by
1544/// value, allowing for reliable comparison. Sorting does break the original
1545/// order of the headers, but this should only very rarely matter.
1546/// 
1547/// # See also
1548/// 
1549/// * [`ResponseExt::unpack()`]
1550/// * [`UnpackedResponse`]
1551/// * [`UnpackedResponseHeader`]
1552/// 
1553fn convert_headers(headermap: &HeaderMap<HeaderValue>) -> Vec<UnpackedResponseHeader> {
1554	let mut headers = vec![];
1555	#[expect(clippy::shadow_reuse, reason = "Clear purpose")]
1556	for (name, value) in headermap {
1557		let name    = name.as_str().to_owned();
1558		let value   = String::from_utf8_lossy(value.as_bytes()).into_owned();
1559		headers.push(UnpackedResponseHeader { name, value });
1560	}
1561	headers.sort_by(|a, b| {
1562		match a.name.cmp(&b.name) {
1563			Ordering::Equal   => a.value.cmp(&b.value),
1564			Ordering::Greater => Ordering::Greater,
1565			Ordering::Less    => Ordering::Less,
1566		}
1567	});
1568	headers
1569}
1570
1571//		convert_response														
1572/// Returns an [`UnpackedResponse`] containing the unpacked response data.
1573/// 
1574/// This function carries out the common part of the conversion process for
1575/// [`ResponseExt::unpack()`]. As [`unpack()`](ResponseExt::unpack()) has a
1576/// number of implementations, the common code is abstracted out into this
1577/// function.
1578/// 
1579/// # Parameters
1580/// 
1581/// * `status`  - The response status code.
1582/// * `headers` - The response headers.
1583/// * `body`    - The response body.
1584/// 
1585/// # See also
1586/// 
1587/// * [`axum::response`](https://docs.rs/axum/latest/axum/response/index.html)
1588/// * [`axum::response::Response`](https://docs.rs/axum/latest/axum/response/type.Response.html)
1589/// * [`http::Response`]
1590/// * [`hyper::Response`]
1591/// * [`ResponseExt::unpack()`]
1592/// * [`UnpackedResponse`]
1593/// * [`UnpackedResponseHeader`]
1594/// 
1595fn convert_response(
1596	status:  StatusCode,
1597	headers: &HeaderMap<HeaderValue>,
1598	body:    &Bytes,
1599) -> UnpackedResponse {
1600	UnpackedResponse {
1601		status,
1602		headers: convert_headers(headers),
1603		body:    UnpackedResponseBody { body: body.to_vec(), ..Default::default() },
1604	}
1605}
1606
1607//		serialize_status_code													
1608/// Returns the status code as a number.
1609/// 
1610/// This function is used by [`serde`] to serialise the status code as a number
1611/// rather than an enum. This is necessary because the [`UnpackedResponse`]
1612/// struct is used for comparison, and the status code is not directly
1613/// comparable to a number.
1614/// 
1615/// # Parameters
1616/// 
1617/// * `status_code` - The status code to serialise.
1618/// * `serializer`  - The serialiser to use.
1619/// 
1620/// # See also
1621/// 
1622/// * [`deserialize_status_code()`]
1623/// * [`http::StatusCode`]
1624/// * [`UnpackedResponse`]
1625/// 
1626#[expect(clippy::trivially_copy_pass_by_ref, reason = "Needs to match trait")]
1627fn serialize_status_code<S>(status_code: &StatusCode, serializer: S) -> Result<S::Ok, S::Error>
1628where
1629	S: Serializer,
1630{
1631	serializer.serialize_u16(status_code.as_u16())
1632}
1633
1634//		deserialize_status_code													
1635/// Returns the status code as an enum.
1636/// 
1637/// This function is used by [`serde`] to deserialise the status code as an
1638/// enum rather than a number. This is necessary because the
1639/// [`UnpackedResponse`] struct is used for comparison, and the status code is
1640/// not directly comparable to a number.
1641/// 
1642/// # Parameters
1643/// 
1644/// * `deserializer` - The deserialiser to use.
1645/// 
1646/// # See also
1647/// 
1648/// * [`http::StatusCode`]
1649/// * [`serialize_status_code()`]
1650/// * [`UnpackedResponse`]
1651/// 
1652fn deserialize_status_code<'de, D>(deserializer: D) -> Result<StatusCode, D::Error>
1653where
1654	D: Deserializer<'de>,
1655{
1656	let status_code_value: u16 = Deserialize::deserialize(deserializer)?;
1657	let status_code            = StatusCode::from_u16(status_code_value).map_err(DeError::custom)?;
1658	Ok(status_code)
1659}
1660
1661