agent_coordinate/
agent_coordinate.rs

1// ---------------- [ File: agent-coordinate/src/agent_coordinate.rs ]
2crate::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}