prc/
param.rs

1use hash40::Hash40;
2use serde::{Deserialize, Serialize};
3use std::collections::HashMap;
4use std::convert::{TryFrom, TryInto};
5
6#[doc(hidden)]
7pub const MAGIC: &[u8; 8] = b"paracobn";
8const UNWRAP_ERR: &str = "Tried to unwrap param into inconsistent type";
9
10/// The central data structure to param files and params.
11/// Similar to tree-like recursive data formats such as JSON.
12#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
13pub enum ParamKind {
14    // index starts at 1
15    Bool(bool),
16    I8(i8),
17    U8(u8),
18    I16(i16),
19    U16(u16),
20    I32(i32),
21    U32(u32),
22    Float(f32),
23    Hash(Hash40),
24    Str(String),
25    List(ParamList),
26    Struct(ParamStruct),
27}
28
29/// A list of params.
30#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
31#[serde(transparent)]
32pub struct ParamList(pub Vec<ParamKind>);
33
34/// A list of key-value pairs of params.
35/// Acts essentially like a hash-map, but is presented in list form to preserve key order, as well as to handle rare cases where a key may be duplicated.
36/// Keys are hashed strings, represented by the [Hash40] type.
37#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
38#[serde(transparent)]
39pub struct ParamStruct(pub Vec<(Hash40, ParamKind)>);
40
41impl ParamKind {
42    /// Attempts to convert an owned param into the contained value.
43    /// Returns an error if the contained value is not the expected type.
44    pub fn try_into_owned<T>(self) -> Result<T, T::Error>
45    where
46        T: TryFrom<ParamKind>,
47    {
48        self.try_into()
49    }
50
51    /// Attempts to convert a param by reference into a reference of the contained value.
52    /// Returns an error if the contained value is not the expected type.
53    pub fn try_into_ref<'a, T>(
54        &'a self,
55    ) -> Result<&'a T, <&'a T as std::convert::TryFrom<&'a ParamKind>>::Error>
56    where
57        &'a T: TryFrom<&'a ParamKind>,
58    {
59        self.try_into()
60    }
61
62    /// Attempts to convert a param by mutable reference into a mutable reference of the contained value.
63    /// Returns an error if the contained value is not the expected type.
64    pub fn try_into_mut<'a, T>(
65        &'a mut self,
66    ) -> Result<&'a mut T, <&'a mut T as TryFrom<&'a mut ParamKind>>::Error>
67    where
68        &'a mut T: TryFrom<&'a mut ParamKind>,
69    {
70        self.try_into()
71    }
72
73    /// Converts an owned param into a [HashMap], indexing into the contained params.
74    /// Panics if the param was not a [ParamKind::Struct].
75    pub fn unwrap_as_hashmap(self) -> HashMap<Hash40, ParamKind> {
76        TryInto::<ParamStruct>::try_into(self)
77            .unwrap()
78            .0
79            .drain(..)
80            .collect::<HashMap<_, _>>()
81    }
82
83    /// Converts a reference to a param into a [HashMap], indexing into references to the contained params.
84    /// Panics if the param was not a [ParamKind::Struct].
85    pub fn unwrap_as_hashmap_ref(&self) -> HashMap<Hash40, &ParamKind> {
86        TryInto::<&ParamStruct>::try_into(self)
87            .unwrap()
88            .0
89            .iter()
90            .map(|(h, p)| (*h, p))
91            .collect::<HashMap<_, _>>()
92    }
93
94    /// Converts a mutable reference to a param into a [HashMap], indexing into mutable references to the contained params.
95    /// Panics if the param was not a [ParamKind::Struct].
96    pub fn unwrap_as_hashmap_mut(&mut self) -> HashMap<Hash40, &mut ParamKind> {
97        TryInto::<&mut ParamStruct>::try_into(self)
98            .unwrap()
99            .0
100            .iter_mut()
101            .map(|(h, p)| (*h, p))
102            .collect::<HashMap<_, _>>()
103    }
104}
105
106use ParamKind::*;
107
108macro_rules! impl_from_param {
109    ($($param:ident ($t:ty)),*$(,)?) => {
110        $(
111            impl TryFrom<ParamKind> for $t {
112                type Error = &'static str;
113
114                fn try_from(param: ParamKind) -> Result<Self, Self::Error> {
115                    if let $param(val) = param {
116                        Ok(val)
117                    } else {
118                        Err(UNWRAP_ERR)
119                    }
120                }
121            }
122
123            impl<'a> TryFrom<&'a ParamKind> for &'a $t {
124                type Error = &'static str;
125
126                fn try_from(param: &'a ParamKind) -> Result<Self, Self::Error> {
127                    if let $param(val) = param {
128                        Ok(val)
129                    } else {
130                        Err(UNWRAP_ERR)
131                    }
132                }
133            }
134
135            impl<'a> TryFrom<&'a mut ParamKind> for &'a mut $t {
136                type Error = &'static str;
137
138                fn try_from(param: &'a mut ParamKind) -> Result<Self, Self::Error> {
139                    if let $param(val) = param {
140                        Ok(val)
141                    } else {
142                        Err(UNWRAP_ERR)
143                    }
144                }
145            }
146
147            impl From<$t> for ParamKind {
148                fn from(v: $t) -> ParamKind {
149                    ParamKind::$param(v)
150                }
151            }
152        )*
153    }
154}
155
156impl_from_param! {
157    Bool(bool),
158    I8(i8),
159    U8(u8),
160    I16(i16),
161    U16(u16),
162    I32(i32),
163    U32(u32),
164    Float(f32),
165    Hash(Hash40),
166    Str(String),
167    List(ParamList),
168    Struct(ParamStruct),
169}