use core::fmt;
use std::fmt::Debug;
use std::hash::Hash;
use serde::{Deserialize, Serialize};
use crate::algebra::ConcreteMessage;
use crate::error::Error;
use crate::protocol::{ProtocolBehavior, ProtocolTypes};
use crate::put::Put;
use crate::stream::Stream;
#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct AgentName(u8);
impl AgentName {
#[must_use]
pub const fn new() -> Self {
const FIRST: AgentName = AgentName(0u8);
FIRST
}
#[must_use]
pub const fn next(&self) -> Self {
Self(self.0 + 1)
}
#[must_use]
pub const fn first() -> Self {
Self::new()
}
}
impl Default for AgentName {
fn default() -> Self {
Self::new()
}
}
impl fmt::Display for AgentName {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl From<AgentName> for u8 {
fn from(value: AgentName) -> Self {
value.0
}
}
pub trait ProtocolDescriptorConfig:
Default + Debug + Clone + Serialize + Hash + for<'a> Deserialize<'a>
{
fn is_reusable_with(&self, other: &Self) -> bool;
}
#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq, Hash)]
#[serde(bound = "C: ProtocolDescriptorConfig")]
pub struct AgentDescriptor<C: ProtocolDescriptorConfig> {
pub name: AgentName,
pub protocol_config: C,
}
impl<C: ProtocolDescriptorConfig> AgentDescriptor<C> {
pub fn from_config(name: AgentName, put_config: C) -> Self {
Self {
name,
protocol_config: put_config,
}
}
pub fn from_name(name: AgentName) -> Self {
Self {
name,
protocol_config: C::default(),
}
}
}
impl<C: ProtocolDescriptorConfig> Default for AgentDescriptor<C> {
fn default() -> Self {
Self {
name: AgentName::first(),
protocol_config: C::default(),
}
}
}
pub struct Agent<PB: ProtocolBehavior> {
descriptor:
AgentDescriptor<<<PB as ProtocolBehavior>::ProtocolTypes as ProtocolTypes>::PUTConfig>,
put: Box<dyn Put<PB>>,
}
impl<PB: ProtocolBehavior> fmt::Debug for Agent<PB> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Agent")
.field("descriptor", &self.descriptor)
.field("put", &self.put.describe_state())
.finish()
}
}
impl<PB: ProtocolBehavior> PartialEq for Agent<PB> {
fn eq(&self, other: &Self) -> bool {
self.descriptor.name.eq(&other.descriptor.name)
&& self.put.describe_state() == other.put.describe_state()
}
}
impl<PB: ProtocolBehavior> Agent<PB> {
#[must_use]
pub fn new(
descriptor: AgentDescriptor<<PB::ProtocolTypes as ProtocolTypes>::PUTConfig>,
put: Box<dyn Put<PB>>,
) -> Self {
Self { descriptor, put }
}
pub fn progress(&mut self) -> Result<(), Error> {
self.put.progress()
}
pub fn reset(&mut self, new_name: AgentName) -> Result<(), Error> {
self.descriptor.name = new_name;
self.put.reset(new_name)
}
pub fn shutdown(&mut self) -> String {
self.put.shutdown()
}
#[must_use]
pub fn is_state_successful(&self) -> bool {
self.put.is_state_successful()
}
#[must_use]
pub fn is_reusable_with(
&self,
other: &AgentDescriptor<<PB::ProtocolTypes as ProtocolTypes>::PUTConfig>,
) -> bool {
self.descriptor
.protocol_config
.is_reusable_with(&other.protocol_config)
}
#[must_use]
pub const fn name(&self) -> AgentName {
self.descriptor.name
}
#[must_use]
pub fn put(&self) -> &dyn Put<PB> {
self.put.as_ref()
}
pub fn put_mut(&mut self) -> &mut dyn Put<PB> {
self.put.as_mut()
}
}
impl<PB: ProtocolBehavior> Stream<PB> for Agent<PB> {
fn add_to_inbound(&mut self, message: &ConcreteMessage) {
self.put.add_to_inbound(message);
}
fn take_message_from_outbound(
&mut self,
) -> Result<Option<PB::OpaqueProtocolMessageFlight>, Error> {
self.put.take_message_from_outbound()
}
}