use async_trait::async_trait;
use http::header::ACCEPT;
use url::Url;
use crate::{
algorithms::ptd::Type,
mf2::{self, types::Document},
};
pub trait ItemPostTypeResolutionExt {
fn post_type(&self) -> Type;
}
impl ItemPostTypeResolutionExt for crate::mf2::types::Item {
fn post_type(&self) -> Type {
crate::algorithms::ptd::resolve_from_object(self.clone()).unwrap_or(Type::Note)
}
}
#[test]
fn item_post_type_resultion_ext() {
let item: crate::mf2::types::Item = serde_json::from_value(serde_json::json!({
"type": ["h-entry"],
"properties": {
"photo": [
"http://example.com/image.jpg"
]
}
}))
.unwrap();
assert_eq!(item.post_type(), Type::Photo);
}
#[async_trait]
pub trait FetchMF2FromExt {
async fn fetch_mf2_from<C: crate::http::Client>(
&self,
client: C,
) -> Result<Document, crate::Error>;
}
#[async_trait]
impl FetchMF2FromExt for Url {
async fn fetch_mf2_from<C: crate::http::Client>(
&self,
client: C,
) -> Result<Document, crate::Error> {
let req = http::Request::get(self.as_str())
.header(
ACCEPT,
"text/html; charset=utf-8, text/mf2+html; charset=utf-8, */*; q=0.6",
)
.body(crate::http::Body::default())
.map_err(crate::Error::Http)?;
let response = client
.send_request(req)
.await?
.map(|body| body.as_bytes().to_vec());
Ok(mf2::http::to_mf2_document(response, self.as_str())
.map_err(crate::Error::from)?)
}
}
pub mod as_string_or_list {
use std::{fmt, str::FromStr};
use serde::{
de::{self, Visitor},
ser::SerializeSeq,
Deserialize, Deserializer, Serialize,
};
pub fn deserialize<'de, Item, D, E>(deserializer: D) -> Result<Vec<Item>, D::Error>
where
Item: Deserialize<'de> + FromStr<Err = E> + fmt::Debug,
E: std::error::Error,
D: Deserializer<'de>,
{
struct CocereIntoList;
impl<'de> Visitor<'de> for CocereIntoList {
type Value = Vec<String>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(
"expecting no value, a string or a list of values, all to be made into a list",
)
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
if v.is_empty() {
Ok(Vec::default())
} else {
Ok(vec![v.to_string()])
}
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: de::SeqAccess<'de>,
{
let mut values = Vec::with_capacity(seq.size_hint().unwrap_or_default());
while let Some(value) = seq.next_element()? {
values.push(value);
}
Ok(values)
}
}
deserializer
.deserialize_any(CocereIntoList)
.and_then(|strings| {
strings.into_iter().try_fold(
Vec::default(),
|mut acc, string| match Item::from_str(&string) {
Ok(v) => {
acc.push(v);
Ok(acc)
}
Err(e) => Err(de::Error::custom(e)),
},
)
})
}
pub fn serialize<Item, S>(list: &[Item], serializer: S) -> Result<S::Ok, S::Error>
where
Item: Serialize,
S: serde::Serializer,
{
if let Some(value) = list.first().filter(|_| list.len() == 1) {
value.serialize(serializer)
} else {
let mut seq = serializer.serialize_seq(Some(list.len()))?;
for v in list {
seq.serialize_element(v)?;
}
seq.end()
}
}
}
mod test;