cat_dev/net/server/requestable/
body.rs1use crate::{
4 errors::CatBridgeError,
5 net::models::{FromRequest, Request},
6};
7use bytes::Bytes;
8use miette::Report;
9use std::fmt::{Debug, Formatter, Result as FmtResult};
10use valuable::{Fields, NamedField, NamedValues, StructDef, Structable, Valuable, Value, Visit};
11
12pub struct Body<BodyTy>(pub BodyTy);
16
17impl<BodyTy, ErrTy, State: Clone + Send + Sync + 'static> FromRequest<State> for Body<BodyTy>
18where
19 BodyTy: TryFrom<Bytes, Error = ErrTy>,
20 ErrTy: Into<Report> + Send + Sync + 'static,
21{
22 async fn from_request(req: Request<State>) -> Result<Self, CatBridgeError> {
23 BodyTy::try_from(req.body_owned())
24 .map(Body)
25 .map_err(Into::into)
26 .map_err(CatBridgeError::UnknownError)
27 }
28}
29
30impl<BodyTy> Debug for Body<BodyTy>
31where
32 BodyTy: Debug,
33{
34 fn fmt(&self, fmt: &mut Formatter<'_>) -> FmtResult {
35 fmt.debug_struct("Body").field("inner", &self.0).finish()
36 }
37}
38
39const BODY_FIELDS: &[NamedField<'static>] = &[NamedField::new("inner")];
40
41impl<BodyTy> Structable for Body<BodyTy>
42where
43 BodyTy: Valuable,
44{
45 fn definition(&self) -> StructDef<'_> {
46 StructDef::new_static("Body", Fields::Named(BODY_FIELDS))
47 }
48}
49
50impl<BodyTy> Valuable for Body<BodyTy>
51where
52 BodyTy: Valuable,
53{
54 fn as_value(&self) -> Value<'_> {
55 Value::Structable(self)
56 }
57
58 fn visit(&self, visitor: &mut dyn Visit) {
59 visitor.visit_named_fields(&NamedValues::new(BODY_FIELDS, &[self.0.as_value()]));
60 }
61}
62
63#[cfg(test)]
64mod unit_tests {
65 use super::*;
66 use crate::net::server::router::{Router, test_helpers::*};
67
68 #[tokio::test]
69 pub async fn test_extract_body() {
70 struct CustomTy(pub Vec<u8>);
71 impl CustomTy {
72 #[must_use]
73 pub fn to_added_bytes(self) -> Vec<u8> {
74 self.0.into_iter().map(|num| num + 1).collect::<Vec<_>>()
75 }
76 }
77 impl TryFrom<Bytes> for CustomTy {
78 type Error = CatBridgeError;
79
80 fn try_from(body: Bytes) -> Result<Self, Self::Error> {
81 let as_vec = Vec::<u8>::from(body);
82
83 assert_eq!(
84 as_vec,
85 vec![0x1, 0x2, 0x3],
86 "Body for custom type was not correct!"
87 );
88
89 Ok(Self(as_vec))
90 }
91 }
92
93 async fn echo_custom(Body(echo): Body<CustomTy>) -> Vec<u8> {
94 echo.to_added_bytes()
95 }
96 let mut router = Router::new();
97 router
98 .add_route(&[0x1], echo_custom)
99 .expect("Failed to add route!");
100 assert_eq!(
101 router_body_no_close(&mut router, &[0x1, 0x2, 0x3]).await,
102 &[0x2, 0x3, 0x4],
103 );
104 }
105}