json_api/query/
page.rs

1use std::fmt::{self, Formatter};
2
3use serde::de::{Deserialize, Deserializer};
4use serde::ser::{Serialize, SerializeStruct, Serializer};
5
6/// Limit and offset based pagination parameters.
7#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
8pub struct Page {
9    /// The page number. This value is checked to be non-zero when a page is created via
10    /// the constructor method or decoded from a query string. If zero is passed to the
11    /// constructor or decoded from a query string, `1` will be used instead.
12    pub number: u64,
13
14    /// Optionally specifies the maximum number of items to include per page.
15    pub size: Option<u64>,
16
17    /// Private field for backwards compatibility.
18    _ext: (),
19}
20
21impl Page {
22    /// Returns a new `Page`. If zero is used for `number` it will be treated as `1`.
23    ///
24    /// # Example
25    ///
26    /// ```
27    /// # extern crate json_api;
28    /// #
29    /// # fn main() {
30    /// use json_api::query::Page;
31    /// assert_eq!(Page::new(1, None), Page::default());
32    /// # }
33    /// ```
34    pub fn new(number: u64, size: Option<u64>) -> Self {
35        let number = if number > 0 { number } else { 1 };
36
37        Page {
38            number,
39            size,
40            _ext: (),
41        }
42    }
43}
44
45impl Default for Page {
46    fn default() -> Self {
47        Page::new(1, None)
48    }
49}
50
51impl<'de> Deserialize<'de> for Page {
52    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
53    where
54        D: Deserializer<'de>,
55    {
56        use serde::de::{MapAccess, Visitor};
57
58        const FIELDS: &[&str] = &["number", "size"];
59
60        #[derive(Debug, Deserialize)]
61        #[serde(field_identifier, rename_all = "lowercase")]
62        enum Field {
63            Number,
64            Size,
65        }
66
67        struct PageVisitor;
68
69        impl<'de> Visitor<'de> for PageVisitor {
70            type Value = Page;
71
72            fn expecting(&self, f: &mut Formatter) -> fmt::Result {
73                write!(f, "an object containing json api pagination parameters")
74            }
75
76            fn visit_map<A>(self, mut access: A) -> Result<Self::Value, A::Error>
77            where
78                A: MapAccess<'de>,
79            {
80                let mut number = None;
81                let mut size = None;
82
83                while let Some(key) = access.next_key()? {
84                    match key {
85                        Field::Number => {
86                            number = access.next_value()?;
87                        }
88                        Field::Size => {
89                            size = access.next_value()?;
90                        }
91                    }
92                }
93
94                Ok(Page::new(number.unwrap_or(1), size))
95            }
96        }
97
98        deserializer.deserialize_struct("Page", FIELDS, PageVisitor)
99    }
100}
101
102impl Serialize for Page {
103    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
104    where
105        S: Serializer,
106    {
107        let mut state = serializer.serialize_struct("Page", 2)?;
108        let number = &self.number;
109        let size = &self.size;
110
111        if *number != 1 {
112            state.serialize_field("number", number)?;
113        }
114
115        if let Some(ref value) = *size {
116            state.serialize_field("size", value)?;
117        }
118
119        state.end()
120    }
121}
122
123#[cfg(test)]
124mod tests {
125    use super::Page;
126
127    #[test]
128    fn page_new() {
129        let mut page = Page::new(0, None);
130
131        // Page number should always be a positive unsigned integer.
132        // If 0 is passed to the constructor, it should be treated as 1.
133        assert_eq!(page.number, 1);
134        assert_eq!(page.size, None);
135
136        for number in 1..5 {
137            page = Page::new(number, None);
138
139            assert_eq!(page.number, number);
140            assert_eq!(page.size, None);
141        }
142
143        for size in (0..10).map(Some) {
144            page = Page::new(1, size);
145
146            assert_eq!(page.number, 1);
147            assert_eq!(page.size, size);
148        }
149    }
150}