1use std::{
2 fmt, hash,
3 collections::{BTreeMap, BTreeSet, HashMap},
4};
5use crate::{
6 Face, ID, NodeID, Context, Contextual, ExclusivelyContextual, InContext, AcesError,
7 AcesErrorKind, sat,
8};
9
10pub type AtomID = ID;
19
20#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
26#[repr(transparent)]
27pub struct PortID(pub(crate) AtomID);
28
29impl PortID {
30 #[inline]
31 pub const fn get(self) -> AtomID {
32 self.0
33 }
34}
35
36impl From<AtomID> for PortID {
37 #[inline]
38 fn from(id: AtomID) -> Self {
39 PortID(id)
40 }
41}
42
43impl From<PortID> for AtomID {
44 #[inline]
45 fn from(id: PortID) -> Self {
46 id.0
47 }
48}
49
50impl ExclusivelyContextual for PortID {
51 fn format_locked(&self, ctx: &Context) -> Result<String, AcesError> {
52 let port = ctx
53 .get_port(*self)
54 .ok_or_else(|| AcesError::from(AcesErrorKind::PortMissingForID(*self)))?;
55 port.format_locked(ctx)
56 }
57}
58
59#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
65#[repr(transparent)]
66pub struct LinkID(pub(crate) AtomID);
67
68impl LinkID {
69 #[inline]
70 pub const fn get(self) -> AtomID {
71 self.0
72 }
73}
74
75impl From<AtomID> for LinkID {
76 #[inline]
77 fn from(id: AtomID) -> Self {
78 LinkID(id)
79 }
80}
81
82impl From<LinkID> for AtomID {
83 #[inline]
84 fn from(id: LinkID) -> Self {
85 id.0
86 }
87}
88
89impl ExclusivelyContextual for LinkID {
90 fn format_locked(&self, ctx: &Context) -> Result<String, AcesError> {
91 let link = ctx
92 .get_link(*self)
93 .ok_or_else(|| AcesError::from(AcesErrorKind::LinkMissingForID(*self)))?;
94 link.format_locked(ctx)
95 }
96}
97
98#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
104#[repr(transparent)]
105pub struct ForkID(pub(crate) AtomID);
106
107impl ForkID {
108 #[inline]
109 pub const fn get(self) -> AtomID {
110 self.0
111 }
112}
113
114impl From<AtomID> for ForkID {
115 #[inline]
116 fn from(id: AtomID) -> Self {
117 ForkID(id)
118 }
119}
120
121impl From<ForkID> for AtomID {
122 #[inline]
123 fn from(id: ForkID) -> Self {
124 id.0
125 }
126}
127
128impl ExclusivelyContextual for ForkID {
129 fn format_locked(&self, ctx: &Context) -> Result<String, AcesError> {
130 let fork = ctx
131 .get_fork(*self)
132 .ok_or_else(|| AcesError::from(AcesErrorKind::ForkMissingForID(*self)))?;
133 fork.format_locked(ctx)
134 }
135}
136
137#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
143#[repr(transparent)]
144pub struct JoinID(pub(crate) AtomID);
145
146impl JoinID {
147 #[inline]
148 pub const fn get(self) -> AtomID {
149 self.0
150 }
151}
152
153impl From<AtomID> for JoinID {
154 #[inline]
155 fn from(id: AtomID) -> Self {
156 JoinID(id)
157 }
158}
159
160impl From<JoinID> for AtomID {
161 #[inline]
162 fn from(id: JoinID) -> Self {
163 id.0
164 }
165}
166
167impl ExclusivelyContextual for JoinID {
168 fn format_locked(&self, ctx: &Context) -> Result<String, AcesError> {
169 let join = ctx
170 .get_join(*self)
171 .ok_or_else(|| AcesError::from(AcesErrorKind::JoinMissingForID(*self)))?;
172 join.format_locked(ctx)
173 }
174}
175
176#[derive(Clone, Debug)]
184pub(crate) struct AtomSpace {
185 atoms: Vec<Atom>,
186 atom_ids: HashMap<Atom, AtomID>,
187 source_nodes: BTreeMap<NodeID, PortID>,
188 sink_nodes: BTreeMap<NodeID, PortID>,
189 internal_nodes: BTreeMap<NodeID, (PortID, PortID)>,
190}
191
192impl Default for AtomSpace {
193 fn default() -> Self {
194 Self {
195 atoms: vec![Atom::Bottom],
196 atom_ids: Default::default(),
197 source_nodes: Default::default(),
198 sink_nodes: Default::default(),
199 internal_nodes: Default::default(),
200 }
201 }
202}
203
204impl AtomSpace {
205 fn do_share_atom(&mut self, mut new_atom: Atom) -> AtomID {
206 if let Some(old_atom_id) = self.get_atom_id(&new_atom) {
207 if new_atom.get_atom_id().is_none() {
208 trace!("Resharing: {:?}", new_atom);
209
210 old_atom_id
211 } else {
212 panic!("Attempt to reset ID of atom {:?}", new_atom);
213 }
214 } else {
215 let atom_id = unsafe { AtomID::new_unchecked(self.atoms.len()) };
216 new_atom.set_atom_id(atom_id);
217
218 trace!("New share: {:?}", new_atom);
219
220 self.atoms.push(new_atom.clone());
221 self.atom_ids.insert(new_atom, atom_id);
222
223 atom_id
224 }
225 }
226
227 pub(crate) fn share_port(&mut self, port: &mut Port) -> PortID {
228 let host = port.node_id;
229
230 match port.face {
231 Face::Tx => {
232 let atom_id = self.do_share_atom(Atom::Tx(port.clone()));
233
234 port.atom_id = Some(atom_id);
235
236 let pid = PortID(atom_id);
237
238 if let Some(&rx_id) = self.sink_nodes.get(&host) {
239 self.sink_nodes.remove(&host);
240 self.internal_nodes.insert(host, (pid, rx_id));
241 } else {
242 self.source_nodes.insert(host, pid);
243 }
244
245 pid
246 }
247 Face::Rx => {
248 let atom_id = self.do_share_atom(Atom::Rx(port.clone()));
249
250 port.atom_id = Some(atom_id);
251
252 let pid = PortID(atom_id);
253
254 if let Some(&tx_id) = self.source_nodes.get(&host) {
255 self.source_nodes.remove(&host);
256 self.internal_nodes.insert(host, (tx_id, pid));
257 } else {
258 self.sink_nodes.insert(host, pid);
259 }
260
261 pid
262 }
263 }
264 }
265
266 #[inline]
267 pub(crate) fn share_link(&mut self, link: &mut Link) -> LinkID {
268 let atom_id = self.do_share_atom(Atom::Link(link.clone()));
269
270 link.atom_id = Some(atom_id);
271
272 LinkID(atom_id)
273 }
274
275 #[inline]
276 pub(crate) fn share_fork(&mut self, fork: &mut Fork) -> ForkID {
277 let atom_id = self.do_share_atom(Atom::Fork(fork.clone()));
278
279 fork.atom_id = Some(atom_id);
280
281 ForkID(atom_id)
282 }
283
284 #[inline]
285 pub(crate) fn share_join(&mut self, join: &mut Join) -> JoinID {
286 let atom_id = self.do_share_atom(Atom::Join(join.clone()));
287
288 join.atom_id = Some(atom_id);
289
290 JoinID(atom_id)
291 }
292
293 #[inline]
294 pub(crate) fn get_atom(&self, atom_id: AtomID) -> Option<&Atom> {
295 self.atoms.get(atom_id.get())
296 }
297
298 #[inline]
299 pub(crate) fn get_atom_id(&self, atom: &Atom) -> Option<AtomID> {
300 self.atom_ids.get(atom).copied()
301 }
302
303 #[inline]
304 pub(crate) fn is_port(&self, atom_id: AtomID) -> bool {
305 match self.get_atom(atom_id) {
306 Some(Atom::Tx(_)) | Some(Atom::Rx(_)) => true,
307 _ => false,
308 }
309 }
310
311 #[inline]
312 pub(crate) fn get_port(&self, pid: PortID) -> Option<&Port> {
313 match self.get_atom(pid.into()) {
314 Some(Atom::Tx(a)) => Some(a),
315 Some(Atom::Rx(a)) => Some(a),
316 _ => None,
317 }
318 }
319
320 #[inline]
321 pub(crate) fn is_link(&self, atom_id: AtomID) -> bool {
322 match self.get_atom(atom_id) {
323 Some(Atom::Link(_)) => true,
324 _ => false,
325 }
326 }
327
328 #[inline]
329 pub(crate) fn get_link(&self, lid: LinkID) -> Option<&Link> {
330 match self.get_atom(lid.into()) {
331 Some(Atom::Link(a)) => Some(a),
332 _ => None,
333 }
334 }
335
336 #[inline]
337 pub(crate) fn is_harc(&self, atom_id: AtomID) -> bool {
338 match self.get_atom(atom_id) {
339 Some(Atom::Fork(_)) | Some(Atom::Join(_)) => true,
340 _ => false,
341 }
342 }
343
344 #[inline]
345 pub(crate) fn get_harc(&self, aid: AtomID) -> Option<&Harc> {
346 match self.get_atom(aid) {
347 Some(Atom::Fork(a)) => Some(a),
348 Some(Atom::Join(a)) => Some(a),
349 _ => None,
350 }
351 }
352
353 #[inline]
354 pub(crate) fn is_fork(&self, atom_id: AtomID) -> bool {
355 match self.get_atom(atom_id) {
356 Some(Atom::Fork(_)) => true,
357 _ => false,
358 }
359 }
360
361 #[inline]
362 pub(crate) fn get_fork(&self, fid: ForkID) -> Option<&Fork> {
363 match self.get_atom(fid.into()) {
364 Some(Atom::Fork(a)) => Some(a),
365 _ => None,
366 }
367 }
368
369 #[inline]
370 pub(crate) fn is_join(&self, atom_id: AtomID) -> bool {
371 match self.get_atom(atom_id) {
372 Some(Atom::Join(_)) => true,
373 _ => false,
374 }
375 }
376
377 #[inline]
378 pub(crate) fn get_join(&self, jid: JoinID) -> Option<&Join> {
379 match self.get_atom(jid.into()) {
380 Some(Atom::Join(a)) => Some(a),
381 _ => None,
382 }
383 }
384
385 pub fn get_antiport_id(&self, pid: PortID) -> Option<PortID> {
386 if let Some(port) = self.get_port(pid) {
387 if let Some(&(tx_id, rx_id)) = self.internal_nodes.get(&port.node_id) {
388 match port.face {
389 Face::Tx => {
390 if tx_id == pid {
391 return Some(rx_id)
392 } else {
393 panic!("Corrupt atom space")
394 }
395 }
396 Face::Rx => {
397 if rx_id == pid {
398 return Some(tx_id)
399 } else {
400 panic!("Corrupt atom space")
401 }
402 }
403 }
404 }
405 }
406
407 None
408 }
409}
410
411#[derive(Clone, Eq, Debug)]
412pub(crate) enum Atom {
413 Tx(Port),
414 Rx(Port),
415 Link(Link),
416 Fork(Fork),
417 Join(Join),
418 Bottom,
419}
420
421impl Atom {
422 fn set_atom_id(&mut self, atom_id: AtomID) {
423 use Atom::*;
424
425 let prev_id = match self {
426 Tx(p) => &mut p.atom_id,
427 Rx(p) => &mut p.atom_id,
428 Link(l) => &mut l.atom_id,
429 Fork(f) => &mut f.atom_id,
430 Join(j) => &mut j.atom_id,
431 Bottom => panic!("Attempt to set ID of the bottom atom"),
432 };
433
434 if *prev_id == None {
435 *prev_id = Some(atom_id);
436 } else {
437 panic!("Attempt to reset ID of atom {:?}", self);
438 }
439 }
440
441 fn get_atom_id(&self) -> Option<AtomID> {
442 use Atom::*;
443
444 match self {
445 Tx(p) => p.atom_id,
446 Rx(p) => p.atom_id,
447 Link(l) => l.atom_id,
448 Fork(f) => f.atom_id,
449 Join(j) => j.atom_id,
450 Bottom => panic!("Attempt to get ID of the bottom atom"),
451 }
452 }
453}
454
455impl PartialEq for Atom {
456 #[rustfmt::skip]
457 fn eq(&self, other: &Self) -> bool {
458 use Atom::*;
459
460 match self {
461 Tx(p) => if let Tx(o) = other { p == o } else { false },
462 Rx(p) => if let Rx(o) = other { p == o } else { false },
463 Link(l) => if let Link(o) = other { l == o } else { false },
464 Fork(f) => if let Fork(o) = other { f == o } else { false },
465 Join(j) => if let Join(o) = other { j == o } else { false },
466 Bottom => panic!("Attempt to access the bottom atom"),
467 }
468 }
469}
470
471impl hash::Hash for Atom {
472 fn hash<H: hash::Hasher>(&self, state: &mut H) {
473 use Atom::*;
474
475 match self {
476 Tx(p) | Rx(p) => p.hash(state),
477 Link(l) => l.hash(state),
478 Fork(f) => f.hash(state),
479 Join(j) => j.hash(state),
480 Bottom => panic!("Attempt to access the bottom atom"),
481 }
482 }
483}
484
485#[derive(Clone, Eq, Debug)]
489pub struct Port {
490 face: Face,
491 atom_id: Option<AtomID>,
492 node_id: NodeID,
493}
494
495impl Port {
496 pub(crate) fn new(face: Face, node_id: NodeID) -> Self {
497 Self { face, atom_id: None, node_id }
498 }
499
500 pub(crate) fn get_face(&self) -> Face {
501 self.face
502 }
503
504 pub fn get_atom_id(&self) -> AtomID {
505 self.atom_id.expect("Attempt to access an uninitialized port")
506 }
507
508 pub fn get_node_id(&self) -> NodeID {
509 self.node_id
510 }
511}
512
513impl PartialEq for Port {
514 fn eq(&self, other: &Self) -> bool {
515 self.node_id == other.node_id
516 }
517}
518
519impl hash::Hash for Port {
520 fn hash<H: hash::Hasher>(&self, state: &mut H) {
521 self.face.hash(state);
522 self.node_id.hash(state);
523 }
524}
525
526impl ExclusivelyContextual for Port {
527 fn format_locked(&self, ctx: &Context) -> Result<String, AcesError> {
528 let node_name = ctx
529 .get_node_name(self.get_node_id())
530 .ok_or_else(|| AcesError::from(AcesErrorKind::NodeMissingForPort(self.get_face())))?;
531
532 Ok(format!("[{} {}]", node_name, self.get_face()))
533 }
534}
535
536#[derive(Clone, Eq, Debug)]
545pub struct Link {
546 atom_id: Option<AtomID>,
547 tx_port_id: PortID,
548 tx_node_id: NodeID,
549 rx_port_id: PortID,
550 rx_node_id: NodeID,
551}
552
553impl Link {
554 pub fn new(
555 tx_port_id: PortID,
556 tx_node_id: NodeID,
557 rx_port_id: PortID,
558 rx_node_id: NodeID,
559 ) -> Self {
560 Self { atom_id: None, tx_port_id, tx_node_id, rx_port_id, rx_node_id }
561 }
562
563 pub fn get_atom_id(&self) -> AtomID {
564 self.atom_id.expect("Attempt to access an uninitialized link")
565 }
566
567 pub fn get_link_id(&self) -> LinkID {
568 LinkID(self.get_atom_id())
569 }
570
571 pub fn get_port_id(&self, face: Face) -> PortID {
572 if face == Face::Rx {
573 self.rx_port_id
574 } else {
575 self.tx_port_id
576 }
577 }
578
579 pub fn get_node_id(&self, face: Face) -> NodeID {
580 if face == Face::Rx {
581 self.rx_node_id
582 } else {
583 self.tx_node_id
584 }
585 }
586
587 pub fn get_tx_port_id(&self) -> PortID {
588 self.tx_port_id
589 }
590
591 pub fn get_tx_node_id(&self) -> NodeID {
592 self.tx_node_id
593 }
594
595 pub fn get_rx_port_id(&self) -> PortID {
596 self.rx_port_id
597 }
598
599 pub fn get_rx_node_id(&self) -> NodeID {
600 self.rx_node_id
601 }
602}
603
604impl PartialEq for Link {
605 fn eq(&self, other: &Self) -> bool {
606 self.tx_port_id == other.tx_port_id && self.rx_node_id == other.rx_node_id
607 }
608}
609
610impl hash::Hash for Link {
611 fn hash<H: hash::Hasher>(&self, state: &mut H) {
612 self.tx_port_id.hash(state);
613 self.tx_node_id.hash(state);
614 self.rx_port_id.hash(state);
615 self.rx_node_id.hash(state);
616 }
617}
618
619impl ExclusivelyContextual for Link {
620 fn format_locked(&self, ctx: &Context) -> Result<String, AcesError> {
621 let tx_node_name = ctx
622 .get_node_name(self.get_tx_node_id())
623 .ok_or_else(|| AcesError::from(AcesErrorKind::NodeMissingForLink(Face::Tx)))?;
624 let rx_node_name = ctx
625 .get_node_name(self.get_rx_node_id())
626 .ok_or_else(|| AcesError::from(AcesErrorKind::NodeMissingForLink(Face::Rx)))?;
627
628 Ok(format!("({} > {})", tx_node_name, rx_node_name))
629 }
630}
631
632#[derive(Clone, Eq)]
640pub struct Harc {
641 atom_id: Option<AtomID>,
642 face: Face,
643 host_id: NodeID,
644 suit_ids: Vec<NodeID>,
645}
646
647impl Harc {
648 fn new_unchecked(face: Face, host_id: NodeID, suit_ids: Vec<NodeID>) -> Self {
649 if cfg!(debug_assertions) {
650 let mut sit = suit_ids.iter();
651
652 if let Some(nid) = sit.next() {
653 let mut prev_nid = *nid;
654
655 for &nid in sit {
656 assert!(prev_nid < nid, "Unordered suit");
657 prev_nid = nid;
658 }
659 } else {
660 panic!("Empty suit")
661 }
662 }
663 Harc { atom_id: None, face, host_id, suit_ids }
664 }
665
666 pub fn new_fork<I>(host_id: NodeID, suit_ids: I) -> Self
670 where
671 I: IntoIterator<Item = NodeID>,
672 {
673 let suit_ids: BTreeSet<_> = suit_ids.into_iter().collect();
674
675 if suit_ids.is_empty() {
676 }
678
679 Self::new_fork_unchecked(host_id, suit_ids)
680 }
681
682 pub fn new_join<I>(host_id: NodeID, suit_ids: I) -> Self
686 where
687 I: IntoIterator<Item = NodeID>,
688 {
689 let suit_ids: BTreeSet<_> = suit_ids.into_iter().collect();
690
691 if suit_ids.is_empty() {
692 }
694
695 Self::new_join_unchecked(host_id, suit_ids)
696 }
697
698 pub fn new_fork_unchecked<I>(host_id: NodeID, suit_ids: I) -> Self
706 where
707 I: IntoIterator<Item = NodeID>,
708 {
709 let suit_ids: Vec<_> = suit_ids.into_iter().collect();
710 trace!("New fork: {:?} -> {:?}", host_id, suit_ids);
711 Harc::new_unchecked(Face::Tx, host_id, suit_ids)
712 }
713
714 pub fn new_join_unchecked<I>(host_id: NodeID, suit_ids: I) -> Self
722 where
723 I: IntoIterator<Item = NodeID>,
724 {
725 let suit_ids: Vec<_> = suit_ids.into_iter().collect();
726 trace!("New join: {:?} <- {:?}", host_id, suit_ids);
727 Harc::new_unchecked(Face::Rx, host_id, suit_ids)
728 }
729
730 pub fn get_atom_id(&self) -> AtomID {
731 match self.face {
732 Face::Tx => self.atom_id.expect("Attempt to access an uninitialized fork"),
733 Face::Rx => self.atom_id.expect("Attempt to access an uninitialized join"),
734 }
735 }
736
737 pub fn get_fork_id(&self) -> Option<ForkID> {
738 match self.face {
739 Face::Tx => Some(ForkID(self.get_atom_id())),
740 Face::Rx => None,
741 }
742 }
743
744 pub fn get_join_id(&self) -> Option<JoinID> {
745 match self.face {
746 Face::Tx => None,
747 Face::Rx => Some(JoinID(self.get_atom_id())),
748 }
749 }
750
751 pub fn get_host_id(&self) -> NodeID {
752 self.host_id
753 }
754
755 pub fn get_suit_ids(&self) -> &[NodeID] {
756 self.suit_ids.as_slice()
757 }
758}
759
760impl fmt::Debug for Harc {
761 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
762 write!(
763 f,
764 "{} {{ atom_id: ",
765 match self.face {
766 Face::Tx => "Fork",
767 Face::Rx => "Join",
768 }
769 )?;
770 self.atom_id.fmt(f)?;
771 write!(f, ", host_id: ")?;
772 self.host_id.fmt(f)?;
773 write!(f, ", suit_ids: ")?;
774 self.suit_ids.fmt(f)?;
775 write!(f, " }}")
776 }
777}
778
779impl PartialEq for Harc {
780 #[inline]
781 fn eq(&self, other: &Self) -> bool {
782 self.face == other.face && self.host_id == other.host_id && self.suit_ids == other.suit_ids
783 }
784}
785
786impl hash::Hash for Harc {
787 fn hash<H: hash::Hasher>(&self, state: &mut H) {
788 self.face.hash(state);
789 self.host_id.hash(state);
790 self.suit_ids.hash(state);
791 }
792}
793
794impl ExclusivelyContextual for Harc {
795 fn format_locked(&self, ctx: &Context) -> Result<String, AcesError> {
796 let host_name = ctx.get_node_name(self.get_host_id()).ok_or(match self.face {
797 Face::Tx => AcesError::from(AcesErrorKind::NodeMissingForFork(Face::Tx)),
798 Face::Rx => AcesError::from(AcesErrorKind::NodeMissingForJoin(Face::Rx)),
799 })?;
800
801 let suit_names: Result<Vec<_>, AcesError> = self
802 .get_suit_ids()
803 .iter()
804 .map(|&node_id| {
805 ctx.get_node_name(node_id).ok_or(match self.face {
806 Face::Tx => AcesError::from(AcesErrorKind::NodeMissingForFork(Face::Rx)),
807 Face::Rx => AcesError::from(AcesErrorKind::NodeMissingForJoin(Face::Tx)),
808 })
809 })
810 .collect();
811
812 match self.face {
813 Face::Tx => Ok(format!("({} > {:?})", host_name, suit_names?)),
814 Face::Rx => Ok(format!("({:?} > {})", suit_names?, host_name)),
815 }
816 }
817}
818
819pub type Fork = Harc;
821
822pub type Join = Harc;
824
825pub trait Atomic:
828 From<AtomID> + Into<AtomID> + Contextual + Copy + PartialEq + Eq + PartialOrd + Ord
829{
830 fn into_node_id(this: InContext<Self>) -> Option<NodeID>;
831
832 fn into_node_id_docked(this: InContext<Self>, _dock: Face) -> Option<NodeID> {
833 Self::into_node_id(this)
834 }
835
836 fn into_sat_literal(self, negated: bool) -> sat::Literal;
837}
838
839impl Atomic for PortID {
840 fn into_node_id(this: InContext<Self>) -> Option<NodeID> {
841 this.using_context(|pid, ctx| ctx.get_port(*pid).map(|port| port.get_node_id()))
842 }
843
844 #[inline]
845 fn into_sat_literal(self, negated: bool) -> sat::Literal {
846 sat::Literal::from_atom_id(self.get(), negated)
847 }
848}
849
850impl Atomic for LinkID {
851 fn into_node_id(_this: InContext<Self>) -> Option<NodeID> {
852 None
853 }
854
855 fn into_node_id_docked(this: InContext<Self>, dock: Face) -> Option<NodeID> {
856 this.using_context(|lid, ctx| ctx.get_link(*lid).map(|link| link.get_node_id(dock)))
857 }
858
859 #[inline]
860 fn into_sat_literal(self, negated: bool) -> sat::Literal {
861 sat::Literal::from_atom_id(self.get(), negated)
862 }
863}
864
865impl Atomic for ForkID {
866 fn into_node_id(this: InContext<Self>) -> Option<NodeID> {
867 this.using_context(|fid, ctx| ctx.get_fork(*fid).map(|fork| fork.get_host_id()))
868 }
869
870 #[inline]
871 fn into_sat_literal(self, negated: bool) -> sat::Literal {
872 sat::Literal::from_atom_id(self.get(), negated)
873 }
874}
875
876impl Atomic for JoinID {
877 fn into_node_id(this: InContext<Self>) -> Option<NodeID> {
878 this.using_context(|jid, ctx| ctx.get_join(*jid).map(|join| join.get_host_id()))
879 }
880
881 #[inline]
882 fn into_sat_literal(self, negated: bool) -> sat::Literal {
883 sat::Literal::from_atom_id(self.get(), negated)
884 }
885}
886
887#[cfg(test)]
888mod tests {
889 use super::*;
890
891 fn new_tx_port(id: usize) -> Port {
892 Port::new(Face::Tx, NodeID(unsafe { ID::new_unchecked(id) }))
893 }
894
895 #[test]
896 #[should_panic(expected = "uninitialized")]
897 fn test_atom_uninitialized() {
898 let atom = Atom::Tx(new_tx_port(1));
899 let _ = atom.get_atom_id().expect("uninitialized");
900 }
901
902 #[test]
903 #[should_panic(expected = "bottom")]
904 fn test_atom_bottom() {
905 let mut atoms = AtomSpace::default();
906 let atom = Atom::Bottom;
907 let _ = atoms.do_share_atom(atom);
908 }
909
910 #[test]
911 #[should_panic(expected = "reset")]
912 fn test_atom_reset_id() {
913 let mut atoms = AtomSpace::default();
914 let mut atom = Atom::Tx(new_tx_port(1));
915 atom.set_atom_id(unsafe { AtomID::new_unchecked(1) });
916 let _ = atoms.do_share_atom(atom);
917 }
918
919 #[test]
920 fn test_atom_id() {
921 let mut atoms = AtomSpace::default();
922 let atom = Atom::Tx(new_tx_port(1));
923 let atom_id = atoms.do_share_atom(atom);
924 let atom = atoms.get_atom(atom_id).unwrap();
925 assert_eq!(atom.get_atom_id().unwrap(), atom_id);
926 }
927}