use crate::{config::Data, error::Error, fetch::fetch_object_http, traits::Collection}; use serde::{Deserialize, Serialize}; use std::{ fmt::{Debug, Display, Formatter}, marker::PhantomData, }; use url::Url; /// Typed wrapper for Activitypub Collection ID which helps with dereferencing. #[derive(Serialize, Deserialize)] #[serde(transparent)] pub struct CollectionId(Box, PhantomData) where Kind: Collection, for<'de2> ::Kind: Deserialize<'de2>; impl CollectionId where Kind: Collection, for<'de2> ::Kind: Deserialize<'de2>, { /// Construct a new CollectionId instance pub fn parse(url: T) -> Result where T: TryInto, url::ParseError: From<>::Error>, { Ok(Self(Box::new(url.try_into()?), PhantomData::)) } /// Fetches collection over HTTP /// /// Unlike [ObjectId::dereference](crate::fetch::object_id::ObjectId::dereference) this method doesn't do /// any caching. pub async fn dereference( &self, owner: &::Owner, data: &Data<::DataType>, ) -> Result::Error> where ::Error: From, { let res = fetch_object_http(&self.0, data).await?; let redirect_url = &res.url; Kind::verify(&res.object, redirect_url, data).await?; Kind::from_json(res.object, owner, data).await } } /// Need to implement clone manually, to avoid requiring Kind to be Clone impl Clone for CollectionId where Kind: Collection, for<'de2> ::Kind: serde::Deserialize<'de2>, { fn clone(&self) -> Self { CollectionId(self.0.clone(), self.1) } } impl Display for CollectionId where Kind: Collection, for<'de2> ::Kind: serde::Deserialize<'de2>, { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.0.as_str()) } } impl Debug for CollectionId where Kind: Collection, for<'de2> ::Kind: serde::Deserialize<'de2>, { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.0.as_str()) } } impl From> for Url where Kind: Collection, for<'de2> ::Kind: serde::Deserialize<'de2>, { fn from(id: CollectionId) -> Self { *id.0 } } impl From for CollectionId where Kind: Collection + Send + 'static, for<'de2> ::Kind: serde::Deserialize<'de2>, { fn from(url: Url) -> Self { CollectionId(Box::new(url), PhantomData::) } } impl PartialEq for CollectionId where Kind: Collection, for<'de2> ::Kind: serde::Deserialize<'de2>, { fn eq(&self, other: &Self) -> bool { self.0.eq(&other.0) && self.1 == other.1 } }