corewars_core/load_file/
metadata.rs

1//! Metadata about a Redcode program. Most of this is not used for execution,
2//! with some exceptions, namely `;redcode` and `;assertion`
3
4use std::fmt;
5
6/// Metadata about a Redcode program that is stored in the comments.
7#[derive(Debug, Default, PartialEq)]
8pub struct Metadata {
9    /// The Redcode standard for this warrior (e.g. "94").
10    // TODO #38 handle directives like `redcode-94` etc.
11    pub redcode: Option<String>,
12
13    /// The name of this warrior.
14    pub name: Option<String>,
15
16    /// The author of this warrior.
17    pub author: Option<String>,
18
19    /// The date when this warrior was written.
20    pub date: Option<String>,
21
22    /// The version of this warrior.
23    pub version: Option<String>,
24
25    /// A description of the warrior's strategy
26    // TODO #38 handle multiline strategies
27    pub strategy: Option<String>,
28
29    /// An assertion for this warrior to ensure compilation.
30    pub assertion: Option<String>,
31}
32
33impl Metadata {
34    /// Parse warrior metadata out of a line. Any comments will be removed and
35    /// the resulting string returned, with whitespace trimmed.
36    pub fn parse_line(&mut self, line: &str) -> String {
37        let split_line: Vec<&str> = line.splitn(2, ';').map(|p| p.trim()).collect();
38
39        if split_line.len() > 1 {
40            let split_comment: Vec<&str> = split_line[1].splitn(2, char::is_whitespace).collect();
41            let value = Some(
42                split_comment
43                    .get(1)
44                    .map_or_else(String::new, |s| s.trim().to_owned()),
45            );
46
47            let directive = split_comment[0].to_lowercase();
48            match directive.as_ref() {
49                "redcode" => self.redcode = value,
50                "name" => self.name = value,
51                "author" => self.author = value,
52                "date" => self.date = value,
53                "version" => self.version = value,
54                "strategy" => self.strategy = value,
55                "assert" => self.assertion = value,
56                _ => (),
57            }
58        }
59
60        split_line[0].trim().to_string()
61    }
62}
63
64impl fmt::Display for Metadata {
65    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
66        for (field, name) in &[
67            (&self.redcode, "redcode"),
68            (&self.name, "name"),
69            (&self.author, "author"),
70            (&self.version, "version"),
71            (&self.date, "date"),
72            (&self.strategy, "strategy"),
73            (&self.assertion, "assert"),
74        ] {
75            if let Some(value) = field.as_deref() {
76                if value.is_empty() {
77                    writeln!(formatter, ";{}", name)?;
78                } else {
79                    writeln!(formatter, ";{} {}", name, value)?;
80                }
81            }
82        }
83        Ok(())
84    }
85}
86
87// TODO as part of #38 test parse_line