s2_common/types/
resources.rs1use std::{fmt::Debug, num::NonZeroUsize, ops::Deref, str::FromStr};
2
3use compact_str::{CompactString, ToCompactString};
4
5#[derive(Debug, Default, Clone, PartialEq, Eq)]
6pub struct Page<T> {
7 pub values: Vec<T>,
8 pub has_more: bool,
9}
10
11impl<T> Page<T> {
12 pub fn new_empty() -> Self {
13 Self {
14 values: Vec::new(),
15 has_more: false,
16 }
17 }
18
19 pub fn new(values: impl Into<Vec<T>>, has_more: bool) -> Self {
20 Self {
21 values: values.into(),
22 has_more,
23 }
24 }
25}
26
27#[derive(Debug, Clone, Copy)]
28pub struct ListLimit(NonZeroUsize);
29
30impl ListLimit {
31 const MAX: NonZeroUsize = NonZeroUsize::new(1000).unwrap();
32
33 pub fn get(&self) -> NonZeroUsize {
34 self.0
35 }
36
37 pub fn as_usize(&self) -> usize {
38 self.0.get()
39 }
40}
41
42impl Default for ListLimit {
43 fn default() -> Self {
44 Self(Self::MAX)
45 }
46}
47
48impl From<usize> for ListLimit {
49 fn from(value: usize) -> Self {
50 Self(NonZeroUsize::new(value).unwrap_or(Self::MAX).min(Self::MAX))
51 }
52}
53
54impl From<ListLimit> for usize {
55 fn from(value: ListLimit) -> Self {
56 value.as_usize()
57 }
58}
59
60#[derive(Debug, Clone, Default)]
61pub struct ListItemsRequestParts<P, S> {
62 pub prefix: P,
63 pub start_after: S,
64 pub limit: ListLimit,
65}
66
67#[derive(Debug, Clone, Default)]
68pub struct ListItemsRequest<P, S>(ListItemsRequestParts<P, S>)
69where
70 P: Default,
71 S: Default;
72
73impl<P, S> ListItemsRequest<P, S>
74where
75 P: Default,
76 S: Default,
77{
78 pub fn parts(&self) -> &ListItemsRequestParts<P, S> {
79 &self.0
80 }
81}
82
83impl<P, S> From<ListItemsRequest<P, S>> for ListItemsRequestParts<P, S>
84where
85 P: Default,
86 S: Default,
87{
88 fn from(ListItemsRequest(parts): ListItemsRequest<P, S>) -> Self {
89 parts
90 }
91}
92
93#[derive(Debug, Clone, thiserror::Error)]
94#[error("`start_after` must be greater than or equal to the `prefix`")]
95pub struct StartAfterLessThanPrefixError;
96
97impl<P, S> TryFrom<ListItemsRequestParts<P, S>> for ListItemsRequest<P, S>
98where
99 P: Deref<Target = str> + Default,
100 S: Deref<Target = str> + Default,
101{
102 type Error = StartAfterLessThanPrefixError;
103
104 fn try_from(parts: ListItemsRequestParts<P, S>) -> Result<Self, Self::Error> {
105 let start_after: &str = &parts.start_after;
106 let prefix: &str = &parts.prefix;
107
108 if !start_after.is_empty() && !prefix.is_empty() && start_after < prefix {
109 return Err(StartAfterLessThanPrefixError);
110 }
111
112 Ok(Self(parts))
113 }
114}
115
116#[derive(Debug, Clone, PartialEq, Eq)]
117pub enum CreateMode {
118 CreateOnly(Option<RequestToken>),
123 CreateOrReconfigure,
127}
128
129pub static REQUEST_TOKEN_HEADER: http::HeaderName =
130 http::HeaderName::from_static("s2-request-token");
131
132pub const MAX_REQUEST_TOKEN_LENGTH: usize = 36;
133
134#[derive(Debug, PartialEq, Eq, thiserror::Error)]
135#[error("request token was longer than {MAX_REQUEST_TOKEN_LENGTH} bytes in length: {0}")]
136pub struct RequestTokenTooLongError(pub usize);
137
138#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
139pub struct RequestToken(CompactString);
140
141#[cfg(feature = "utoipa")]
142impl utoipa::PartialSchema for RequestToken {
143 fn schema() -> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
144 utoipa::openapi::Object::builder()
145 .schema_type(utoipa::openapi::Type::String)
146 .max_length(Some(MAX_REQUEST_TOKEN_LENGTH))
147 .into()
148 }
149}
150
151#[cfg(feature = "utoipa")]
152impl utoipa::ToSchema for RequestToken {}
153
154impl serde::Serialize for RequestToken {
155 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
156 where
157 S: serde::Serializer,
158 {
159 serializer.serialize_str(&self.0)
160 }
161}
162
163impl<'de> serde::Deserialize<'de> for RequestToken {
164 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
165 where
166 D: serde::Deserializer<'de>,
167 {
168 let s = CompactString::deserialize(deserializer)?;
169 RequestToken::try_from(s).map_err(serde::de::Error::custom)
170 }
171}
172
173impl std::fmt::Display for RequestToken {
174 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
175 write!(f, "{}", self.0)
176 }
177}
178
179impl TryFrom<CompactString> for RequestToken {
180 type Error = RequestTokenTooLongError;
181
182 fn try_from(input: CompactString) -> Result<Self, Self::Error> {
183 if input.len() > MAX_REQUEST_TOKEN_LENGTH {
184 return Err(RequestTokenTooLongError(input.len()));
185 }
186 Ok(RequestToken(input))
187 }
188}
189
190impl FromStr for RequestToken {
191 type Err = RequestTokenTooLongError;
192
193 fn from_str(s: &str) -> Result<Self, Self::Err> {
194 s.to_compact_string().try_into()
195 }
196}
197
198impl From<RequestToken> for CompactString {
199 fn from(token: RequestToken) -> Self {
200 token.0
201 }
202}
203
204impl AsRef<str> for RequestToken {
205 fn as_ref(&self) -> &str {
206 &self.0
207 }
208}
209
210impl Deref for RequestToken {
211 type Target = str;
212
213 fn deref(&self) -> &Self::Target {
214 &self.0
215 }
216}
217
218impl crate::http::ParseableHeader for RequestToken {
219 fn name() -> &'static http::HeaderName {
220 &REQUEST_TOKEN_HEADER
221 }
222}