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