--- a/rust/hedgewars-server/src/server/demo.rs Tue May 19 02:25:24 2020 +0300
+++ b/rust/hedgewars-server/src/server/demo.rs Tue May 19 19:26:48 2020 +0300
@@ -1,5 +1,7 @@
-use crate::core::types::{GameCfg, TeamInfo};
-
+use crate::{
+ core::types::{GameCfg, HedgehogInfo, TeamInfo},
+ server::haskell::HaskellValue,
+};
use std::{
fs,
io::{self, BufReader, Read, Write},
@@ -17,14 +19,25 @@
Ok(unimplemented!())
}
- fn load(file: String) -> io::Result<Self> {
- let value = super::haskell::parse(&[]);
- Ok(unimplemented!())
+ fn load(filename: String) -> io::Result<Self> {
+ let mut file = fs::File::open(filename)?;
+ let mut bytes = vec![];
+ file.read_to_end(&mut bytes)?;
+ match super::haskell::parse(&bytes[..]) {
+ Ok((_, value)) => haskell_to_demo(value).ok_or(io::Error::new(
+ io::ErrorKind::InvalidData,
+ "Invalid demo structure",
+ )),
+ Err(_) => Err(io::Error::new(
+ io::ErrorKind::InvalidData,
+ "Unable to parse file",
+ )),
+ }
}
- fn load_hwd(file: String) -> io::Result<Self> {
- let datum = fs::File::open(file)?;
- let mut reader = io::BufReader::new(datum);
+ fn load_hwd(filename: String) -> io::Result<Self> {
+ let file = fs::File::open(filename)?;
+ let mut reader = io::BufReader::new(file);
#[inline]
fn error<T>(cause: &str) -> io::Result<T> {
@@ -254,3 +267,70 @@
})
}
}
+
+fn haskell_to_demo(value: HaskellValue) -> Option<Demo> {
+ use HaskellValue::*;
+ let mut lists = value.into_tuple()?;
+ let mut lists_iter = lists.drain(..);
+
+ let teams_list = lists_iter.next()?.into_list()?;
+ let map_config = lists_iter.next()?.into_list()?;
+ let game_config = lists_iter.next()?.into_list()?;
+ let engine_messages = lists_iter.next()?.into_list()?;
+
+ let mut teams = Vec::with_capacity(teams_list.len());
+
+ for team in teams_list {
+ let (_, mut fields) = team.into_struct()?;
+
+ let mut team_info = TeamInfo::default();
+ for (name, value) in fields.drain() {
+ match &name[..] {
+ "teamowner" => team_info.owner = value.into_string()?,
+ "teamname" => team_info.name = value.into_string()?,
+ "teamcolor" => team_info.color = u8::from_str(&value.into_string()?).ok()?,
+ "teamgrave" => team_info.grave = value.into_string()?,
+ "teamfort" => team_info.fort = value.into_string()?,
+ "teamvoicepack" => team_info.voice_pack = value.into_string()?,
+ "teamflag" => team_info.flag = value.into_string()?,
+ "difficulty" => team_info.difficulty = value.into_number()?,
+ "hhnum" => team_info.hedgehogs_number = value.into_number()?,
+ "hedgehogs" => {
+ for (index, hog) in value
+ .into_list()?
+ .drain(..)
+ .enumerate()
+ .take(team_info.hedgehogs.len())
+ {
+ let (_, mut fields) = hog.into_anon_struct()?;
+ let mut fields_iter = fields.drain(..);
+ team_info.hedgehogs[index] = HedgehogInfo {
+ name: fields_iter.next()?.into_string()?,
+ hat: fields_iter.next()?.into_string()?,
+ }
+ }
+ }
+ _ => (),
+ }
+ }
+ teams.push(team_info)
+ }
+
+ let mut config = Vec::with_capacity(map_config.len() + game_config.len());
+
+ for item in map_config {}
+
+ for item in game_config {}
+
+ let mut messages = Vec::with_capacity(engine_messages.len());
+
+ for message in engine_messages {
+ messages.push(message.into_string()?);
+ }
+
+ Some(Demo {
+ teams,
+ config,
+ messages,
+ })
+}
--- a/rust/hedgewars-server/src/server/haskell.rs Tue May 19 02:25:24 2020 +0300
+++ b/rust/hedgewars-server/src/server/haskell.rs Tue May 19 19:26:48 2020 +0300
@@ -30,6 +30,64 @@
},
}
+impl HaskellValue {
+ pub fn to_number(&self) -> Option<u8> {
+ match self {
+ HaskellValue::Number(value) => Some(*value),
+ _ => None,
+ }
+ }
+
+ pub fn into_number(self) -> Option<u8> {
+ match self {
+ HaskellValue::Number(value) => Some(value),
+ _ => None,
+ }
+ }
+
+ pub fn to_string(&self) -> Option<&str> {
+ match self {
+ HaskellValue::String(value) => Some(value),
+ _ => None,
+ }
+ }
+
+ pub fn into_string(self) -> Option<String> {
+ match self {
+ HaskellValue::String(value) => Some(value),
+ _ => None,
+ }
+ }
+
+ pub fn into_list(self) -> Option<Vec<HaskellValue>> {
+ match self {
+ HaskellValue::List(items) => Some(items),
+ _ => None,
+ }
+ }
+
+ pub fn into_tuple(self) -> Option<Vec<HaskellValue>> {
+ match self {
+ HaskellValue::Tuple(items) => Some(items),
+ _ => None,
+ }
+ }
+
+ pub fn into_anon_struct(self) -> Option<(String, Vec<HaskellValue>)> {
+ match self {
+ HaskellValue::AnonStruct { name, fields } => Some((name, fields)),
+ _ => None,
+ }
+ }
+
+ pub fn into_struct(self) -> Option<(String, HashMap<String, HaskellValue>)> {
+ match self {
+ HaskellValue::Struct { name, fields } => Some((name, fields)),
+ _ => None,
+ }
+ }
+}
+
fn write_sequence(
f: &mut Formatter<'_>,
brackets: &[u8; 2],
@@ -37,7 +95,7 @@
) -> Result<(), Error> {
write!(f, "{}", brackets[0] as char)?;
while let Some(value) = items.next() {
- write!(f, "{}", value);
+ write!(f, "{}", value)?;
if !items.as_slice().is_empty() {
write!(f, ", ")?;
}