agent_coordinate/
agent_coordinate.rs1crate::ix!();
3
4#[derive(Clone, Debug, Getters, Builder)]
5#[builder(setter(into, strip_option), default)]
6#[getset(get = "pub")]
7pub struct AgentCoordinate {
8 location: Option<String>,
9 goal: Option<String>,
10}
11
12impl Default for AgentCoordinate {
13 fn default() -> Self {
14 info!("Creating default AgentCoordinate (nowhere_with_no_goal).");
15 Self::nowhere_with_no_goal()
16 }
17}
18
19impl AgentCoordinate {
20
21 pub fn here_without_a_goal(location: &str) -> Self {
22 info!("Creating AgentCoordinate with location='{location}' and no goal.");
23 Self {
24 location: Some(location.to_string()),
25 goal: None,
26 }
27 }
28
29 pub fn here_with_a_goal(location: &str, goal: &str) -> Self {
30 info!("Creating AgentCoordinate with location='{location}' and goal='{goal}'.");
31 Self {
32 location: Some(location.to_string()),
33 goal: Some(goal.to_string()),
34 }
35 }
36
37 pub fn nowhere_with_no_goal() -> Self {
38 info!("Creating AgentCoordinate with no location and no goal.");
39 Self {
40 location: None,
41 goal: None,
42 }
43 }
44
45 pub fn nowhere_with_a_goal(goal: &str) -> Self {
46 info!("Creating AgentCoordinate with no location and goal='{goal}'.");
47 Self {
48 location: None,
49 goal: Some(goal.to_string()),
50 }
51 }
52
53 pub fn has_location(&self) -> bool {
54 let has_loc = self.location.is_some();
55 debug!("Checking if AgentCoordinate has a location: {has_loc}");
56 has_loc
57 }
58
59 pub fn has_goal(&self) -> bool {
60 let has_g = self.goal.is_some();
61 debug!("Checking if AgentCoordinate has a goal: {has_g}");
62 has_g
63 }
64
65 pub fn is_fully_specified(&self) -> bool {
66 let fully = self.has_location() && self.has_goal();
67 trace!("Checking if AgentCoordinate is fully specified: {fully}");
68 fully
69 }
70
71 pub fn set_location(&mut self, loc: Option<&str>) {
72 if self.location.is_some() {
73 warn!("Overwriting existing location with '{loc:?}'");
74 }
75 self.location = loc.map(|x| x.to_string());
76 }
77
78 pub fn set_goal(&mut self, g: Option<&str>) {
79 if self.goal.is_some() {
80 warn!("Overwriting existing goal with '{g:?}'");
81 }
82 self.goal = g.map(|x| x.to_string());
83 }
84}
85
86impl std::fmt::Display for AgentCoordinate {
87 fn fmt(&self, out: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88 debug!("Formatting AgentCoordinate for display.");
89
90 if self.location.is_none() && self.goal.is_none() {
91 debug!("No location and no goal specified.");
92 return write!(
93 out,
94 "Neither your goal nor your location are specified by the user."
95 );
96 }
97
98 let mut x = String::new();
99
100 if let Some(place) = &self.location {
101 debug!("Appending location='{place}' to display output.");
102 x.push_str(&format!("You are here: {place}. "));
103 }
104
105 if let Some(g) = &self.goal {
106 debug!("Appending goal='{g}' to display output.");
107 x.push_str(&format!("Goal: {g}."));
108 }
109
110 write!(out, "{x}")
111 }
112}
113
114#[cfg(test)]
115mod agent_coordinate_functionality_tests {
116 use super::*;
117
118 #[traced_test]
119 fn test_here_without_a_goal() {
120 let coord = AgentCoordinate::here_without_a_goal("Kitchen");
121 assert!(coord.has_location());
122 assert!(!coord.has_goal());
123 pretty_assert_eq!(*coord.location(), Some("Kitchen".to_string()));
124 info!("test_here_without_a_goal passed.");
125 }
126
127 #[traced_test]
128 fn test_here_with_a_goal() {
129 let coord = AgentCoordinate::here_with_a_goal("Office", "Finish report");
130 assert!(coord.has_location());
131 assert!(coord.has_goal());
132 pretty_assert_eq!(*coord.location(), Some("Office".to_string()));
133 pretty_assert_eq!(*coord.goal(), Some("Finish report".to_string()));
134 info!("test_here_with_a_goal passed.");
135 }
136
137 #[traced_test]
138 fn test_nowhere_with_no_goal() {
139 let coord = AgentCoordinate::nowhere_with_no_goal();
140 assert!(!coord.has_location());
141 assert!(!coord.has_goal());
142 info!("test_nowhere_with_no_goal passed.");
143 }
144
145 #[traced_test]
146 fn test_nowhere_with_a_goal() {
147 let coord = AgentCoordinate::nowhere_with_a_goal("Become world champion");
148 assert!(!coord.has_location());
149 assert!(coord.has_goal());
150 pretty_assert_eq!(*coord.goal(), Some("Become world champion".to_string()));
151 info!("test_nowhere_with_a_goal passed.");
152 }
153
154 #[traced_test]
155 fn test_set_location_and_goal() {
156 let mut coord = AgentCoordinate::nowhere_with_no_goal();
157 coord.set_location(Some("Library"));
158 coord.set_goal(Some("Read more books"));
159 pretty_assert_eq!(*coord.location(), Some("Library".to_string()));
160 pretty_assert_eq!(*coord.goal(), Some("Read more books".to_string()));
161 info!("test_set_location_and_goal passed.");
162 }
163
164 #[traced_test]
165 fn test_is_fully_specified() {
166 let coord1 = AgentCoordinate::here_without_a_goal("Dorm");
167 let coord2 = AgentCoordinate::here_with_a_goal("Gym", "Workout");
168 assert!(!coord1.is_fully_specified());
169 assert!(coord2.is_fully_specified());
170 info!("test_is_fully_specified passed.");
171 }
172
173 #[traced_test]
174 fn test_display() {
175 let coord = AgentCoordinate::here_with_a_goal("Park", "Jog around");
176 let out = format!("{}", coord);
177 assert!(out.contains("Park"));
178 assert!(out.contains("Jog around"));
179 info!("test_display passed.");
180 }
181
182 #[traced_test]
183 fn test_builder_usage() {
184 let coord = AgentCoordinateBuilder::default()
185 .location("School")
186 .goal("Attend class")
187 .build()
188 .expect("Failed to build AgentCoordinate using builder.");
189 pretty_assert_eq!(*coord.location(), Some("School".to_string()));
190 pretty_assert_eq!(*coord.goal(), Some("Attend class".to_string()));
191 info!("test_builder_usage passed.");
192 }
193}