r402_http/server/
pricing.rs1use std::future::Future;
8use std::pin::Pin;
9use std::sync::Arc;
10
11use http::{HeaderMap, Uri};
12use r402::proto::v2;
13use url::Url;
14
15pub trait PriceTagSource: Clone + Send + Sync + 'static {
20 fn resolve(
24 &self,
25 headers: &HeaderMap,
26 uri: &Uri,
27 base_url: Option<&Url>,
28 ) -> impl Future<Output = Vec<v2::PriceTag>> + Send;
29}
30
31#[derive(Clone, Debug)]
36pub struct StaticPriceTags {
37 tags: Arc<Vec<v2::PriceTag>>,
38}
39
40impl StaticPriceTags {
41 #[must_use]
43 pub fn new(tags: Vec<v2::PriceTag>) -> Self {
44 Self {
45 tags: Arc::new(tags),
46 }
47 }
48
49 #[must_use]
51 pub fn tags(&self) -> &[v2::PriceTag] {
52 &self.tags
53 }
54
55 #[must_use]
57 pub fn with_price_tag(mut self, tag: v2::PriceTag) -> Self {
58 let mut tags = (*self.tags).clone();
59 tags.push(tag);
60 self.tags = Arc::new(tags);
61 self
62 }
63}
64
65impl PriceTagSource for StaticPriceTags {
66 async fn resolve(
67 &self,
68 _headers: &HeaderMap,
69 _uri: &Uri,
70 _base_url: Option<&Url>,
71 ) -> Vec<v2::PriceTag> {
72 (*self.tags).clone()
73 }
74}
75
76type BoxedDynamicPriceCallback = dyn for<'a> Fn(
78 &'a HeaderMap,
79 &'a Uri,
80 Option<&'a Url>,
81 ) -> Pin<Box<dyn Future<Output = Vec<v2::PriceTag>> + Send + 'a>>
82 + Send
83 + Sync;
84
85pub struct DynamicPriceTags {
90 callback: Arc<BoxedDynamicPriceCallback>,
91}
92
93impl Clone for DynamicPriceTags {
94 fn clone(&self) -> Self {
95 Self {
96 callback: Arc::clone(&self.callback),
97 }
98 }
99}
100
101impl std::fmt::Debug for DynamicPriceTags {
102 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
103 f.debug_struct("DynamicPriceTags")
104 .field("callback", &"<callback>")
105 .finish()
106 }
107}
108
109impl DynamicPriceTags {
110 pub fn new<F, Fut>(callback: F) -> Self
114 where
115 F: Fn(&HeaderMap, &Uri, Option<&Url>) -> Fut + Send + Sync + 'static,
116 Fut: Future<Output = Vec<v2::PriceTag>> + Send + 'static,
117 {
118 Self {
119 callback: Arc::new(move |headers, uri, base_url| {
120 Box::pin(callback(headers, uri, base_url))
121 }),
122 }
123 }
124}
125
126impl PriceTagSource for DynamicPriceTags {
127 async fn resolve(
128 &self,
129 headers: &HeaderMap,
130 uri: &Uri,
131 base_url: Option<&Url>,
132 ) -> Vec<v2::PriceTag> {
133 (self.callback)(headers, uri, base_url).await
134 }
135}