use std::any::{Any, TypeId};
use std::fmt::{Debug, Display};
use std::hash::Hash;
use serde::de::DeserializeOwned;
use serde::Serialize;
use crate::algebra::signature::Signature;
use crate::algebra::Matcher;
use crate::claims::{Claim, SecurityViolationPolicy};
use crate::codec;
use crate::error::Error;
use crate::trace::{Knowledge, Source, Trace};
pub trait AsAny {
fn as_any(&self) -> &dyn Any;
}
impl<T: 'static> AsAny for T {
fn as_any(&self) -> &dyn Any {
self
}
}
pub trait Extractable<PT: ProtocolTypes>: std::fmt::Debug + AsAny
where
Self: 'static,
{
fn extract_knowledge<'a>(
&'a self,
knowledges: &mut Vec<Knowledge<'a, PT>>,
matcher: Option<PT::Matcher>,
source: &'a Source,
) -> Result<(), Error>;
}
pub trait EvaluatedTerm<PT: ProtocolTypes>:
codec::CodecP + Extractable<PT> + Debug + AsAny + 'static
where
Self: 'static,
{
fn type_id(&self) -> TypeId {
Any::type_id(self)
}
fn type_name(&self) -> &'static str {
std::any::type_name::<Self>()
}
fn boxed(&self) -> Box<dyn EvaluatedTerm<PT>>;
}
impl<T, PT: ProtocolTypes> EvaluatedTerm<PT> for T
where
T: codec::CodecP + Extractable<PT> + 'static + Clone,
{
fn boxed(&self) -> Box<dyn EvaluatedTerm<PT>> {
Box::new(self.clone())
}
}
pub trait ProtocolMessageFlight<
PT: ProtocolTypes,
M: ProtocolMessage<PT, O>,
O: OpaqueProtocolMessage<PT>,
OF: OpaqueProtocolMessageFlight<PT, O>,
>: Clone + Debug + From<M> + TryFrom<OF> + Into<OF> + EvaluatedTerm<PT>
{
fn new() -> Self;
fn push(&mut self, msg: M);
fn debug(&self, info: &str);
}
pub trait OpaqueProtocolMessageFlight<PT: ProtocolTypes, O: OpaqueProtocolMessage<PT>>:
Clone + Debug + codec::Codec + From<O> + EvaluatedTerm<PT>
{
fn new() -> Self;
fn debug(&self, info: &str);
fn push(&mut self, msg: O);
}
pub trait ProtocolMessage<PT: ProtocolTypes, O: OpaqueProtocolMessage<PT>>:
Clone + Debug + EvaluatedTerm<PT>
{
fn create_opaque(&self) -> O;
fn debug(&self, info: &str);
}
pub trait OpaqueProtocolMessage<PT: ProtocolTypes>: Clone + Debug + EvaluatedTerm<PT> {
fn debug(&self, info: &str);
}
pub trait ProtocolMessageDeframer<PT: ProtocolTypes> {
type OpaqueProtocolMessage: OpaqueProtocolMessage<PT>;
fn pop_frame(&mut self) -> Option<Self::OpaqueProtocolMessage>;
fn read(&mut self, rd: &mut dyn std::io::Read) -> std::io::Result<usize>;
}
pub trait ProtocolTypes:
'static + Clone + Hash + Display + Debug + Serialize + DeserializeOwned
{
type Matcher: Matcher;
fn signature() -> &'static Signature<Self>;
}
pub trait ProtocolBehavior: 'static {
type ProtocolTypes: ProtocolTypes;
type Claim: Claim<Self::ProtocolTypes>;
type SecurityViolationPolicy: SecurityViolationPolicy<Self::ProtocolTypes, Self::Claim>;
type ProtocolMessage: ProtocolMessage<Self::ProtocolTypes, Self::OpaqueProtocolMessage>;
type OpaqueProtocolMessage: OpaqueProtocolMessage<Self::ProtocolTypes>;
type ProtocolMessageFlight: ProtocolMessageFlight<
Self::ProtocolTypes,
Self::ProtocolMessage,
Self::OpaqueProtocolMessage,
Self::OpaqueProtocolMessageFlight,
>;
type OpaqueProtocolMessageFlight: OpaqueProtocolMessageFlight<Self::ProtocolTypes, Self::OpaqueProtocolMessage>
+ From<Self::ProtocolMessageFlight>;
fn create_corpus() -> Vec<(Trace<Self::ProtocolTypes>, &'static str)>;
fn any_get_encoding(message: &dyn EvaluatedTerm<Self::ProtocolTypes>) -> Vec<u8> {
codec::CodecP::get_encoding(message)
}
fn try_read_bytes(
bitstring: &[u8],
ty: TypeId,
) -> Result<Box<dyn EvaluatedTerm<Self::ProtocolTypes>>, Error>;
}
#[macro_export]
macro_rules! dummy_extract_knowledge {
($protocol_type:ty, $extract_type:ty) => {
impl Extractable<$protocol_type> for $extract_type {
fn extract_knowledge<'a>(
&'a self,
_knowledges: &mut Vec<Knowledge<'a, $protocol_type>>,
_matcher: Option<<$protocol_type as ProtocolTypes>::Matcher>,
_source: &'a Source,
) -> Result<(), Error> {
log::warn!(
"Trying to extract a dummy type: {}",
stringify!($extract_type)
);
Ok(())
}
}
};
}
#[macro_export]
macro_rules! dummy_codec {
($protocol_type:ty, $extract_type:ty) => {
impl codec::CodecP for $extract_type {
fn encode(&self, _bytes: &mut Vec<u8>) {
log::warn!(
"Trying to encode a dummy type: {}",
stringify!($extract_type)
);
}
fn read(&mut self, _r: &mut codec::Reader) -> Result<(), Error> {
log::warn!("Trying to read a dummy type: {}", stringify!($extract_type));
Ok(())
}
}
};
}
#[macro_export]
macro_rules! dummy_extract_knowledge_codec {
($protocol_type:ty, $extract_type:ty) => {
dummy_extract_knowledge!($protocol_type, $extract_type);
dummy_codec!($protocol_type, $extract_type);
};
}
#[macro_export]
macro_rules! atom_extract_knowledge {
($protocol_type:ty, $extract_type:ty) => {
impl Extractable<$protocol_type> for $extract_type {
fn extract_knowledge<'a>(
&'a self,
knowledges: &mut Vec<Knowledge<'a, $protocol_type>>,
matcher: Option<<$protocol_type as ProtocolTypes>::Matcher>,
source: &'a Source,
) -> Result<(), Error> {
log::debug!("Extract atom: {}", stringify!($extract_type));
knowledges.push(Knowledge {
source,
matcher,
data: self,
});
Ok(())
}
}
};
}