1use std::{
2 ops::{AddAssign, MulAssign},
3 collections::{BTreeMap, BTreeSet},
4 path::Path,
5 fmt,
6 error::Error,
7};
8use crate::{NodeID, ContextHandle};
9
10pub trait ContentFormat: fmt::Debug {
11 fn expected_extensions(&self) -> &[&str];
14
15 fn path_is_acceptable(&self, path: &Path) -> bool {
16 if let Some(ext) = path.extension() {
17 if !ext.is_empty() {
18 if let Some(ext) = ext.to_str() {
19 for expected in self.expected_extensions() {
20 if ext.eq_ignore_ascii_case(expected) {
21 return true
22 }
23 }
24 }
25
26 return false
29 }
30 }
31
32 true
34 }
35
36 fn script_is_acceptable(&self, script: &str) -> bool;
37
38 fn script_to_content(
39 &self,
40 cxt: &ContextHandle,
41 script: &str,
42 ) -> Result<Box<dyn Content>, Box<dyn Error>>;
43}
44
45#[derive(Clone, Default, Debug)]
46pub struct InteractiveFormat;
47
48impl InteractiveFormat {
49 pub fn new() -> Self {
50 Default::default()
51 }
52}
53
54impl ContentFormat for InteractiveFormat {
55 fn expected_extensions(&self) -> &[&str] {
56 &[]
57 }
58
59 fn script_is_acceptable(&self, _script: &str) -> bool {
60 false
61 }
62
63 fn script_to_content(
64 &self,
65 _cxt: &ContextHandle,
66 _script: &str,
67 ) -> Result<Box<dyn Content>, Box<dyn Error>> {
68 panic!("Attempt to bypass a script acceptance test.")
69 }
70}
71
72pub trait Content: fmt::Debug {
86 fn get_script(&self) -> Option<&str>;
89 fn get_name(&self) -> Option<&str>;
90 fn get_carrier_ids(&mut self) -> Vec<NodeID>;
91 fn get_causes_by_id(&self, id: NodeID) -> Option<&Vec<Vec<NodeID>>>;
92 fn get_effects_by_id(&self, id: NodeID) -> Option<&Vec<Vec<NodeID>>>;
93}
94
95impl Content for String {
96 fn get_script(&self) -> Option<&str> {
97 Some(self)
98 }
99
100 fn get_name(&self) -> Option<&str> {
101 panic!("Attempt to access a phantom content.")
102 }
103
104 fn get_carrier_ids(&mut self) -> Vec<NodeID> {
105 panic!("Attempt to access a phantom content.")
106 }
107
108 fn get_causes_by_id(&self, _id: NodeID) -> Option<&Vec<Vec<NodeID>>> {
109 panic!("Attempt to access a phantom content.")
110 }
111
112 fn get_effects_by_id(&self, _id: NodeID) -> Option<&Vec<Vec<NodeID>>> {
113 panic!("Attempt to access a phantom content.")
114 }
115}
116
117impl<'a, C: Content + 'a> From<C> for Box<dyn Content + 'a> {
118 fn from(content: C) -> Box<dyn Content + 'a> {
119 Box::new(content)
120 }
121}
122
123#[derive(PartialOrd, Ord, PartialEq, Eq, Clone, Default, Debug)]
124pub(crate) struct MonoForContent {
125 content: Vec<NodeID>,
126}
127
128impl MonoForContent {
129 pub(crate) fn new() -> Self {
130 Default::default()
131 }
132
133 pub(crate) fn add_node(&mut self, id: NodeID) {
134 if let Err(pos) = self.content.binary_search(&id) {
135 self.content.insert(pos, id);
136 }
137 }
138
139 pub(crate) fn into_content(self) -> Vec<NodeID> {
140 self.content
141 }
142}
143
144#[derive(PartialOrd, Ord, PartialEq, Eq, Clone, Default, Debug)]
145pub(crate) struct PolyForContent {
146 content: Vec<Vec<NodeID>>,
147}
148
149impl PolyForContent {
150 pub(crate) fn new() -> Self {
151 Default::default()
152 }
153
154 pub(crate) fn add_mono(&mut self, mono: Vec<NodeID>) {
155 if let Err(pos) = self.content.binary_search(&mono) {
156 self.content.insert(pos, mono);
157 }
158 }
159
160 pub(crate) fn multiply_by_mono(&mut self, mono: Vec<NodeID>) {
161 if self.content.is_empty() {
162 self.add_mono(mono);
163 } else {
164 let mut old_poly = Vec::new();
165 old_poly.append(&mut self.content);
166
167 for mut old_mono in old_poly {
168 for node_id in mono.iter() {
169 if let Err(pos) = old_mono.binary_search(node_id) {
170 old_mono.insert(pos, *node_id);
171 }
172 }
173 self.add_mono(old_mono);
174 }
175 }
176 }
177
178 pub(crate) fn as_content(&self) -> &Vec<Vec<NodeID>> {
179 &self.content
180 }
181}
182
183impl AddAssign for PolyForContent {
184 fn add_assign(&mut self, other: Self) {
185 for mono in other.content {
186 self.add_mono(mono);
187 }
188 }
189}
190
191#[derive(Clone, Default, Debug)]
192struct MapForContent {
193 content: BTreeMap<NodeID, PolyForContent>,
194}
195
196impl MapForContent {
197 fn add_poly(&mut self, id: NodeID, poly: &[Vec<NodeID>]) {
201 self.content
202 .entry(id)
203 .and_modify(|old_poly| {
204 for mono in poly {
205 old_poly.add_mono(mono.to_vec());
206 }
207 })
208 .or_insert_with(|| PolyForContent { content: poly.to_vec() });
209 }
210
211 fn multiply_by_poly(&mut self, id: NodeID, poly: &[Vec<NodeID>]) {
215 self.content
216 .entry(id)
217 .and_modify(|old_poly| {
218 let mut new_poly = PolyForContent::new();
219 for mono in poly {
220 let mut aux_poly = old_poly.clone();
221 aux_poly.multiply_by_mono(mono.to_vec());
222 new_poly += aux_poly;
223 }
224 *old_poly = new_poly;
225 })
226 .or_insert_with(|| PolyForContent { content: poly.to_vec() });
227 }
228}
229
230#[derive(Clone, Default, Debug)]
231struct CarrierForContent {
232 content: Option<BTreeSet<NodeID>>,
233}
234
235impl CarrierForContent {
236 fn touch(&mut self, id: NodeID) {
237 if let Some(ref content) = self.content {
238 if content.contains(&id) {
239 return
240 }
241 }
242 self.content = None;
243 }
244
245 fn maybe_update(&mut self, causes: &MapForContent, effects: &MapForContent) {
246 if self.content.is_none() {
247 self.content =
248 Some(effects.content.keys().chain(causes.content.keys()).copied().collect());
249 }
250 }
251
252 fn as_owned_content(&self) -> Vec<NodeID> {
253 self.content.as_ref().unwrap().iter().copied().collect()
254 }
255}
256
257#[derive(Clone, Debug)]
258pub struct PartialContent {
259 context: ContextHandle,
260 carrier: CarrierForContent,
261 causes: MapForContent,
262 effects: MapForContent,
263}
264
265impl PartialContent {
266 pub fn new(ctx: &ContextHandle) -> Self {
267 PartialContent {
268 context: ctx.clone(),
269 carrier: Default::default(),
270 causes: Default::default(),
271 effects: Default::default(),
272 }
273 }
274
275 pub fn get_context(&self) -> &ContextHandle {
276 &self.context
277 }
278
279 pub fn add_to_causes(&mut self, id: NodeID, poly: &[Vec<NodeID>]) {
280 if !poly.is_empty() {
281 self.causes.add_poly(id, poly);
282 self.carrier.touch(id);
283 }
284 }
285
286 pub fn add_to_effects(&mut self, id: NodeID, poly: &[Vec<NodeID>]) {
287 if !poly.is_empty() {
288 self.effects.add_poly(id, poly);
289 self.carrier.touch(id);
290 }
291 }
292
293 pub fn multiply_causes(&mut self, id: NodeID, poly: &[Vec<NodeID>]) {
294 if !poly.is_empty() {
295 self.causes.multiply_by_poly(id, poly);
296 self.carrier.touch(id);
297 }
298 }
299
300 pub fn multiply_effects(&mut self, id: NodeID, poly: &[Vec<NodeID>]) {
301 if !poly.is_empty() {
302 self.effects.multiply_by_poly(id, poly);
303 self.carrier.touch(id);
304 }
305 }
306}
307
308impl AddAssign for PartialContent {
309 fn add_assign(&mut self, other: Self) {
310 for (id, poly) in other.causes.content {
311 self.add_to_causes(id, &poly.content);
312 }
313
314 for (id, poly) in other.effects.content {
315 self.add_to_effects(id, &poly.content);
316 }
317 }
318}
319
320impl MulAssign for PartialContent {
321 fn mul_assign(&mut self, other: Self) {
322 for (id, poly) in other.causes.content {
323 self.multiply_causes(id, &poly.content);
324 }
325
326 for (id, poly) in other.effects.content {
327 self.multiply_effects(id, &poly.content);
328 }
329 }
330}
331
332impl Content for PartialContent {
333 fn get_script(&self) -> Option<&str> {
334 None
335 }
336
337 fn get_name(&self) -> Option<&str> {
338 None
339 }
340
341 fn get_carrier_ids(&mut self) -> Vec<NodeID> {
342 self.carrier.maybe_update(&self.causes, &self.effects);
343 self.carrier.as_owned_content()
344 }
345
346 fn get_causes_by_id(&self, id: NodeID) -> Option<&Vec<Vec<NodeID>>> {
347 self.causes.content.get(&id).map(|poly| poly.as_content())
348 }
349
350 fn get_effects_by_id(&self, id: NodeID) -> Option<&Vec<Vec<NodeID>>> {
351 self.effects.content.get(&id).map(|poly| poly.as_content())
352 }
353}
354
355pub trait CompilableMut {
356 fn compile_mut(&mut self, ctx: &ContextHandle) -> Result<bool, Box<dyn Error>>;
357}
358
359pub trait Compilable {
360 fn compile(&self, ctx: &ContextHandle) -> Result<bool, Box<dyn Error>>;
361}
362
363pub trait CompilableAsContent {
364 fn get_compiled_content(&self, ctx: &ContextHandle) -> Result<PartialContent, Box<dyn Error>>;
378
379 fn check_dependencies(&self, _ctx: &ContextHandle) -> Option<String> {
388 None
389 }
390}
391
392pub trait CompilableAsDependency: CompilableAsContent {
393 fn compile_as_dependency(&self, ctx: &ContextHandle) -> Result<Option<String>, Box<dyn Error>>;
401}