use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use http::{HeaderMap, Uri};
use r402::proto::v2;
use url::Url;
pub trait PriceTagSource: Clone + Send + Sync + 'static {
fn resolve(
&self,
headers: &HeaderMap,
uri: &Uri,
base_url: Option<&Url>,
) -> impl Future<Output = Vec<v2::PriceTag>> + Send;
}
#[derive(Clone, Debug)]
pub struct StaticPriceTags {
tags: Arc<[v2::PriceTag]>,
}
impl StaticPriceTags {
#[must_use]
pub fn new(tags: Vec<v2::PriceTag>) -> Self {
Self { tags: tags.into() }
}
#[must_use]
pub fn tags(&self) -> &[v2::PriceTag] {
&self.tags
}
#[must_use]
pub fn with_price_tag(mut self, tag: v2::PriceTag) -> Self {
let mut tags = self.tags.to_vec();
tags.push(tag);
self.tags = tags.into();
self
}
}
impl PriceTagSource for StaticPriceTags {
async fn resolve(
&self,
_headers: &HeaderMap,
_uri: &Uri,
_base_url: Option<&Url>,
) -> Vec<v2::PriceTag> {
self.tags.to_vec()
}
}
type BoxedDynamicPriceCallback = dyn for<'a> Fn(
&'a HeaderMap,
&'a Uri,
Option<&'a Url>,
) -> Pin<Box<dyn Future<Output = Vec<v2::PriceTag>> + Send + 'a>>
+ Send
+ Sync;
pub struct DynamicPriceTags {
callback: Arc<BoxedDynamicPriceCallback>,
}
impl Clone for DynamicPriceTags {
fn clone(&self) -> Self {
Self {
callback: Arc::clone(&self.callback),
}
}
}
impl std::fmt::Debug for DynamicPriceTags {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("DynamicPriceTags")
.field("callback", &"<callback>")
.finish()
}
}
impl DynamicPriceTags {
pub fn new<F, Fut>(callback: F) -> Self
where
F: Fn(&HeaderMap, &Uri, Option<&Url>) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Vec<v2::PriceTag>> + Send + 'static,
{
Self {
callback: Arc::new(move |headers, uri, base_url| {
Box::pin(callback(headers, uri, base_url))
}),
}
}
}
impl PriceTagSource for DynamicPriceTags {
async fn resolve(
&self,
headers: &HeaderMap,
uri: &Uri,
base_url: Option<&Url>,
) -> Vec<v2::PriceTag> {
(self.callback)(headers, uri, base_url).await
}
}