1use crate::{Angles, Color, LightColor, Negated, Vector};
2use std::num::{ParseFloatError, ParseIntError};
3use std::str::FromStr;
4use thiserror::Error;
5
6pub trait EntityProp<'a>: Sized {
7 fn parse(raw: &'a str) -> Result<Self, EntityParseError>;
8}
9
10pub trait FromStrProp: FromStr {}
12
13impl FromStrProp for u8 {}
14impl FromStrProp for u16 {}
15impl FromStrProp for f32 {}
16impl FromStrProp for u32 {}
17impl FromStrProp for i32 {}
18impl FromStrProp for Color {}
19impl FromStrProp for Angles {}
20impl FromStrProp for Vector {}
21impl FromStrProp for LightColor {}
22impl FromStrProp for Negated {}
23
24impl<T: FromStrProp> EntityProp<'_> for T
25where
26 EntityParseError: From<<T as FromStr>::Err>,
27{
28 fn parse(raw: &'_ str) -> Result<Self, EntityParseError> {
29 Ok(raw.parse()?)
30 }
31}
32
33impl<T: FromStrProp, const N: usize> EntityProp<'_> for [T; N]
34where
35 EntityParseError: From<<T as FromStr>::Err>,
36 [T; N]: Default,
37{
38 fn parse(raw: &'_ str) -> Result<Self, EntityParseError> {
39 let mut values = raw.split_whitespace().map(T::from_str);
40 let mut result = <[T; N]>::default();
41 for item in result.iter_mut() {
42 *item = values.next().ok_or(EntityParseError::ElementCount)??;
43 }
44 Ok(result)
45 }
46}
47
48impl<'a> EntityProp<'a> for &'a str {
49 fn parse(raw: &'a str) -> Result<Self, EntityParseError> {
50 Ok(raw)
51 }
52}
53
54impl EntityProp<'_> for bool {
55 fn parse(raw: &'_ str) -> Result<Self, EntityParseError> {
56 Ok(raw != "0" && raw != "no")
57 }
58}
59
60impl<'a, T: EntityProp<'a>> EntityProp<'a> for Option<T> {
61 fn parse(raw: &'a str) -> Result<Self, EntityParseError> {
62 Ok(Some(T::parse(raw)?))
63 }
64}
65
66#[derive(Debug, Error)]
67pub enum EntityParseError {
68 #[error("wrong number of elements")]
69 ElementCount,
70 #[error(transparent)]
71 Float(#[from] ParseFloatError),
72 #[error(transparent)]
73 Int(#[from] ParseIntError),
74}