1use core::{
4 cell::{Ref, RefCell, RefMut},
5 mem,
6};
7
8use super::{
9 body::{RequestBody, ResponseBody},
10 handler::FromRequest,
11 http::{BorrowReq, BorrowReqMut, IntoResponse, Request, RequestExt, WebRequest, WebResponse},
12};
13
14pub struct WebContext<'a, C = (), B = RequestBody> {
16 pub(crate) req: &'a mut WebRequest<()>,
17 pub(crate) body: &'a mut RefCell<B>,
18 pub(crate) ctx: &'a C,
19}
20
21impl<'a, C, B> WebContext<'a, C, B> {
22 pub(crate) fn new(req: &'a mut WebRequest<()>, body: &'a mut RefCell<B>, ctx: &'a C) -> Self {
23 Self { req, body, ctx }
24 }
25
26 #[inline]
50 pub fn reborrow(&mut self) -> WebContext<'_, C, B> {
51 WebContext {
52 req: self.req,
53 body: self.body,
54 ctx: self.ctx,
55 }
56 }
57
58 pub async fn extract<'r, T>(&'r self) -> Result<T, T::Error>
76 where
77 T: FromRequest<'r, Self>,
78 {
79 T::from_request(self).await
80 }
81
82 #[inline]
84 pub fn state(&self) -> &C {
85 self.ctx
86 }
87
88 #[inline]
90 pub fn req(&self) -> &WebRequest<()> {
91 self.req
92 }
93
94 #[inline]
96 pub fn req_mut(&mut self) -> &mut WebRequest<()> {
97 self.req
98 }
99
100 #[inline]
102 pub fn body(&self) -> Ref<'_, B> {
103 self.body.borrow()
104 }
105
106 #[inline]
108 pub fn body_borrow_mut(&self) -> RefMut<'_, B> {
109 self.body.borrow_mut()
110 }
111
112 #[inline]
116 pub fn body_get_mut(&mut self) -> &mut B {
117 self.body.get_mut()
118 }
119
120 pub fn take_request(&mut self) -> WebRequest<B>
121 where
122 B: Default,
123 {
124 let head = mem::take(self.req_mut());
125 let body = self.take_body_mut();
126 head.map(|ext| ext.map_body(|_| body))
127 }
128
129 #[inline]
133 pub fn into_response<ResB: Into<ResponseBody>>(self, body: ResB) -> WebResponse {
134 self.req.as_response(body.into())
135 }
136
137 #[inline]
141 pub fn as_response<ResB: Into<ResponseBody>>(&mut self, body: ResB) -> WebResponse {
142 self.req.as_response(body.into())
143 }
144
145 pub(crate) fn take_body_ref(&self) -> B
146 where
147 B: Default,
148 {
149 mem::take(&mut *self.body_borrow_mut())
150 }
151
152 pub(crate) fn take_body_mut(&mut self) -> B
153 where
154 B: Default,
155 {
156 mem::take(self.body_get_mut())
157 }
158}
159
160impl<C, B, T> BorrowReq<T> for WebContext<'_, C, B>
161where
162 Request<RequestExt<()>>: BorrowReq<T>,
163{
164 fn borrow(&self) -> &T {
165 self.req().borrow()
166 }
167}
168
169impl<C, B, T> BorrowReqMut<T> for WebContext<'_, C, B>
170where
171 Request<RequestExt<()>>: BorrowReqMut<T>,
172{
173 fn borrow_mut(&mut self) -> &mut T {
174 self.req_mut().borrow_mut()
175 }
176}
177
178#[cfg(test)]
179pub(crate) struct TestWebContext<C> {
180 pub(crate) req: Request<RequestExt<()>>,
181 pub(crate) body: RefCell<RequestBody>,
182 pub(crate) ctx: C,
183}
184
185#[cfg(test)]
186impl<C> TestWebContext<C> {
187 pub(crate) fn as_web_ctx(&mut self) -> WebContext<'_, C> {
188 WebContext {
189 req: &mut self.req,
190 body: &mut self.body,
191 ctx: &self.ctx,
192 }
193 }
194}
195
196#[cfg(test)]
197impl<C> WebContext<'_, C> {
198 pub(crate) fn new_test(ctx: C) -> TestWebContext<C> {
199 TestWebContext {
200 req: Request::new(RequestExt::default()),
201 body: RefCell::new(RequestBody::None),
202 ctx,
203 }
204 }
205}
206
207#[cfg(test)]
208mod test {
209 use xitca_unsafe_collection::futures::NowOrPanic;
210
211 use super::*;
212
213 #[test]
214 fn extract() {
215 use crate::handler::{path::PathRef, state::StateRef};
216
217 let mut ctx = WebContext::new_test(996usize);
218 let mut ctx = ctx.as_web_ctx();
219
220 *ctx.req_mut().uri_mut() = crate::http::Uri::from_static("/foo");
221
222 let StateRef(state) = ctx.extract().now_or_panic().ok().unwrap();
223
224 assert_eq!(*state, 996);
225
226 let PathRef(path) = ctx.extract().now_or_panic().ok().unwrap();
227
228 assert_eq!(path, "/foo");
229 }
230}