actpub_activitystreams/
value.rs1use serde::{Deserialize, Deserializer, Serialize, Serializer};
10use url::Url;
11
12#[derive(Debug, Clone, PartialEq, Eq, Hash)]
31pub struct OneOrMany<T>(Vec<T>);
32
33impl<T> OneOrMany<T> {
34 #[must_use]
36 pub const fn new() -> Self {
37 Self(Vec::new())
38 }
39
40 pub fn one(value: T) -> Self {
42 Self(vec![value])
43 }
44
45 #[must_use]
47 pub const fn many(values: Vec<T>) -> Self {
48 Self(values)
49 }
50
51 #[must_use]
53 pub fn as_slice(&self) -> &[T] {
54 &self.0
55 }
56
57 pub fn as_mut_slice(&mut self) -> &mut [T] {
59 &mut self.0
60 }
61
62 #[must_use]
64 pub fn into_vec(self) -> Vec<T> {
65 self.0
66 }
67
68 pub fn push(&mut self, value: T) {
70 self.0.push(value);
71 }
72
73 #[must_use]
75 pub const fn is_empty(&self) -> bool {
76 self.0.is_empty()
77 }
78
79 #[must_use]
81 pub const fn len(&self) -> usize {
82 self.0.len()
83 }
84
85 pub fn iter(&self) -> core::slice::Iter<'_, T> {
87 self.0.iter()
88 }
89
90 pub fn iter_mut(&mut self) -> core::slice::IterMut<'_, T> {
92 self.0.iter_mut()
93 }
94
95 #[must_use]
97 pub fn first(&self) -> Option<&T> {
98 self.0.first()
99 }
100
101 #[must_use]
103 pub fn last(&self) -> Option<&T> {
104 self.0.last()
105 }
106}
107
108impl<T> Default for OneOrMany<T> {
109 fn default() -> Self {
110 Self::new()
111 }
112}
113
114impl<T> IntoIterator for OneOrMany<T> {
115 type Item = T;
116 type IntoIter = std::vec::IntoIter<T>;
117
118 fn into_iter(self) -> Self::IntoIter {
119 self.0.into_iter()
120 }
121}
122
123impl<'a, T> IntoIterator for &'a OneOrMany<T> {
124 type Item = &'a T;
125 type IntoIter = core::slice::Iter<'a, T>;
126
127 fn into_iter(self) -> Self::IntoIter {
128 self.0.iter()
129 }
130}
131
132impl<'a, T> IntoIterator for &'a mut OneOrMany<T> {
133 type Item = &'a mut T;
134 type IntoIter = core::slice::IterMut<'a, T>;
135
136 fn into_iter(self) -> Self::IntoIter {
137 self.0.iter_mut()
138 }
139}
140
141impl<T> From<T> for OneOrMany<T> {
142 fn from(value: T) -> Self {
143 Self::one(value)
144 }
145}
146
147impl<T> From<Vec<T>> for OneOrMany<T> {
148 fn from(values: Vec<T>) -> Self {
149 Self::many(values)
150 }
151}
152
153impl<T> FromIterator<T> for OneOrMany<T> {
154 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
155 Self(iter.into_iter().collect())
156 }
157}
158
159impl<T: Serialize> Serialize for OneOrMany<T> {
160 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
161 match self.0.as_slice() {
162 [only] => only.serialize(serializer),
163 many => many.serialize(serializer),
164 }
165 }
166}
167
168impl<'de, T: Deserialize<'de>> Deserialize<'de> for OneOrMany<T> {
169 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
170 #[derive(Deserialize)]
171 #[serde(untagged)]
172 enum Either<T> {
173 Many(Vec<T>),
174 One(T),
175 }
176
177 match Option::<Either<T>>::deserialize(deserializer)? {
181 None => Ok(Self::new()),
182 Some(Either::One(value)) => Ok(Self::one(value)),
183 Some(Either::Many(values)) => Ok(Self::many(values)),
184 }
185 }
186}
187
188#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
197#[serde(untagged)]
198pub enum UrlOr<T> {
199 Url(Url),
201 Object(T),
203}
204
205impl<T> UrlOr<T> {
206 pub fn url(&self) -> Option<&Url>
209 where
210 T: HasId,
211 {
212 match self {
213 Self::Url(u) => Some(u),
214 Self::Object(o) => o.id(),
215 }
216 }
217
218 #[must_use]
220 pub const fn as_object(&self) -> Option<&T> {
221 match self {
222 Self::Object(o) => Some(o),
223 Self::Url(_) => None,
224 }
225 }
226}
227
228pub trait HasId {
230 fn id(&self) -> Option<&Url>;
232}
233
234#[derive(Copy, Clone, Debug, Eq, PartialEq)]
240pub struct Public;
241
242impl Public {
243 pub const URI: &'static str = "https://www.w3.org/ns/activitystreams#Public";
245 pub const CURIE: &'static str = "as:Public";
248 pub const BARE: &'static str = "Public";
251
252 #[must_use]
255 pub fn is_public(value: &str) -> bool {
256 matches!(value, Self::URI | Self::CURIE | Self::BARE)
257 }
258}
259
260#[cfg(test)]
261mod tests {
262 use pretty_assertions::assert_eq;
263 use serde_json::json;
264
265 use super::*;
266
267 #[test]
268 fn one_or_many_single_value_serialises_as_bare_value() {
269 let value = OneOrMany::one("hello".to_owned());
270 let json = serde_json::to_value(&value).expect("serialise");
271 assert_eq!(json, json!("hello"));
272
273 let back: OneOrMany<String> = serde_json::from_value(json).expect("deserialise");
274 assert_eq!(back, value);
275 }
276
277 #[test]
278 fn one_or_many_multi_value_serialises_as_array() {
279 let value = OneOrMany::many(vec![1_i32, 2, 3]);
280 let json = serde_json::to_value(&value).expect("serialise");
281 assert_eq!(json, json!([1, 2, 3]));
282
283 let back: OneOrMany<i32> = serde_json::from_value(json).expect("deserialise");
284 assert_eq!(back, value);
285 }
286
287 #[test]
288 fn one_or_many_empty_serialises_as_empty_array() {
289 let value: OneOrMany<String> = OneOrMany::new();
290 let json = serde_json::to_value(&value).expect("serialise");
291 assert_eq!(json, json!([]));
292 }
293
294 #[test]
295 fn one_or_many_deserialises_null_as_empty() {
296 let back: OneOrMany<String> =
301 serde_json::from_value(json!(null)).expect("null must deserialise");
302 assert!(back.is_empty(), "null must yield an empty collection");
303 }
304
305 #[test]
306 fn one_or_many_collects_from_iterator() {
307 let value: OneOrMany<i32> = [1, 2, 3].into_iter().collect();
308 assert_eq!(value.as_slice(), &[1, 2, 3]);
309 }
310
311 #[test]
312 fn url_or_deserializes_bare_url() {
313 #[derive(Deserialize, Serialize, Debug, PartialEq)]
314 struct Dummy {
315 id: String,
316 }
317 let value: UrlOr<Dummy> = serde_json::from_value(json!("https://example/1")).unwrap();
318 assert!(matches!(value, UrlOr::Url(_)));
319 }
320
321 #[test]
322 fn url_or_deserializes_object() {
323 #[derive(Deserialize, Serialize, Debug, PartialEq)]
324 struct Dummy {
325 id: String,
326 }
327 let value: UrlOr<Dummy> = serde_json::from_value(json!({ "id": "abc" })).unwrap();
328 assert!(matches!(value, UrlOr::Object(Dummy { .. })));
329 }
330
331 #[test]
332 fn public_is_recognised_in_all_spellings() {
333 assert!(Public::is_public(Public::URI));
334 assert!(Public::is_public(Public::CURIE));
335 assert!(Public::is_public(Public::BARE));
336 assert!(!Public::is_public("https://example/actor"));
337 }
338}