1use async_trait::async_trait;
2use http::header::ACCEPT;
3use url::Url;
4
5use crate::{
6 algorithms::ptd::Type,
7 mf2::{self, types::Document},
8};
9
10pub trait ItemPostTypeResolutionExt {
12 fn post_type(&self) -> Type;
14}
15
16impl ItemPostTypeResolutionExt for crate::mf2::types::Item {
17 fn post_type(&self) -> Type {
18 crate::algorithms::ptd::resolve_from_object(self.clone()).unwrap_or(Type::Note)
19 }
20}
21
22#[test]
23fn item_post_type_resultion_ext() {
24 let item: crate::mf2::types::Item = serde_json::from_value(serde_json::json!({
25 "type": ["h-entry"],
26 "properties": {
27 "photo": [
28 "http://example.com/image.jpg"
29 ]
30 }
31 }))
32 .unwrap();
33
34 assert_eq!(item.post_type(), Type::Photo);
35}
36
37#[async_trait]
39pub trait FetchMF2FromExt {
40 async fn fetch_mf2_from<C: crate::http::Client>(
42 &self,
43 client: C,
44 ) -> Result<Document, crate::Error>;
45}
46
47#[async_trait]
48impl FetchMF2FromExt for Url {
49 async fn fetch_mf2_from<C: crate::http::Client>(
50 &self,
51 client: C,
52 ) -> Result<Document, crate::Error> {
53 let req = http::Request::get(self.as_str())
54 .header(
55 ACCEPT,
56 "text/html; charset=utf-8, text/mf2+html; charset=utf-8, */*; q=0.6",
57 )
58 .body(crate::http::Body::default())
59 .map_err(crate::Error::Http)?;
60
61 let response = client
62 .send_request(req)
63 .await?
64 .map(|body| body.as_bytes().to_vec());
65 Ok(mf2::parser::http::to_mf2_document(response, self.as_str())
66 .map_err(mf2::Error::Parser)?)
67 }
68}
69
70pub mod as_string_or_list {
72
73 use std::{fmt, str::FromStr};
74
75 use serde::{
76 de::{self, Visitor},
77 ser::SerializeSeq,
78 Deserialize, Deserializer, Serialize,
79 };
80
81 pub fn deserialize<'de, Item, D, E>(deserializer: D) -> Result<Vec<Item>, D::Error>
82 where
83 Item: Deserialize<'de> + FromStr<Err = E> + fmt::Debug,
84 E: std::error::Error,
85 D: Deserializer<'de>,
86 {
87 struct CocereIntoList;
88
89 impl<'de> Visitor<'de> for CocereIntoList {
90 type Value = Vec<String>;
91
92 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
93 formatter.write_str(
94 "expecting no value, a string or a list of values, all to be made into a list",
95 )
96 }
97
98 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
99 where
100 E: de::Error,
101 {
102 if v.is_empty() {
103 Ok(Vec::default())
104 } else {
105 Ok(vec![v.to_string()])
106 }
107 }
108
109 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
110 where
111 A: de::SeqAccess<'de>,
112 {
113 let mut values = Vec::with_capacity(seq.size_hint().unwrap_or_default());
114
115 while let Some(value) = seq.next_element()? {
116 values.push(value);
117 }
118
119 Ok(values)
120 }
121 }
122
123 deserializer
124 .deserialize_any(CocereIntoList)
125 .and_then(|strings| {
126 strings.into_iter().try_fold(
127 Vec::default(),
128 |mut acc, string| match Item::from_str(&string) {
129 Ok(v) => {
130 acc.push(v);
131 Ok(acc)
132 }
133 Err(e) => Err(de::Error::custom(e)),
134 },
135 )
136 })
137 }
138
139 pub fn serialize<Item, S>(list: &[Item], serializer: S) -> Result<S::Ok, S::Error>
140 where
141 Item: Serialize,
142 S: serde::Serializer,
143 {
144 if let Some(value) = list.first().filter(|_| list.len() == 1) {
145 value.serialize(serializer)
146 } else {
147 let mut seq = serializer.serialize_seq(Some(list.len()))?;
148
149 for v in list {
150 seq.serialize_element(v)?;
151 }
152
153 seq.end()
154 }
155 }
156}
157
158mod test;