swarm_engine_eval/
environment.rs1use swarm_engine_core::environment::{DefaultEnvironment, EnvironmentBox};
23
24use crate::environments::{MazeEnvironment, NoneEnvironment};
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32pub enum EnvironmentType {
33 None,
35 Maze,
37 Codebase,
39}
40
41impl EnvironmentType {
42 pub fn parse(s: &str) -> Option<Self> {
44 match s.to_lowercase().as_str() {
45 "none" | "" => Some(Self::None),
46 "maze" => Some(Self::Maze),
47 "codebase" | "default" => Some(Self::Codebase),
48 _ => None,
49 }
50 }
51
52 pub fn as_str(&self) -> &'static str {
54 match self {
55 Self::None => "none",
56 Self::Maze => "maze",
57 Self::Codebase => "codebase",
58 }
59 }
60}
61
62pub struct EnvironmentRegistry;
70
71impl EnvironmentRegistry {
72 pub fn create(
83 env_type: &str,
84 params: &serde_json::Value,
85 ) -> Result<EnvironmentBox, EnvironmentError> {
86 let env_type = EnvironmentType::parse(env_type)
87 .ok_or_else(|| EnvironmentError::UnknownType(env_type.to_string()))?;
88
89 match env_type {
90 EnvironmentType::None => Ok(Box::new(NoneEnvironment)),
91
92 EnvironmentType::Maze => {
93 let map_str = params.get("map").and_then(|v| v.as_str()).ok_or_else(|| {
94 EnvironmentError::Config("Maze environment requires 'map' parameter".into())
95 })?;
96
97 let worker_count = params
98 .get("worker_count")
99 .and_then(|v| v.as_u64())
100 .unwrap_or(1) as usize;
101
102 Ok(Box::new(MazeEnvironment::from_str(map_str, worker_count)))
103 }
104
105 EnvironmentType::Codebase => Ok(Box::new(DefaultEnvironment::new())),
106 }
107 }
108
109 pub fn supported_types() -> Vec<EnvironmentType> {
111 vec![
112 EnvironmentType::None,
113 EnvironmentType::Maze,
114 EnvironmentType::Codebase,
115 ]
116 }
117}
118
119#[derive(Debug, Clone)]
125pub enum EnvironmentError {
126 UnknownType(String),
128 Config(String),
130}
131
132impl std::fmt::Display for EnvironmentError {
133 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
134 match self {
135 Self::UnknownType(t) => write!(f, "Unknown environment type: {}", t),
136 Self::Config(e) => write!(f, "Environment config error: {}", e),
137 }
138 }
139}
140
141impl std::error::Error for EnvironmentError {}
142
143#[cfg(test)]
148mod tests {
149 use super::*;
150
151 #[test]
152 fn test_environment_type_from_str() {
153 assert_eq!(EnvironmentType::parse("none"), Some(EnvironmentType::None));
154 assert_eq!(EnvironmentType::parse("maze"), Some(EnvironmentType::Maze));
155 assert_eq!(
156 EnvironmentType::parse("codebase"),
157 Some(EnvironmentType::Codebase)
158 );
159 assert_eq!(EnvironmentType::parse("unknown"), None);
160 }
161
162 #[test]
163 fn test_create_none_environment() {
164 let env = EnvironmentRegistry::create("none", &serde_json::Value::Null);
165 assert!(env.is_ok());
166 assert_eq!(env.unwrap().name(), "NoneEnvironment");
167 }
168
169 #[test]
170 fn test_create_codebase_environment() {
171 let env = EnvironmentRegistry::create("codebase", &serde_json::Value::Null);
172 assert!(env.is_ok());
173 assert_eq!(env.unwrap().name(), "DefaultEnvironment");
174 }
175
176 #[test]
177 fn test_create_maze_environment() {
178 let params = serde_json::json!({
179 "map": "#####\n#S.G#\n#####",
180 "worker_count": 1
181 });
182 let env = EnvironmentRegistry::create("maze", ¶ms);
183 assert!(env.is_ok());
184 assert_eq!(env.unwrap().name(), "MazeEnvironment");
185 }
186
187 #[test]
188 fn test_create_maze_without_map() {
189 let env = EnvironmentRegistry::create("maze", &serde_json::Value::Null);
190 assert!(env.is_err());
191 }
192}