use serde::{Deserialize, Serialize};
mod element {
use std::{fmt, str::FromStr};
use serde::{
de::Deserializer,
ser::{SerializeMap, Serializer},
Deserialize, Serialize,
};
#[derive(Serialize, Deserialize)]
struct Element<T> {
#[serde(rename = "$value")]
value: T,
}
pub fn deserialize<'de, D: Deserializer<'de>, T: FromStr>(
deserializer: D,
) -> Result<T, D::Error>
where
T::Err: fmt::Display,
{
Element::<String>::deserialize(deserializer).and_then(|e| {
e.value
.parse()
.map_err(|e: T::Err| <D::Error as serde::de::Error>::custom(e.to_string()))
})
}
pub fn serialize<S: Serializer, T: Serialize>(
value: &T,
serializer: S,
) -> Result<S::Ok, S::Error> {
let mut map = serializer.serialize_map(Some(1))?;
map.serialize_entry("$value", value)?;
map.end()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Behavior {
version: String,
#[serde(with = "element", rename = "Name")]
name: String,
#[serde(rename = "CompoundAction")]
actions: Vec<CompoundAction>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CompoundAction {
#[serde(rename = "Action")]
pub actions: Vec<Action>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "Type", rename_all = "PascalCase")]
pub enum Action {
OnAttack,
OnEnterProximity {
#[serde(with = "element", rename = "Distance")]
distance: f32,
},
OnChat {
#[serde(with = "element", rename = "Message")]
message: String,
},
PlaySound {
#[serde(with = "element")]
sound: String,
},
Chat {
#[serde(with = "element", rename = "Message")]
message: String,
},
Smash {
#[serde(with = "element", rename = "Opacity")]
opacity: f32,
#[serde(with = "element")]
force: f32,
},
Wait {
#[serde(with = "element", rename = "Delay")]
delay: f32,
},
UnSmash {
#[serde(with = "element", rename = "Duration")]
duration: f32,
},
MoveToInteractor {
#[serde(with = "element", rename = "Distance")]
distance: f32,
},
}
#[cfg(test)]
mod tests {
use super::Behavior;
#[test]
fn test_deserialize() {
let text = include_str!("../test/Droid.xml");
let _data: Behavior = quick_xml::de::from_str(text).unwrap();
}
}