use crate::agent::traits::{Agent, AgentSet, RecordedAgent, RecordedAgentSet};
use crate::contract::Transaction;
use crate::env::{Env, Validator};
use crate::DB;
use alloy_primitives::Address;
use rand::RngCore;
use std::mem;
pub struct AgentVec<R, A: Agent + RecordedAgent<R>> {
agents: Vec<A>,
records: Vec<Vec<R>>,
}
impl<R, A: Agent + RecordedAgent<R>> Default for AgentVec<R, A> {
fn default() -> Self {
AgentVec {
agents: Vec::<A>::new(),
records: Vec::<Vec<R>>::new(),
}
}
}
impl<R, A: Agent + RecordedAgent<R>> AgentVec<R, A> {
pub fn new() -> Self {
AgentVec {
agents: Vec::<A>::new(),
records: Vec::<Vec<R>>::new(),
}
}
pub fn from(agents: Vec<A>) -> Self {
AgentVec {
agents,
records: Vec::<Vec<R>>::new(),
}
}
pub fn add_agent(&mut self, agent: A) {
self.agents.push(agent);
}
pub fn get_records(&self) -> &Vec<Vec<R>> {
&self.records
}
}
impl<R, A: Agent + RecordedAgent<R>> RecordedAgentSet<R> for AgentVec<R, A> {
fn take_records(&mut self) -> Vec<Vec<R>> {
mem::take(&mut self.records)
}
}
impl<R: 'static, A: Agent + RecordedAgent<R> + 'static> AgentSet for AgentVec<R, A> {
fn call<D: DB, V: Validator, RG: RngCore>(
&mut self,
rng: &mut RG,
network: &mut Env<D, V>,
) -> Vec<Transaction> {
self.agents
.iter_mut()
.flat_map(|x| x.update(rng, network))
.collect()
}
fn record<D: DB, V: Validator>(&mut self, env: &mut Env<D, V>) {
let records: Vec<R> = self.agents.iter_mut().map(|x| x.record(env)).collect();
self.records.push(records);
}
fn get_addresses(&self) -> Vec<Address> {
self.agents.iter().map(|x| x.get_address()).collect()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::LocalDB;
use crate::{agent::traits, env::RandomValidator};
use alloy_primitives::{Uint, U256};
use rand::SeedableRng;
use rstest::*;
struct TestAgent {
address: Address,
value: u64,
}
impl traits::Agent for TestAgent {
fn update<D: DB, V: Validator, RG: RngCore>(
&mut self,
_rng: &mut RG,
_network: &mut crate::env::Env<D, V>,
) -> Vec<crate::contract::Transaction> {
self.value += 1;
vec![
Transaction {
function_selector: [0, 0, 0, 0],
callee: Address::ZERO,
transact_to: Address::ZERO,
args: Vec::default(),
value: U256::ZERO,
checked: false,
gas_priority_fee: None,
nonce: None,
},
Transaction {
function_selector: [0, 0, 0, 0],
callee: Address::ZERO,
transact_to: Address::ZERO,
args: Vec::default(),
value: U256::ZERO,
checked: false,
gas_priority_fee: None,
nonce: None,
},
]
}
fn get_address(&self) -> Address {
self.address
}
}
impl traits::RecordedAgent<u64> for TestAgent {
fn record<D: DB, V: Validator>(&mut self, _env: &mut Env<D, V>) -> u64 {
self.value
}
}
#[fixture]
fn env() -> Env<LocalDB, RandomValidator> {
Env::<LocalDB, RandomValidator>::init(U256::ZERO, U256::ZERO, RandomValidator {})
}
#[fixture]
fn rng() -> rand_xoshiro::Xoroshiro128StarStar {
rand_xoshiro::Xoroshiro128StarStar::seed_from_u64(101)
}
#[rstest]
fn test_agent_vec(
mut env: Env<LocalDB, RandomValidator>,
mut rng: rand_xoshiro::Xoroshiro128StarStar,
) {
let a = Address::from(Uint::from(101u128));
let b = Address::from(Uint::from(202u128));
let agents = vec![
TestAgent {
address: a,
value: 0,
},
TestAgent {
address: b,
value: 1,
},
];
let mut agent_vec = AgentVec::from(agents);
assert_eq!(agent_vec.get_addresses(), vec![a, b]);
agent_vec.record(&mut env);
assert_eq!(agent_vec.records.len(), 1);
let calls = agent_vec.call(&mut rng, &mut env);
assert_eq!(calls.len(), 4);
agent_vec.record(&mut env);
assert_eq!(agent_vec.records.len(), 2);
let records = agent_vec.take_records();
assert_eq!(records[0], vec![0, 1]);
assert_eq!(records[1], vec![1, 2]);
}
}