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