1use std::fmt::{self, Display, Formatter};
2use std::ops::Neg;
3use std::str::FromStr;
4
5use serde::de::{Deserialize, Deserializer};
6use serde::ser::{Serialize, Serializer};
7
8use error::Error;
9use query::Path;
10use sealed::Sealed;
11use value::Stringify;
12
13#[derive(Clone, Debug, Eq, Hash, PartialEq)]
15pub struct Sort {
16 pub direction: Direction,
18
19 pub field: Path,
21
22 _ext: (),
24}
25
26impl Sort {
27 pub fn new(field: Path, direction: Direction) -> Self {
29 Sort {
30 direction,
31 field,
32 _ext: (),
33 }
34 }
35
36 pub fn reverse(&self) -> Self {
63 -self.clone()
64 }
65}
66
67impl Display for Sort {
68 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
69 f.write_str(&self.stringify())
70 }
71}
72
73impl FromStr for Sort {
74 type Err = Error;
75
76 fn from_str(value: &str) -> Result<Self, Self::Err> {
77 if value.starts_with('-') {
78 let field = (&value[1..]).parse()?;
79 Ok(Sort::new(field, Direction::Desc))
80 } else {
81 let field = value.parse()?;
82 Ok(Sort::new(field, Direction::Asc))
83 }
84 }
85}
86
87impl Neg for Sort {
88 type Output = Self;
89
90 fn neg(self) -> Self::Output {
91 Sort::new(self.field, -self.direction)
92 }
93}
94
95impl<'de> Deserialize<'de> for Sort {
96 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
97 where
98 D: Deserializer<'de>,
99 {
100 use serde::de::{Error, Visitor};
101
102 struct SortVisitor;
103
104 impl<'de> Visitor<'de> for SortVisitor {
105 type Value = Sort;
106
107 fn expecting(&self, f: &mut Formatter) -> fmt::Result {
108 write!(f, "a valid json api member name, optionally ")?;
109 write!(f, r#"prefixed with "-" to denote descending order"#)
110 }
111
112 fn visit_str<E: Error>(self, value: &str) -> Result<Self::Value, E> {
113 value.parse().map_err(Error::custom)
114 }
115 }
116
117 deserializer.deserialize_str(SortVisitor)
118 }
119}
120
121impl Serialize for Sort {
122 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
123 where
124 S: Serializer,
125 {
126 self.stringify().serialize(serializer)
127 }
128}
129
130impl Sealed for Sort {}
131
132impl Stringify for Sort {
133 fn to_bytes(&self) -> Vec<u8> {
134 let mut field = self.field.to_bytes();
135 let mut bytes = Vec::with_capacity(field.len() + 1);
136
137 if self.direction.is_desc() {
138 bytes.push(b'-');
139 }
140
141 bytes.append(&mut field);
142 bytes
143 }
144}
145
146#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
148pub enum Direction {
149 Asc,
151
152 Desc,
154}
155
156impl Direction {
157 pub fn is_asc(&self) -> bool {
177 *self == Direction::Asc
178 }
179
180 pub fn is_desc(&self) -> bool {
200 *self == Direction::Desc
201 }
202
203 pub fn reverse(&self) -> Self {
221 -*self
222 }
223}
224
225impl Neg for Direction {
226 type Output = Self;
227
228 fn neg(self) -> Self::Output {
229 match self {
230 Direction::Asc => Direction::Desc,
231 Direction::Desc => Direction::Asc,
232 }
233 }
234}
235
236#[cfg(test)]
237mod tests {
238 use super::{Direction, Sort};
239 use value::Path;
240
241 #[test]
242 fn direction_is_asc() {
243 assert_eq!(Direction::Asc.is_asc(), true);
244 assert_eq!(Direction::Desc.is_asc(), false);
245 }
246
247 #[test]
248 fn direction_is_desc() {
249 assert_eq!(Direction::Desc.is_desc(), true);
250 assert_eq!(Direction::Asc.is_desc(), false);
251 }
252
253 #[test]
254 fn direction_reverse() {
255 let asc = Direction::Asc;
256 let desc = Direction::Desc;
257
258 assert_eq!(asc.reverse(), desc);
259 assert_eq!(desc.reverse(), asc);
260 }
261
262 #[test]
263 fn sort_from_str() {
264 let field = "created-at".parse::<Path>().unwrap();
265 let mut sort = "created-at".parse::<Sort>().unwrap();
266
267 assert_eq!(sort.field, field);
268 assert_eq!(sort.direction, Direction::Asc);
269
270 sort = "-created-at".parse().unwrap();
271
272 assert_eq!(sort.field, field);
273 assert_eq!(sort.direction, Direction::Desc);
274 }
275
276 #[test]
277 fn sort_reverse() {
278 let field = "created-at".parse().unwrap();
279 let chrono = Sort::new(field, Direction::Asc);
280 let latest = chrono.reverse();
281
282 assert_eq!(chrono.field, latest.field);
283 assert_eq!(chrono.direction, Direction::Asc);
284 assert_eq!(latest.direction, Direction::Desc);
285 }
286
287 #[test]
288 fn sort_to_string() {
289 let sort = Sort::new("created-at".parse().unwrap(), Direction::Asc);
290
291 assert_eq!(sort.to_string(), "created-at");
292 assert_eq!(sort.reverse().to_string(), "-created-at");
293 }
294}