use std::fmt::{self, Debug};
use std::hash::Hash;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
pub trait AgentId: Clone + Debug + Eq + Hash + Send + Sync + 'static {}
impl<T> AgentId for T where T: Clone + Debug + Eq + Hash + Send + Sync + 'static {}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(bound = "ID: Serialize + for<'de2> Deserialize<'de2>"))]
pub enum Agent<ID: AgentId> {
Human(ID),
Bot(ID),
System,
}
impl<ID: AgentId> Agent<ID> {
pub fn new_human(id: ID) -> Self {
Agent::Human(id)
}
pub fn new_bot(id: ID) -> Self {
Agent::Bot(id)
}
pub fn system() -> Self {
Agent::System
}
pub fn id(&self) -> Option<&ID> {
match self {
Agent::Human(id) | Agent::Bot(id) => Some(id),
Agent::System => None,
}
}
pub fn id_cloned(&self) -> Option<ID> {
self.id().cloned()
}
pub fn is_system(&self) -> bool {
matches!(self, Agent::System)
}
}
impl<ID: AgentId> fmt::Display for Agent<ID> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Agent::Human(id) => write!(f, "human:{id:?}"),
Agent::Bot(id) => write!(f, "bot:{id:?}"),
Agent::System => f.write_str("SYSTEM"),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::hash_map::DefaultHasher;
use std::hash::Hasher;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
enum TestOp {
Move { x: i32 },
}
fn hash_of<T: Hash>(value: &T) -> u64 {
let mut hasher = DefaultHasher::new();
value.hash(&mut hasher);
hasher.finish()
}
#[test]
fn agents_compare_and_hash_by_identity_alone() {
let one = Agent::new_human(7u32);
let same = Agent::new_human(7u32);
assert_eq!(one, same);
assert_eq!(hash_of(&one), hash_of(&same));
assert_ne!(one, Agent::new_bot(7u32), "kind still distinguishes");
}
#[test]
fn the_system_agent_has_no_id_and_still_names_itself() {
let system: Agent<u32> = Agent::system();
assert_eq!(system.id(), None);
assert_eq!(system.to_string(), "SYSTEM");
assert_eq!(Agent::new_human(7u32).to_string(), "human:7");
assert!(system.is_system());
}
}