stripe_types/
pagination.rs1use std::fmt::Debug;
2use std::str::FromStr;
3
4use serde::{Serialize, Serializer};
5
6#[doc(hidden)]
7pub trait FromCursor {
8 fn from_cursor(val: &str) -> Option<Self>
9 where
10 Self: Sized;
11}
12
13impl FromCursor for smol_str::SmolStr {
14 fn from_cursor(val: &str) -> Option<Self> {
15 Self::from_str(val).ok()
16 }
17}
18
19impl<T: FromCursor> FromCursor for Option<T> {
20 fn from_cursor(val: &str) -> Option<Self> {
21 Some(T::from_cursor(val))
22 }
23}
24
25#[doc(hidden)]
26pub trait AsCursorOpt {
27 fn as_cursor_opt(&self) -> Option<&str>;
28}
29
30#[doc(hidden)]
31pub trait AsCursor {
32 fn as_cursor(&self) -> &str;
33}
34
35impl AsCursor for smol_str::SmolStr {
36 fn as_cursor(&self) -> &str {
37 self.as_str()
38 }
39}
40
41impl<T: AsCursor> AsCursorOpt for T {
42 fn as_cursor_opt(&self) -> Option<&str> {
43 Some(self.as_cursor())
44 }
45}
46
47impl<T: AsCursor> AsCursorOpt for Option<T> {
48 fn as_cursor_opt(&self) -> Option<&str> {
49 self.as_ref().map(|id| id.as_cursor())
50 }
51}
52
53pub trait Object {
55 type Id: AsCursorOpt + FromCursor;
57
58 fn id(&self) -> &Self::Id;
60
61 fn into_id(self) -> Self::Id;
63}
64
65#[derive(Debug)]
69#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
70pub struct List<T> {
71 pub data: Vec<T>,
73 pub has_more: bool,
75 pub url: String,
77}
78
79impl<T: Serialize> Serialize for List<T> {
84 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
85 where
86 S: Serializer,
87 {
88 use serde::ser::SerializeStruct;
89 let mut ser = serializer.serialize_struct("List", 5)?;
90 ser.serialize_field("data", &self.data)?;
91 ser.serialize_field("has_more", &self.has_more)?;
92 ser.serialize_field("url", &self.url)?;
93 ser.serialize_field("object", "list")?;
94 ser.end()
95 }
96}
97
98impl<T: Clone> Clone for List<T> {
99 fn clone(&self) -> Self {
100 List { data: self.data.clone(), has_more: self.has_more, url: self.url.clone() }
101 }
102}
103
104#[derive(Debug, Serialize)]
108#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
109pub struct SearchList<T> {
110 pub url: String,
112 pub has_more: bool,
114 pub data: Vec<T>,
116 pub next_page: Option<String>,
118 pub total_count: Option<u64>,
120}
121
122impl<T: Clone> Clone for SearchList<T> {
123 fn clone(&self) -> Self {
124 SearchList {
125 data: self.data.clone(),
126 has_more: self.has_more,
127 total_count: self.total_count,
128 url: self.url.clone(),
129 next_page: self.next_page.clone(),
130 }
131 }
132}
133
134#[doc(hidden)]
135mod impl_deserialize {
136 use miniserde::de::{Map, Visitor};
137 use miniserde::json::Value;
138 use miniserde::{Deserialize, Error, make_place};
139
140 use crate::miniserde_helpers::FromValueOpt;
141 use crate::{List, SearchList};
142 make_place!(Place);
143
144 impl<T: Deserialize> Deserialize for List<T> {
145 fn begin(out: &mut Option<Self>) -> &mut dyn Visitor {
146 Place::new(out)
147 }
148 }
149
150 impl<T: Deserialize> Visitor for Place<List<T>> {
151 fn map(&mut self) -> miniserde::Result<Box<dyn Map + '_>> {
152 Ok(Box::new(ListBuilder {
153 out: &mut self.out,
154 data: Deserialize::default(),
155 has_more: Deserialize::default(),
156 url: Deserialize::default(),
157 }))
158 }
159 }
160
161 struct ListBuilder<'a, T> {
162 out: &'a mut Option<List<T>>,
163 data: Option<Vec<T>>,
164 has_more: Option<bool>,
165 url: Option<String>,
166 }
167
168 impl<T: Deserialize> Map for ListBuilder<'_, T> {
169 fn key(&mut self, k: &str) -> miniserde::Result<&mut dyn Visitor> {
170 match k {
171 "url" => Ok(Deserialize::begin(&mut self.url)),
172 "data" => Ok(Deserialize::begin(&mut self.data)),
173 "has_more" => Ok(Deserialize::begin(&mut self.has_more)),
174 _ => Ok(<dyn Visitor>::ignore()),
175 }
176 }
177
178 fn finish(&mut self) -> miniserde::Result<()> {
179 let url = self.url.take().ok_or(Error)?;
180 let data = self.data.take().ok_or(Error)?;
181 let has_more = self.has_more.ok_or(Error)?;
182 *self.out = Some(List { data, has_more, url });
183 Ok(())
184 }
185 }
186
187 impl<T: FromValueOpt> FromValueOpt for List<T> {
188 fn from_value(v: Value) -> Option<Self> {
189 let mut data: Option<Vec<T>> = None;
190 let mut has_more: Option<bool> = None;
191 let mut url: Option<String> = None;
192 let Value::Object(obj) = v else {
193 return None;
194 };
195 for (k, v) in obj {
196 match k.as_str() {
197 "has_more" => has_more = Some(bool::from_value(v)?),
198 "data" => data = Some(FromValueOpt::from_value(v)?),
199 "url" => url = Some(FromValueOpt::from_value(v)?),
200 _ => {}
201 }
202 }
203 Some(Self { data: data?, has_more: has_more?, url: url? })
204 }
205 }
206
207 impl<T: Deserialize> Deserialize for SearchList<T> {
208 fn begin(out: &mut Option<Self>) -> &mut dyn Visitor {
209 Place::new(out)
210 }
211 }
212
213 struct SearchListBuilder<'a, T> {
214 out: &'a mut Option<SearchList<T>>,
215 data: Option<Vec<T>>,
216 has_more: Option<bool>,
217 total_count: Option<Option<u64>>,
218 url: Option<String>,
219 next_page: Option<Option<String>>,
220 }
221
222 impl<T: Deserialize> Visitor for Place<SearchList<T>> {
223 fn map(&mut self) -> miniserde::Result<Box<dyn Map + '_>> {
224 Ok(Box::new(SearchListBuilder {
225 out: &mut self.out,
226 data: Deserialize::default(),
227 has_more: Deserialize::default(),
228 total_count: Deserialize::default(),
229 url: Deserialize::default(),
230 next_page: Deserialize::default(),
231 }))
232 }
233 }
234
235 impl<T: Deserialize> Map for SearchListBuilder<'_, T> {
236 fn key(&mut self, k: &str) -> miniserde::Result<&mut dyn Visitor> {
237 match k {
238 "url" => Ok(Deserialize::begin(&mut self.url)),
239 "data" => Ok(Deserialize::begin(&mut self.data)),
240 "has_more" => Ok(Deserialize::begin(&mut self.has_more)),
241 "total_count" => Ok(Deserialize::begin(&mut self.total_count)),
242 "next_page" => Ok(Deserialize::begin(&mut self.next_page)),
243 _ => Ok(<dyn Visitor>::ignore()),
244 }
245 }
246
247 fn finish(&mut self) -> miniserde::Result<()> {
248 let url = self.url.take().ok_or(Error)?;
249 let data = self.data.take().ok_or(Error)?;
250 let has_more = self.has_more.take().ok_or(Error)?;
251 let total_count = self.total_count.take().ok_or(Error)?;
252 let next_page = self.next_page.take().ok_or(Error)?;
253 *self.out = Some(SearchList { data, has_more, total_count, url, next_page });
254 Ok(())
255 }
256 }
257}