1use std::str;
4
5use quick_xml::events::BytesStart;
6use serde::Serialize;
7
8use error::Error;
9use crate::xml;
10
11#[derive(Clone, Serialize, PartialEq)]
13#[cfg_attr(test, derive(Debug))]
14pub enum Parent
15{
16 Family(String),
19 Monster(String),
21}
22
23#[derive(Clone, Serialize)]
25#[cfg_attr(test, derive(Debug, PartialEq))]
26pub struct ParentRequirement
27{
28 pub parent: Parent,
30 pub min_plus: u8,
34}
35
36impl ParentRequirement
37{
38 fn fromXMLTag(e: &BytesStart) -> Result<Self, Error>
39 {
40 let min_plus = if let Some(attr) = e.try_get_attribute("min_plus")
41 .map_err(|_| xmlerr!("Failed to get attribute 'min_plus'."))?
42 {
43 str::from_utf8(attr.value.as_ref()).map_err(
44 |_| xmlerr!("Failed to decode min +level in XML"))?.parse()
45 .map_err(|_| xmlerr!("Invalid min +level in XML"))?
46 }
47 else
48 {
49 0
50 };
51
52 if let Some(attr) = e.try_get_attribute("monster").map_err(
53 |_| xmlerr!("Failed to get attribute 'monster'."))?
54 {
55 let monster = String::from_utf8(attr.value.into_owned()).map_err(
56 |_| xmlerr!("Failed to decode monster name in XML"))?;
57 Ok(Self {
58 parent: Parent::Monster(monster),
59 min_plus
60 })
61 }
62 else if let Some(attr) = e.try_get_attribute("family").map_err(
63 |_| xmlerr!("Failed to get attribute 'family'."))?
64 {
65 let family = String::from_utf8(attr.value.into_owned()).map_err(
66 |_| xmlerr!("Failed to decode family name in XML"))?;
67 Ok(Self {
68 parent: Parent::Family(family),
69 min_plus
70 })
71 }
72 else
73 {
74 Err(xmlerr!("Invalid parent definition in XML"))
75 }
76 }
77}
78
79#[derive(Clone, Serialize)]
81#[cfg_attr(test, derive(Debug, PartialEq))]
82pub struct Formula
83{
84 pub base: Vec<ParentRequirement>,
86 pub mate: Vec<ParentRequirement>,
88 pub offspring: String,
90}
91
92impl Formula
93{
94 pub fn fromXML(x: &[u8]) -> Result<Self, Error>
95 {
96 let mut offspring = String::new();
97 let mut base = Vec::new();
98 let mut mate = Vec::new();
99 let mut parser = xml::Parser::new();
100
101 parser.addBeginHandler("breed", |_, e: &BytesStart| {
102 if let Some(attr) = e.try_get_attribute("target").map_err(
103 |_| xmlerr!("Failed to get attribute 'target'."))?
104 {
105 offspring = String::from_utf8(attr.value.into_owned()).map_err(
106 |_| xmlerr!("Failed to decode breed target name in XML"))?;
107 Ok(())
108 }
109 else
110 {
111 Err(xmlerr!("Found breed formula without target"))
112 }
113 });
114
115 parser.addBeginHandler("breed-requirement", |path, e: &BytesStart| {
116 if let Some(tag) = path.get(path.len() - 2)
117 {
118 match tag.as_str()
119 {
120 "base" => base.push(ParentRequirement::fromXMLTag(e)?),
121 "mate" => mate.push(ParentRequirement::fromXMLTag(e)?),
122 _ => return Err(xmlerr!("Invalid tag '{}'", tag)),
123 }
124 }
125 else
126 {
127 return Err(xmlerr!("Invalid breed requirement"));
128 }
129 Ok(())
130 });
131 parser.parse(x)?;
132 drop(parser);
133 let result = Self { base, mate, offspring };
134 Ok(result)
135 }
136}
137
138#[cfg(test)]
141mod tests {
142 use super::*;
143
144 use anyhow::Result;
145
146 #[test]
147 fn deserializeFormula() -> Result<()>
148 {
149 let xml = r#"<breed target="KingSlime">
150 <base>
151 <breed-requirement monster="SpotKing"/>
152 </base>
153 <mate>
154 <breed-requirement monster="DeadNoble"/>
155 <breed-requirement monster="Divinegon"/>
156 <breed-requirement monster="Gigantes"/>
157 </mate>
158 </breed>"#;
159 let p = Formula::fromXML(xml.as_bytes())?;
160 assert_eq!(
161 p,
162 Formula {
163 base: vec![ParentRequirement{ parent: Parent::Monster("SpotKing".to_owned()), min_plus: 0 }],
164 mate: vec![ParentRequirement{ parent: Parent::Monster("DeadNoble".to_owned()), min_plus: 0 },
165 ParentRequirement{ parent: Parent::Monster("Divinegon".to_owned()), min_plus: 0 },
166 ParentRequirement{ parent: Parent::Monster("Gigantes".to_owned()), min_plus: 0},],
167 offspring: "KingSlime".to_owned(),
168 });
169
170 let xml = r#"<breed target="Octogon">
171 <base>
172 <breed-requirement monster="Octoreach"/>
173 </base>
174 <mate>
175 <breed-requirement monster="Octoreach" min_plus="4"/>
176 </mate>
177 </breed>"#;
178 let p = Formula::fromXML(xml.as_bytes())?;
179 assert_eq!(
180 p,
181 Formula {
182 base: vec![ParentRequirement{ parent: Parent::Monster("Octoreach".to_owned()), min_plus: 0 }],
183 mate: vec![ParentRequirement{ parent: Parent::Monster("Octoreach".to_owned()), min_plus: 4 }],
184 offspring: "Octogon".to_owned(),
185 });
186
187 let xml = r#"<breed target="Moray">
188 <base>
189 <breed-requirement family="water"/>
190 </base>
191 <mate>
192 <breed-requirement family="dragon"/>
193 </mate>
194 </breed>"#;
195 let p = Formula::fromXML(xml.as_bytes())?;
196 assert_eq!(
197 p,
198 Formula {
199 base: vec![ParentRequirement{ parent: Parent::Family("water".to_owned()), min_plus: 0 }],
200 mate: vec![ParentRequirement{ parent: Parent::Family("dragon".to_owned()), min_plus: 0 }],
201 offspring: "Moray".to_owned(),
202 });
203
204 Ok(())
205 }
206}