1use crate::error::{Error, Result};
5use crate::ethic::Ethics;
6use crate::resources::Resources;
7use crate::resources::influence::Influence;
8use derive_more::{Display, From, Into};
9use serde::{Deserialize, Serialize};
10use std::borrow::{Borrow, Cow};
11use std::collections::HashMap;
12use std::ops::Deref;
13use std::sync::Arc;
14
15#[derive(Clone, Debug, Default, Deserialize, Serialize)]
16#[serde(rename_all = "camelCase")]
17pub struct BotManager(HashMap<BotId, Bot>);
18
19impl BotManager {
20 pub(crate) fn manage(&mut self, id: BotId) -> Result<()> {
21 if self.0.contains_key(&id) {
22 return Err(Error::BotAlreadySpawned(id));
23 }
24
25 self.0.insert(id.clone(), Bot::new(id));
26
27 Ok(())
28 }
29
30 pub fn bot(&self, id: &BotId) -> Result<&Bot> {
31 self
32 .0
33 .get(id)
34 .ok_or_else(|| Error::BotNotFound(id.clone()))
35 }
36
37 pub(crate) fn bot_mut(&mut self, id: &BotId) -> Result<&mut Bot> {
38 self
39 .0
40 .get_mut(id)
41 .ok_or_else(|| Error::BotNotFound(id.clone()))
42 }
43
44 pub fn bots(&self) -> impl Iterator<Item = &Bot> {
45 self.0.values()
46 }
47}
48
49#[derive(Clone, Debug, Deserialize, Serialize)]
50#[serde(rename_all = "camelCase")]
51#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
52pub struct Bot {
53 id: BotId,
54 ethics: Ethics,
55 resources: Resources,
56 influence: Influence,
57}
58
59impl Bot {
60 pub(crate) fn new(id: BotId) -> Self {
61 Self {
62 id,
63 ethics: Ethics::random(),
64 resources: Resources::BOT.clone(),
65 influence: Influence::MIN,
66 }
67 }
68
69 #[inline]
70 pub fn id(&self) -> BotId {
71 self.id.clone()
72 }
73
74 #[inline]
75 pub fn ethics(&self) -> &Ethics {
76 &self.ethics
77 }
78
79 #[inline]
80 pub(crate) fn ethics_mut(&mut self) -> &mut Ethics {
81 &mut self.ethics
82 }
83
84 #[inline]
85 pub fn resources(&self) -> &Resources {
86 &self.resources
87 }
88
89 pub(crate) fn resources_mut(&mut self) -> &mut Resources {
90 &mut self.resources
91 }
92
93 #[inline]
94 pub fn influence(&self) -> Influence {
95 self.influence
96 }
97}
98
99#[derive(Debug, Display, PartialEq, Eq, Hash, From, Into, Deserialize, Serialize)]
100#[from(String, &str, Arc<str>, Box<str>, Cow<'_, str>)]
101#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
102pub struct BotId(Arc<str>);
103
104impl Clone for BotId {
105 fn clone(&self) -> Self {
106 Self(Arc::clone(&self.0))
107 }
108}
109
110impl AsRef<str> for BotId {
111 fn as_ref(&self) -> &str {
112 self.0.as_str()
113 }
114}
115
116impl Deref for BotId {
117 type Target = str;
118
119 fn deref(&self) -> &Self::Target {
120 self.0.as_str()
121 }
122}
123
124impl Borrow<str> for BotId {
125 fn borrow(&self) -> &str {
126 self.0.as_str()
127 }
128}
129
130impl From<BotId> for String {
131 fn from(value: BotId) -> Self {
132 String::from(value.0.as_ref())
133 }
134}
135
136#[derive(Clone, Debug, Deserialize, Serialize)]
137#[serde(rename_all = "camelCase")]
138#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
139pub struct PublicBot {
140 id: BotId,
141}
142
143impl From<&Bot> for PublicBot {
144 fn from(bot: &Bot) -> Self {
145 Self { id: bot.id.clone() }
146 }
147}