1use std::{
2 cmp, fmt,
3 collections::BTreeMap,
4 sync::{Arc, Mutex},
5};
6use crate::{
7 PartialContent, Port, Link, Harc, Fork, Join, Face, ID, NodeID, AtomID, PortID, LinkID, ForkID,
8 JoinID, Semantics, Capacity, Weight, AcesError,
9 name::NameSpace,
10 atom::{AtomSpace, Atom},
11 sat, solver, runner, vis,
12};
13
14pub type ContextHandle = Arc<Mutex<Context>>;
29
30#[derive(Debug)]
42pub struct Context {
43 magic_id: u64, name_id: ID, globals: NameSpace,
46 nodes: NameSpace,
47 atoms: AtomSpace,
48 content: BTreeMap<ID, PartialContent>,
49 capacities: BTreeMap<NodeID, Capacity>,
50 weights: BTreeMap<AtomID, Weight>,
51 solver_props: solver::Props,
52 runner_props: runner::Props,
53 vis_props: vis::Props,
54}
55
56impl Context {
57 pub fn new_toplevel<S: AsRef<str>>(name: S) -> ContextHandle {
63 let magic_id = rand::random();
64
65 let mut globals = NameSpace::default();
66 let name_id = globals.share_name(name);
67
68 let ctx = Self {
69 magic_id,
70 name_id,
71 globals,
72 nodes: Default::default(),
73 atoms: Default::default(),
74 content: Default::default(),
75 capacities: Default::default(),
76 weights: Default::default(),
77 solver_props: Default::default(),
78 runner_props: Default::default(),
79 vis_props: Default::default(),
80 };
81
82 Arc::new(Mutex::new(ctx))
83 }
84
85 pub fn reset(&mut self) {
92 self.content.clear();
94 self.capacities.clear();
95 self.weights.clear();
96 self.solver_props.clear();
97 self.runner_props.clear();
98 self.vis_props.clear();
99 }
100
101 pub fn new_derived<S: AsRef<str>>(name: S, parent: &ContextHandle) -> ContextHandle {
107 let ctx = {
108 let mut parent = parent.lock().unwrap();
109
110 let magic_id = parent.magic_id;
111
112 let name_id = parent.globals.share_name(name);
115
116 let globals = parent.globals.clone();
117 let nodes = parent.nodes.clone();
118 let atoms = parent.atoms.clone();
119 let content = parent.content.clone();
120 let capacities = parent.capacities.clone();
121 let weights = parent.weights.clone();
122 let solver_props = parent.solver_props.clone();
123 let runner_props = parent.runner_props.clone();
124 let vis_props = parent.vis_props.clone();
125
126 Self {
127 magic_id,
128 name_id,
129 globals,
130 nodes,
131 atoms,
132 content,
133 capacities,
134 weights,
135 solver_props,
136 runner_props,
137 vis_props,
138 }
139 };
140
141 Arc::new(Mutex::new(ctx))
142 }
143
144 pub fn is_toplevel(&self) -> bool {
145 self.name_id == unsafe { ID::new_unchecked(1) }
146 }
147
148 pub fn is_derived(&self) -> bool {
149 self.name_id > unsafe { ID::new_unchecked(1) }
150 }
151
152 pub fn get_name(&self) -> &str {
153 self.globals.get_name(self.name_id).expect("Invalid context.")
154 }
155
156 #[inline]
161 pub fn share_node_name<S: AsRef<str>>(&mut self, node_name: S) -> NodeID {
162 NodeID(self.nodes.share_name(node_name))
163 }
164
165 #[inline]
166 pub fn get_node_name(&self, node_id: NodeID) -> Option<&str> {
167 self.nodes.get_name(node_id.get())
168 }
169
170 #[inline]
171 pub fn get_node_id<S: AsRef<str>>(&self, node_name: S) -> Option<NodeID> {
172 self.nodes.get_id(node_name).map(NodeID)
173 }
174
175 #[inline]
178 pub(crate) fn get_atom(&self, atom_id: AtomID) -> Option<&Atom> {
179 self.atoms.get_atom(atom_id)
180 }
181
182 #[allow(dead_code)]
183 #[inline]
184 pub(crate) fn get_atom_id(&self, atom: &Atom) -> Option<AtomID> {
185 self.atoms.get_atom_id(atom)
186 }
187
188 #[inline]
189 pub fn is_port(&self, atom_id: AtomID) -> bool {
190 self.atoms.is_port(atom_id)
191 }
192
193 #[inline]
194 pub fn is_link(&self, atom_id: AtomID) -> bool {
195 self.atoms.is_link(atom_id)
196 }
197
198 #[inline]
199 pub fn is_harc(&self, atom_id: AtomID) -> bool {
200 self.atoms.is_harc(atom_id)
201 }
202
203 #[inline]
204 pub fn is_fork(&self, atom_id: AtomID) -> bool {
205 self.atoms.is_fork(atom_id)
206 }
207
208 #[inline]
209 pub fn is_join(&self, atom_id: AtomID) -> bool {
210 self.atoms.is_join(atom_id)
211 }
212
213 #[inline]
214 pub fn share_port(&mut self, port: &mut Port) -> PortID {
215 self.atoms.share_port(port)
216 }
217
218 #[inline]
219 pub fn share_link(&mut self, link: &mut Link) -> LinkID {
220 self.atoms.share_link(link)
221 }
222
223 #[inline]
224 pub fn share_fork(&mut self, fork: &mut Fork) -> ForkID {
225 self.atoms.share_fork(fork)
226 }
227
228 #[inline]
229 pub fn share_join(&mut self, join: &mut Join) -> JoinID {
230 self.atoms.share_join(join)
231 }
232
233 #[inline]
234 pub fn get_port(&self, port_id: PortID) -> Option<&Port> {
235 self.atoms.get_port(port_id)
236 }
237
238 #[inline]
239 pub fn get_link(&self, link_id: LinkID) -> Option<&Link> {
240 self.atoms.get_link(link_id)
241 }
242
243 #[inline]
244 pub fn get_harc(&self, atom_id: AtomID) -> Option<&Harc> {
245 self.atoms.get_harc(atom_id)
246 }
247
248 #[inline]
249 pub fn get_fork(&self, fork_id: ForkID) -> Option<&Fork> {
250 self.atoms.get_fork(fork_id)
251 }
252
253 #[inline]
254 pub fn get_join(&self, join_id: JoinID) -> Option<&Join> {
255 self.atoms.get_join(join_id)
256 }
257
258 #[inline]
259 pub fn get_antiport_id(&self, port_id: PortID) -> Option<PortID> {
260 self.atoms.get_antiport_id(port_id)
261 }
262
263 pub fn add_content<S: AsRef<str>>(
266 &mut self,
267 name: S,
268 content: PartialContent,
269 ) -> Option<PartialContent> {
270 let name_id = self.globals.share_name(name);
271
272 self.content.insert(name_id, content)
273 }
274
275 pub fn get_content<S: AsRef<str>>(&self, name: S) -> Option<&PartialContent> {
276 self.globals.get_id(name).and_then(|id| self.content.get(&id))
277 }
278
279 pub fn has_content<S: AsRef<str>>(&self, name: S) -> bool {
280 self.globals.get_id(name).map_or(false, |id| self.content.contains_key(&id))
281 }
282
283 pub fn set_capacity_by_name<S: AsRef<str>>(
286 &mut self,
287 node_name: S,
288 cap: Capacity,
289 ) -> Option<Capacity> {
290 let node_id = self.share_node_name(node_name.as_ref());
291
292 self.capacities.insert(node_id, cap)
293 }
294
295 #[inline]
296 pub fn get_capacity(&self, node_id: NodeID) -> Capacity {
297 self.capacities.get(&node_id).copied().unwrap_or_else(Capacity::one)
298 }
299
300 pub fn set_weight_by_name<S, I>(
303 &mut self,
304 face: Face,
305 host_name: S,
306 suit_names: I,
307 weight: Weight,
308 ) -> Option<Weight>
309 where
310 S: AsRef<str>,
311 I: IntoIterator,
312 I::Item: AsRef<str>,
313 {
314 let host_id = self.share_node_name(host_name.as_ref());
315 let suit_ids = suit_names.into_iter().map(|n| self.share_node_name(n.as_ref()));
316
317 let atom_id = match face {
318 Face::Tx => {
319 let mut fork = Harc::new_fork(host_id, suit_ids);
320 let fork_id = self.share_fork(&mut fork);
321
322 fork_id.get()
323 }
324 Face::Rx => {
325 let mut join = Harc::new_join(host_id, suit_ids);
326 let join_id = self.share_join(&mut join);
327
328 join_id.get()
329 }
330 };
331
332 self.weights.insert(atom_id, weight)
333 }
334
335 #[inline]
336 pub fn set_inhibitor_by_name<S, I>(
337 &mut self,
338 face: Face,
339 host_name: S,
340 suit_names: I,
341 ) -> Option<Weight>
342 where
343 S: AsRef<str>,
344 I: IntoIterator,
345 I::Item: AsRef<str>,
346 {
347 self.set_weight_by_name(face, host_name, suit_names, Weight::omega())
348 }
349
350 #[inline]
351 pub fn set_holder_by_name<S, I>(
352 &mut self,
353 face: Face,
354 host_name: S,
355 suit_names: I,
356 ) -> Option<Weight>
357 where
358 S: AsRef<str>,
359 I: IntoIterator,
360 I::Item: AsRef<str>,
361 {
362 self.set_weight_by_name(face, host_name, suit_names, Weight::zero())
363 }
364
365 #[inline]
366 pub fn get_weight(&self, atom_id: AtomID) -> Weight {
367 self.weights.get(&atom_id).copied().unwrap_or_else(Weight::one)
368 }
369
370 pub fn set_encoding(&mut self, encoding: sat::Encoding) {
373 self.solver_props.sat_encoding = Some(encoding);
374 }
375
376 pub fn get_encoding(&self) -> Option<sat::Encoding> {
377 self.solver_props.sat_encoding
378 }
379
380 pub fn set_search(&mut self, search: sat::Search) {
381 self.solver_props.sat_search = Some(search);
382 }
383
384 pub fn get_search(&self) -> Option<sat::Search> {
385 self.solver_props.sat_search
386 }
387
388 pub fn set_semantics(&mut self, semantics: Semantics) {
391 self.runner_props.semantics = Some(semantics);
392 }
393
394 pub fn get_semantics(&self) -> Option<Semantics> {
395 self.runner_props.semantics
396 }
397
398 pub fn set_max_steps(&mut self, max_steps: usize) {
399 self.runner_props.max_steps = Some(max_steps);
400 }
401
402 pub fn get_max_steps(&self) -> Option<usize> {
403 self.runner_props.max_steps
404 }
405
406 pub fn set_title<S: AsRef<str>>(&mut self, title: S) {
409 self.vis_props.title = Some(title.as_ref().to_owned());
410 }
411
412 pub fn get_title(&self) -> Option<&str> {
413 self.vis_props.title.as_deref()
414 }
415
416 pub fn set_label<S: AsRef<str>>(&mut self, node_id: NodeID, label: S) {
417 self.vis_props.labels.insert(node_id, label.as_ref().to_owned());
418 }
419
420 pub fn get_label(&self, node_id: NodeID) -> Option<&str> {
421 self.vis_props.labels.get(&node_id).map(|t| t.as_str())
422 }
423}
424
425impl PartialEq for Context {
426 fn eq(&self, other: &Self) -> bool {
427 self.magic_id == other.magic_id && self.name_id == other.name_id
428 }
429}
430
431impl Eq for Context {}
432
433impl PartialOrd for Context {
435 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
436 if self.magic_id == other.magic_id {
437 if other.globals.get_id(self.get_name()) == Some(self.name_id) {
438 Some(other.name_id.cmp(&self.name_id))
442 } else if self.globals.get_id(other.get_name()) == Some(other.name_id) {
443 match other.name_id.cmp(&self.name_id) {
445 cmp::Ordering::Less => Some(cmp::Ordering::Less),
447 cmp::Ordering::Greater => unreachable!(),
450 cmp::Ordering::Equal => unreachable!(),
453 }
454 } else if self.name_id == other.name_id {
455 unreachable!()
457 } else {
458 None
459 }
460 } else {
461 None
462 }
463 }
464}
465
466pub trait Contextual: Sized {
472 fn format(&self, ctx: &ContextHandle) -> Result<String, AcesError>;
473
474 #[inline]
475 fn with(&self, ctx: &ContextHandle) -> InContext<Self> {
476 InContext { context: ctx.clone(), thing: self }
477 }
478
479 #[inline]
480 fn with_mut(&mut self, ctx: &ContextHandle) -> InContextMut<Self> {
481 InContextMut { context: ctx.clone(), thing: self }
482 }
483}
484
485pub trait ExclusivelyContextual: Sized {
488 fn format_locked(&self, ctx: &Context) -> Result<String, AcesError>;
489}
490
491impl<T: ExclusivelyContextual> Contextual for T {
492 #[inline]
493 fn format(&self, ctx: &ContextHandle) -> Result<String, AcesError> {
494 self.format_locked(&ctx.lock().unwrap())
495 }
496}
497
498impl<T: ExclusivelyContextual> Contextual for Vec<T> {
499 fn format(&self, ctx: &ContextHandle) -> Result<String, AcesError> {
500 let mut elts = self.iter();
501
502 if let Some(elt) = elts.next() {
503 let ctx = ctx.lock().unwrap();
504 let mut elts_repr = elt.format_locked(&ctx)?;
505
506 for elt in elts {
507 elts_repr.push_str(&format!(", {}", elt.format_locked(&ctx)?));
508 }
509
510 Ok(format!("{{{}}}", elts_repr))
511 } else {
512 Ok("{{}}".to_owned())
513 }
514 }
515}
516
517pub struct InContext<'a, D: Contextual> {
525 context: ContextHandle,
526 thing: &'a D,
527}
528
529impl<D: Contextual> InContext<'_, D> {
530 pub fn using_context<T, F>(&self, f: F) -> T
531 where
532 F: FnOnce(&D, &Context) -> T,
533 {
534 let ctx = self.context.lock().unwrap();
535
536 f(self.thing, &ctx)
537 }
538
539 #[inline]
540 pub fn same_context(&self, other: &Self) -> bool {
541 Arc::ptr_eq(&self.context, &other.context)
542 }
543
544 #[inline]
545 pub fn get_context(&self) -> &ContextHandle {
546 &self.context
547 }
548
549 #[inline]
550 pub fn get_thing(&self) -> &D {
551 self.thing
552 }
553}
554
555impl<'a, D: Contextual> fmt::Display for InContext<'a, D> {
556 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
557 write!(f, "{}", self.thing.format(&self.context).expect("Can't display"))
558 }
559}
560
561pub struct InContextMut<'a, D: Contextual> {
569 context: ContextHandle,
570 thing: &'a mut D,
571}
572
573impl<D: Contextual> InContextMut<'_, D> {
574 pub fn using_context<T, F>(&mut self, f: F) -> T
575 where
576 F: FnOnce(&mut D, &Context) -> T,
577 {
578 let ctx = self.context.lock().unwrap();
579
580 f(self.thing, &ctx)
581 }
582
583 #[inline]
584 pub fn same_context(&self, other: &Self) -> bool {
585 Arc::ptr_eq(&self.context, &other.context)
586 }
587
588 #[inline]
589 pub fn get_context(&self) -> &ContextHandle {
590 &self.context
591 }
592
593 #[inline]
594 pub fn get_thing(&self) -> &D {
595 self.thing
596 }
597
598 #[inline]
599 pub fn get_thing_mut(&mut self) -> &mut D {
600 self.thing
601 }
602}
603
604impl<'a, D: Contextual> fmt::Display for InContextMut<'a, D> {
605 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
606 write!(f, "{}", self.thing.format(&self.context).expect("Can't display"))
607 }
608}
609
610#[cfg(test)]
611mod tests {
612 use super::*;
613
614 fn new_port(ctx: &ContextHandle, face: Face, host_name: &str) -> (Port, PortID) {
615 let mut ctx = ctx.lock().unwrap();
616 let node_id = ctx.share_node_name(host_name);
617 let mut port = Port::new(face, node_id);
618 let port_id = ctx.share_port(&mut port);
619
620 (port, port_id)
621 }
622
623 #[test]
624 fn test_partial_order() {
625 let toplevel = Context::new_toplevel("toplevel");
626 let derived = Context::new_derived("derived", &toplevel);
627
628 assert_eq!(
629 toplevel.lock().unwrap().partial_cmp(&derived.lock().unwrap()),
630 Some(cmp::Ordering::Greater)
631 );
632 }
633
634 #[test]
635 fn test_derivation() {
636 let toplevel = Context::new_toplevel("toplevel");
637 let (a_port, a_port_id) = new_port(&toplevel, Face::Tx, "a");
638
639 {
640 let derived = Context::new_derived("derived", &toplevel);
641 let (_, z_port_id) = new_port(&derived, Face::Rx, "z");
642
643 assert_eq!(derived.lock().unwrap().get_port(a_port_id), Some(&a_port));
644 assert_eq!(toplevel.lock().unwrap().get_port(z_port_id), None);
645 }
646
647 let (b_port, b_port_id) = new_port(&toplevel, Face::Tx, "b");
648
649 assert_eq!(toplevel.lock().unwrap().get_port(b_port_id), Some(&b_port));
650 }
651}