use std::{
cmp, fmt,
error::Error,
sync::{Arc, Mutex},
};
use crate::{
Port, Link, NodeID, PortID, LinkID, node,
name::NameSpace,
atom::{AtomSpace, AtomID},
};
pub type ContextHandle = Arc<Mutex<Context>>;
#[derive(Debug)]
pub struct Context {
id: usize, pub(crate) globals: NameSpace,
pub(crate) nodes: NameSpace,
pub(crate) atoms: AtomSpace,
}
impl Context {
fn new() -> Self {
Self {
id: rand::random(), globals: Default::default(),
nodes: Default::default(),
atoms: Default::default(),
}
}
pub fn new_as_handle() -> ContextHandle {
Arc::new(Mutex::new(Context::new()))
}
pub fn share_node_name<S: AsRef<str>>(&mut self, node_name: S) -> NodeID {
NodeID(self.nodes.share_name(node_name))
}
pub fn get_node_name(&self, node_id: NodeID) -> Option<&str> {
self.nodes.get_name(node_id.get())
}
pub fn get_node_id<S: AsRef<str>>(&self, node_name: S) -> Option<NodeID> {
self.nodes.get_id(node_name).map(NodeID)
}
pub(crate) fn is_port(&self, atom_id: AtomID) -> bool {
self.atoms.is_port(atom_id)
}
pub fn share_port(&mut self, port: &mut Port) -> PortID {
self.atoms.share_port(port)
}
pub fn share_link(&mut self, link: &mut Link) -> LinkID {
self.atoms.share_link(link)
}
pub fn get_port(&self, port_id: PortID) -> Option<&Port> {
self.atoms.get_port(port_id)
}
pub fn get_port_mut(&mut self, port_id: PortID) -> Option<&mut Port> {
self.atoms.get_port_mut(port_id)
}
pub fn get_link(&self, link_id: LinkID) -> Option<&Link> {
self.atoms.get_link(link_id)
}
pub fn get_link_mut(&mut self, link_id: LinkID) -> Option<&mut Link> {
self.atoms.get_link_mut(link_id)
}
pub fn get_antiport_id(&self, port_id: PortID) -> Option<PortID> {
self.atoms.get_antiport_id(port_id)
}
}
impl cmp::PartialEq for Context {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl cmp::Eq for Context {}
pub trait Contextual {
fn format(&self, ctx: &Context, dock: Option<node::Face>) -> Result<String, Box<dyn Error>>;
}
pub struct InContext<'a, D: Contextual> {
context: &'a Context,
dock: Option<node::Face>,
thing: &'a D,
}
impl<D: Contextual> InContext<'_, D> {
#[inline]
pub fn get_context(&self) -> &Context {
self.context
}
#[inline]
pub fn get_dock(&self) -> Option<node::Face> {
self.dock
}
#[inline]
pub fn get_thing(&self) -> &D {
self.thing
}
}
impl<'a, D: Contextual> fmt::Display for InContext<'a, D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.thing.format(self.context, self.dock).expect("Can't display"))
}
}
pub struct InContextMut<'a, D: Contextual> {
context: &'a Context,
dock: Option<node::Face>,
thing: &'a mut D,
}
impl<D: Contextual> InContextMut<'_, D> {
#[inline]
pub fn get_context(&self) -> &Context {
self.context
}
#[inline]
pub fn get_dock(&self) -> Option<node::Face> {
self.dock
}
#[inline]
pub fn get_thing(&self) -> &D {
self.thing
}
#[inline]
pub fn get_thing_mut(&mut self) -> &mut D {
self.thing
}
}
impl<'a, D: Contextual> fmt::Display for InContextMut<'a, D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.thing.format(self.context, self.dock).expect("Can't display"))
}
}
impl Context {
pub fn with<'a, T: Contextual>(&'a self, thing: &'a T) -> InContext<'a, T> {
InContext { context: self, dock: None, thing }
}
pub fn with_mut<'a, T: Contextual>(&'a self, thing: &'a mut T) -> InContextMut<'a, T> {
InContextMut { context: self, dock: None, thing }
}
pub fn with_docked<'a, T: Contextual>(
&'a self,
face: node::Face,
thing: &'a T,
) -> InContext<'a, T> {
InContext { context: self, dock: Some(face), thing }
}
pub fn with_docked_mut<'a, T: Contextual>(
&'a self,
face: node::Face,
thing: &'a mut T,
) -> InContextMut<'a, T> {
InContextMut { context: self, dock: Some(face), thing }
}
}