async_graphql/types/connection/
cursor.rs1use std::{
2 char::ParseCharError,
3 convert::Infallible,
4 fmt::Display,
5 num::{ParseFloatError, ParseIntError},
6 ops::{Deref, DerefMut},
7 str::ParseBoolError,
8};
9
10use serde::{Serialize, de::DeserializeOwned};
11
12use crate::ID;
13
14pub trait CursorType: Sized {
19 type Error: Display;
21
22 fn decode_cursor(s: &str) -> Result<Self, Self::Error>;
24
25 fn encode_cursor(&self) -> String;
27}
28
29macro_rules! cursor_type_int_impl {
30 ($($t:ty)*) => {$(
31 impl CursorType for $t {
32 type Error = ParseIntError;
33
34 fn decode_cursor(s: &str) -> Result<Self, Self::Error> {
35 s.parse()
36 }
37
38 fn encode_cursor(&self) -> String {
39 self.to_string()
40 }
41 }
42 )*}
43}
44
45cursor_type_int_impl! { isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 }
46
47impl CursorType for f32 {
48 type Error = ParseFloatError;
49
50 fn decode_cursor(s: &str) -> Result<Self, Self::Error> {
51 s.parse()
52 }
53
54 fn encode_cursor(&self) -> String {
55 self.to_string()
56 }
57}
58
59impl CursorType for f64 {
60 type Error = ParseFloatError;
61
62 fn decode_cursor(s: &str) -> Result<Self, Self::Error> {
63 s.parse()
64 }
65
66 fn encode_cursor(&self) -> String {
67 self.to_string()
68 }
69}
70
71impl CursorType for char {
72 type Error = ParseCharError;
73
74 fn decode_cursor(s: &str) -> Result<Self, Self::Error> {
75 s.parse()
76 }
77
78 fn encode_cursor(&self) -> String {
79 self.to_string()
80 }
81}
82
83impl CursorType for bool {
84 type Error = ParseBoolError;
85
86 fn decode_cursor(s: &str) -> Result<Self, Self::Error> {
87 s.parse()
88 }
89
90 fn encode_cursor(&self) -> String {
91 self.to_string()
92 }
93}
94
95impl CursorType for String {
96 type Error = Infallible;
97
98 fn decode_cursor(s: &str) -> Result<Self, Self::Error> {
99 Ok(s.to_string())
100 }
101
102 fn encode_cursor(&self) -> String {
103 self.clone()
104 }
105}
106
107impl CursorType for ID {
108 type Error = Infallible;
109
110 fn decode_cursor(s: &str) -> Result<Self, Self::Error> {
111 Ok(s.to_string().into())
112 }
113
114 fn encode_cursor(&self) -> String {
115 self.to_string()
116 }
117}
118
119#[cfg(feature = "chrono")]
120impl CursorType for chrono::DateTime<chrono::Utc> {
121 type Error = chrono::ParseError;
122
123 fn decode_cursor(s: &str) -> Result<Self, Self::Error> {
124 Ok(chrono::DateTime::parse_from_rfc3339(s)?.with_timezone::<chrono::Utc>(&chrono::Utc {}))
125 }
126
127 fn encode_cursor(&self) -> String {
128 self.to_rfc3339_opts(chrono::SecondsFormat::Micros, true)
129 }
130}
131
132#[cfg(feature = "uuid")]
133impl CursorType for uuid::Uuid {
134 type Error = uuid::Error;
135
136 fn decode_cursor(s: &str) -> Result<Self, Self::Error> {
137 s.parse()
138 }
139
140 fn encode_cursor(&self) -> String {
141 self.to_string()
142 }
143}
144
145pub struct OpaqueCursor<T>(pub T);
147
148impl<T> Deref for OpaqueCursor<T> {
149 type Target = T;
150
151 #[inline]
152 fn deref(&self) -> &Self::Target {
153 &self.0
154 }
155}
156
157impl<T> DerefMut for OpaqueCursor<T> {
158 #[inline]
159 fn deref_mut(&mut self) -> &mut Self::Target {
160 &mut self.0
161 }
162}
163
164impl<T> CursorType for OpaqueCursor<T>
165where
166 T: Serialize + DeserializeOwned,
167{
168 type Error = Box<dyn std::error::Error + Send + Sync>;
169
170 fn decode_cursor(s: &str) -> Result<Self, Self::Error> {
171 use base64::Engine;
172
173 let data = base64::engine::general_purpose::URL_SAFE_NO_PAD.decode(s)?;
174 Ok(Self(serde_json::from_slice(&data)?))
175 }
176
177 fn encode_cursor(&self) -> String {
178 use base64::Engine;
179
180 let value = serde_json::to_vec(&self.0).unwrap_or_default();
181 base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(value)
182 }
183}