use std::{
collections::BTreeMap,
marker::PhantomData,
ops::{ShlAssign, Shr},
};
use serde_json::Value;
#[derive(Debug)]
pub enum SIMPError {
AlreadyDefined(serde_json::Value),
SerializationError(serde_json::Error),
}
impl std::fmt::Display for SIMPError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
write!(f, "{:?}", self)
}
}
impl std::error::Error for SIMPError {}
impl From<serde_json::Error> for SIMPError {
fn from(v: serde_json::Error) -> Self {
SIMPError::SerializationError(v)
}
}
pub trait SIMP {
fn static_get_protocol_number() -> i64
where
Self: Sized;
fn get_protocol_number(&self) -> i64;
fn to_json(&self) -> Result<Value, serde_json::Error>;
fn from_json(value: Value) -> Result<Self, serde_json::Error>
where
Self: Sized;
}
pub trait LocationTag {}
macro_rules! gen_location {
($x:ident) => {
pub struct $x;
impl LocationTag for $x {}
};
}
gen_location!(ContinuationPointLT);
gen_location!(CompiledObjectLT);
gen_location!(TemplateLT);
gen_location!(TemplateOutputLT);
gen_location!(GuardLT);
gen_location!(TemplateInputLT);
pub trait SIMPAttachableAt<T: LocationTag>
where
Self: SIMP,
{
}
pub struct BySIMP<T>(pub PhantomData<T>);
pub fn by_simp<T>() -> BySIMP<T> {
BySIMP(Default::default())
}
pub struct SimpValue<T>(pub T);
pub fn simp_value<T: SIMP>(v: T) -> SimpValue<T> {
SimpValue(v)
}
impl<T: SIMP> ShlAssign<SimpValue<T>> for BTreeMap<i64, Value> {
fn shl_assign(&mut self, rhs: SimpValue<T>) {
if let Ok(js) = rhs.0.to_json() {
self.insert(T::static_get_protocol_number(), js);
}
}
}
impl ShlAssign<Box<dyn SIMP>> for BTreeMap<i64, Box<dyn SIMP>> {
fn shl_assign(&mut self, rhs: Box<dyn SIMP>) {
self.insert(rhs.get_protocol_number(), rhs);
}
}
impl<'a, T: SIMP, V> Shr<BySIMP<T>> for &'a BTreeMap<i64, V> {
type Output = Option<&'a V>;
fn shr(self, _rhs: BySIMP<T>) -> Self::Output {
self.get(&T::static_get_protocol_number())
}
}
impl<'a, T: SIMP, V> Shr<BySIMP<T>> for &'a mut BTreeMap<i64, V> {
type Output = Option<&'a mut V>;
fn shr(self, _rhs: BySIMP<T>) -> Self::Output {
self.get_mut(&T::static_get_protocol_number())
}
}