prison_architect_savefile/
lib.rs

1mod format;
2mod parse;
3
4pub use crate::parse::ParseError;
5
6use std::{collections::HashMap, fmt, io, path::Path, vec};
7
8/// Reads a prison architect savefile from the file system.
9pub fn read(path: impl AsRef<Path>) -> io::Result<Node> {
10    Node::read(path)
11}
12
13/// A single element of a savefile.
14#[derive(Default, Clone, PartialEq, Eq)]
15pub struct Node {
16    properties: HashMap<String, Vec<String>>,
17    children: HashMap<String, Vec<Node>>,
18}
19
20impl Node {
21    /// Create a new, empty, node.
22    pub fn new() -> Self {
23        Default::default()
24    }
25
26    /// Parses a node from a string.
27    pub fn parse(input: impl AsRef<str>) -> Result<Self, ParseError> {
28        input.as_ref().parse()
29    }
30
31    /// Reads a savefile from the file system.
32    pub fn read(path: impl AsRef<Path>) -> io::Result<Self> {
33        let input = fs_err::read_to_string(path)?;
34        Node::parse(input).map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))
35    }
36
37    /// Writes a savefile to the file system.
38    pub fn write(&self, path: impl AsRef<Path>) -> io::Result<()> {
39        let output = self.to_string();
40        fs_err::write(path, output)
41    }
42
43    /// Gets an iterator over all key-value properties on this node.
44    pub fn properties(&self) -> impl Iterator<Item = (&str, &str)> {
45        self.properties
46            .iter()
47            .flat_map(|(key, values)| values.iter().map(|value| (key.as_str(), value.as_str())))
48    }
49
50    /// Gets the property value for a given key, if it exists. If multiple values are set, the first is returned.
51    pub fn property(&self, key: impl AsRef<str>) -> Option<&str> {
52        self.properties
53            .get(key.as_ref())
54            .and_then(|value| value.first())
55            .map(|value| value.as_str())
56    }
57
58    /// Returns true if this node contains at least one property with the given key.
59    pub fn has_property(&mut self, key: impl AsRef<str>) -> bool {
60        self.properties
61            .get(key.as_ref())
62            .map_or(false, |values| !values.is_empty())
63    }
64
65    /// Sets the property value for a given key. If a value is already set, it is cleared.
66    pub fn set_property(&mut self, key: impl Into<String>, value: impl Into<String>) {
67        let values = self.properties.entry(key.into()).or_default();
68        values.clear();
69        values.push(value.into());
70    }
71
72    /// Sets an additional property value for a given key. Existing values are kept.
73    pub fn add_property(&mut self, key: impl Into<String>, value: impl Into<String>) {
74        self.properties
75            .entry(key.into())
76            .or_default()
77            .push(value.into())
78    }
79
80    /// Removes all property values for the given key and returns them.
81    pub fn clear_property(&mut self, key: impl AsRef<str>) -> impl Iterator<Item = String> {
82        match self.properties.remove(key.as_ref()) {
83            Some(properties) => properties.into_iter(),
84            None => vec::IntoIter::default(),
85        }
86    }
87
88    /// Removes all property values for this node and returns them.
89    pub fn clear_properties(&mut self) -> impl Iterator<Item = (String, String)> + '_ {
90        self.properties.drain().flat_map(|(key, properties)| {
91            properties
92                .into_iter()
93                .map(move |property| (key.clone(), property))
94        })
95    }
96
97    /// Adds the given key-value properties to this node.
98    pub fn extend_properties<K, V>(&mut self, properties: impl IntoIterator<Item = (K, V)>)
99    where
100        K: Into<String>,
101        V: Into<String>,
102    {
103        for (key, value) in properties {
104            self.properties
105                .entry(key.into())
106                .or_default()
107                .push(value.into())
108        }
109    }
110
111    /// Gets an iterator over all children of this node.
112    pub fn children(&self) -> impl Iterator<Item = (&str, &Node)> {
113        self.children
114            .iter()
115            .flat_map(|(key, children)| children.iter().map(|child| (key.as_str(), child)))
116    }
117
118    /// Gets a mutable iterator over all children of this node.
119    pub fn children_mut(&mut self) -> impl Iterator<Item = (&str, &mut Node)> {
120        self.children
121            .iter_mut()
122            .flat_map(|(key, children)| children.iter_mut().map(|child| (key.as_str(), child)))
123    }
124
125    /// Gets the child for a given key, if it exists. If multiple children exist, the first is returned.
126    pub fn child(&self, key: &str) -> Option<&Node> {
127        self.children.get(key).and_then(|child| child.first())
128    }
129
130    /// Gets a mutable reference to the child for a given key, if it exists. If multiple children exist, the first is returned.
131    pub fn child_mut(&mut self, key: &str) -> Option<&mut Node> {
132        self.children
133            .get_mut(key)
134            .and_then(|child| child.first_mut())
135    }
136
137    /// Returns true if this node contains at least child with the given key.
138    pub fn has_child(&mut self, key: impl AsRef<str>) -> bool {
139        self.children
140            .get(key.as_ref())
141            .map_or(false, |values| !values.is_empty())
142    }
143
144    /// Sets the child value for a given key. If a child is already set, it is cleared.
145    pub fn set_child(&mut self, key: impl Into<String>, child: Node) {
146        let values = self.children.entry(key.into()).or_default();
147        values.clear();
148        values.push(child);
149    }
150
151    /// Sets an additional child value for a given key. Existing children are kept.
152    pub fn add_child(&mut self, key: impl Into<String>, child: Node) {
153        self.children.entry(key.into()).or_default().push(child)
154    }
155
156    /// Removes all children for the given key and returns them.
157    pub fn clear_child(&mut self, key: impl AsRef<str>) -> impl Iterator<Item = Node> {
158        match self.children.remove(key.as_ref()) {
159            Some(children) => children.into_iter(),
160            None => vec::IntoIter::default(),
161        }
162    }
163
164    /// Removes all children for this node and returns them.
165    pub fn clear_children(&mut self) -> impl Iterator<Item = (String, Node)> + '_ {
166        self.children
167            .drain()
168            .flat_map(|(key, children)| children.into_iter().map(move |child| (key.clone(), child)))
169    }
170
171    /// Adds the given children to this node.
172    pub fn extend_children<K>(&mut self, properties: impl IntoIterator<Item = (K, Node)>)
173    where
174        K: Into<String>,
175    {
176        for (key, child) in properties {
177            self.children.entry(key.into()).or_default().push(child)
178        }
179    }
180}
181
182impl fmt::Debug for Node {
183    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184        f.debug_map()
185            .entries(self.properties())
186            .entries(self.children())
187            .finish()
188    }
189}