grid_tariffs/
links.rs

1use serde::Serialize;
2
3#[derive(Debug, Clone, Serialize)]
4#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
5pub struct Links {
6    /// Website page containing info about the fees that the company charges
7    fee_info: Link,
8    /// Website page containing info about feed-in revenue
9    feed_in_revenue_info: Option<Link>,
10    /// Link to public Eltariff-API endpoint (https://github.com/RI-SE/Eltariff-API)
11    eltariff_api: Option<&'static str>,
12}
13
14impl Links {
15    pub const fn fee_info(&self) -> &Link {
16        &self.fee_info
17    }
18
19    pub(crate) const fn new(fee_info: Link) -> Self {
20        Self::builder().fee_info(fee_info).build()
21    }
22
23    pub(crate) const fn builder() -> LinksBuilder {
24        LinksBuilder::new()
25    }
26}
27
28pub(crate) struct LinksBuilder {
29    fee_info: Option<Link>,
30    feed_in_revenue_info: Option<Link>,
31    eltariff_api: Option<&'static str>,
32}
33
34impl LinksBuilder {
35    pub(crate) const fn new() -> Self {
36        Self {
37            fee_info: None,
38            feed_in_revenue_info: None,
39            eltariff_api: None,
40        }
41    }
42
43    pub(crate) const fn fee_info(mut self, link: Link) -> Self {
44        self.fee_info = Some(link);
45        self
46    }
47
48    pub(crate) const fn new_fee_info(self, link: &'static str, css_selector: &'static str) -> Self {
49        self.fee_info(
50            Link::builder(link)
51                .plain_content_locator(css_selector)
52                .build(),
53        )
54    }
55
56    pub(crate) const fn feed_in_revenue_info(mut self, link: Link) -> Self {
57        self.feed_in_revenue_info = Some(link);
58        self
59    }
60
61    pub(crate) const fn new_feed_in_revenue_info(
62        self,
63        link: &'static str,
64        css_selector: &'static str,
65    ) -> Self {
66        self.feed_in_revenue_info(
67            Link::builder(link)
68                .plain_content_locator(css_selector)
69                .build(),
70        )
71    }
72
73    pub(crate) const fn eltariff_api(mut self, link: &'static str) -> Self {
74        self.eltariff_api = Some(link);
75        self
76    }
77
78    pub(crate) const fn build(self) -> Links {
79        Links {
80            fee_info: self.fee_info.expect("`fee_info` not specified"),
81            feed_in_revenue_info: self.feed_in_revenue_info,
82            eltariff_api: self.eltariff_api,
83        }
84    }
85}
86
87#[derive(Debug, Clone, Copy, Serialize)]
88#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
89pub enum TargetContainer {
90    Current,
91    Parent,
92    Ancestor(usize),
93}
94
95/// What content to checksum witihin the elements found
96#[derive(Debug, Clone, Serialize)]
97#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
98pub enum ContentTarget {
99    TextWithLinks,
100    /// Attribute which contains the relevant content
101    Attribute(&'static str),
102}
103
104#[derive(Debug, Clone, Serialize)]
105#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
106pub struct ContentLocator {
107    method: LocatorMethod,
108    content: ContentTarget,
109    uses_default_locator: bool,
110}
111
112impl ContentLocator {
113    pub(crate) const fn new(method: LocatorMethod, content: ContentTarget) -> Self {
114        Self {
115            method,
116            content,
117            uses_default_locator: false,
118        }
119    }
120
121    pub const fn method(&self) -> &LocatorMethod {
122        &self.method
123    }
124
125    pub const fn uses_default_locator(&self) -> bool {
126        self.uses_default_locator
127    }
128
129    pub const fn content_target(&self) -> &ContentTarget {
130        &self.content
131    }
132
133    pub(crate) const fn new_starts_with(
134        needle: &'static str,
135        target_container: TargetContainer,
136        content: ContentTarget,
137    ) -> ContentLocator {
138        Self::new(
139            LocatorMethod::TextStartsWith {
140                needle,
141                target_container,
142            },
143            content,
144        )
145    }
146}
147
148#[derive(Debug, Clone, Serialize)]
149#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
150pub enum LocatorMethod {
151    CssSelector(&'static str),
152    TextStartsWith {
153        needle: &'static str,
154        target_container: TargetContainer,
155    },
156}
157
158impl LocatorMethod {
159    pub fn target_container(&self) -> TargetContainer {
160        match self {
161            Self::CssSelector(_) => TargetContainer::Current,
162            Self::TextStartsWith {
163                target_container, ..
164            } => *target_container,
165        }
166    }
167}
168
169#[derive(Debug, Clone, Serialize)]
170#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
171pub struct Link {
172    link: &'static str,
173    content_locator: ContentLocator,
174}
175
176impl Link {
177    pub const fn link(&self) -> &str {
178        self.link
179    }
180
181    pub const fn content_locator(&self) -> &ContentLocator {
182        &self.content_locator
183    }
184
185    pub(crate) const fn builder(link: &'static str) -> LinkBuilder {
186        LinkBuilder::new(link)
187    }
188}
189
190pub struct LinkBuilder {
191    link: &'static str,
192    content_locator: Option<ContentLocator>,
193}
194
195impl LinkBuilder {
196    pub(crate) const fn new(link: &'static str) -> Self {
197        Self {
198            link,
199            content_locator: None,
200        }
201    }
202
203    pub(crate) const fn content_locator(mut self, locator: ContentLocator) -> Self {
204        self.content_locator = Some(locator);
205        self
206    }
207
208    pub(crate) const fn plain_content_locator(mut self, css_selector: &'static str) -> Self {
209        self.content_locator = Some(ContentLocator::new(
210            LocatorMethod::CssSelector(css_selector),
211            ContentTarget::TextWithLinks,
212        ));
213        self
214    }
215
216    pub(crate) const fn content_locator_default(mut self) -> Self {
217        self.content_locator = Some(ContentLocator {
218            method: LocatorMethod::CssSelector("main"),
219            content: ContentTarget::TextWithLinks,
220            uses_default_locator: true,
221        });
222        self
223    }
224
225    pub(crate) const fn build(self) -> Link {
226        Link {
227            link: self.link,
228            content_locator: self.content_locator.expect("`locator` missing"),
229        }
230    }
231}