1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
use super::pagination::Pagination;
use super::pagination_config::PaginationConfig;

use actix_web::dev;
use actix_web::web;
use actix_web::FromRequest;
use actix_web::HttpRequest;
use futures_util::future;

impl FromRequest for Pagination {
    type Error = actix_web::Error;

    type Future = future::Ready<actix_web::Result<Self>>;

    type Config = ();

    fn from_request(req: &HttpRequest, _payload: &mut dev::Payload) -> Self::Future {
        future::ready(Pagination::parse(req))
    }
}

impl Pagination {
    pub(crate) fn parse(req: &HttpRequest) -> actix_web::Result<Pagination> {
        let config = req
            .app_data_resolved()
            .unwrap_or(&PaginationConfig::DEFAULT);

        let mut it = config.pagination();
        form_urlencoded::parse(req.query_string().as_bytes()).for_each(|(k, v)| match k {
            _ if k == config.page_name => it.page = config.parse_page(&v) as _,
            _ if k == config.per_page_name => it.per_page = config.parse_per_page(&v) as _,
            _ => {}
        });

        Ok(it)
    }
}

trait HttpRequestExt {
    fn app_data_resolved<T: 'static>(&self) -> Option<&T>;
}

impl HttpRequestExt for HttpRequest {
    fn app_data_resolved<T: 'static>(&self) -> Option<&T> {
        self.app_data()
            .or_else(|| self.app_data::<web::Data<T>>().map(|it| it.as_ref()))
    }
}