use db_objects::{Contest, Task, Taskgroup}; use serde_yaml; #[derive(Debug, Deserialize)] struct ContestYaml { name: Option, participation_start: Option, participation_end: Option, duration_minutes: Option, public_listing: Option, tasks: Option, } // The task path is stored relatively to the contest.yaml for easier identificationy // Concatenation happens in functions::show_task pub fn parse_yaml(content: &str, filename: &str, directory: &str) -> Option { let config: ContestYaml = serde_yaml::from_str(&content).unwrap(); let mut contest = Contest::new(directory.to_string(), filename.to_string(), config.name?, config.duration_minutes?, config.public_listing.unwrap_or(false), None, None); for (name, info) in config.tasks? { if let serde_yaml::Value::String(name) = name { let mut taskgroup = Taskgroup::new(name); match info { serde_yaml::Value::String(taskdir) => { let task = Task::new(taskdir, 3); taskgroup.tasks.push(task); } serde_yaml::Value::Sequence(taskdirs) => { let mut stars = 2; for taskdir in taskdirs { if let serde_yaml::Value::String(taskdir) = taskdir { let task = Task::new(taskdir, stars); taskgroup.tasks.push(task); } else { panic!("Invalid contest YAML: {}{} (a)", directory, filename) } stars += 1; } } serde_yaml::Value::Mapping(taskdirs) => { let mut stars = 2; for (taskdir, taskinfo) in taskdirs { if let (serde_yaml::Value::String(taskdir), serde_yaml::Value::Mapping(taskinfo)) = (taskdir, taskinfo) { if let Some(serde_yaml::Value::Number(cstars)) = taskinfo.get(&serde_yaml::Value::String("stars".to_string())) { stars = cstars.as_u64().unwrap() as i8; } let task = Task::new(taskdir, stars); taskgroup.tasks.push(task); stars += 1; } else { panic!("Invalid contest YAML: {}{} (b)", directory, filename) } } } _ => panic!("Invalid contest YAML: {}{} (c)", directory, filename), } contest.taskgroups.push(taskgroup); } else { panic!("Invalid contest YAML: {}{} (d)", directory, filename) } } Some(contest) }