miau/configuration/
key.rs

1use crate::{error::ConfigurationError, parsing};
2use serde::{Deserialize, Serialize};
3use std::convert::TryFrom;
4use std::ops::Deref;
5use std::{convert::From, fmt};
6
7///Multikey for configuration
8///
9///Consists of multiple [keys](Key)
10///
11///It is used indirectly in many functions reading from configuration.
12///Usually it should not be constructed directly.
13#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Hash)]
14#[serde(transparent)]
15pub struct CompoundKey(Vec<Key>);
16
17///Configuration key
18///
19///It comes in two flavours - for arrays and maps.
20#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Hash)]
21#[serde(untagged)]
22pub enum Key {
23    ///Variant that is used to index into arrays
24    Array(usize),
25    ///Variant that is used as a key in maps
26    Map(String),
27}
28
29impl CompoundKey {
30    /// Constructs new instance of `CompoundKey`
31    pub fn new(keys: Vec<Key>) -> Self {
32        CompoundKey(keys)
33    }
34}
35
36impl Key {
37    /// Unwraps underlying string in map variant
38    ///
39    /// # Panics
40    /// Panics if `Key` variant is `Array`
41    pub fn unwrap_map(&self) -> String {
42        match self {
43            Key::Array(_) => panic!("Expected key to be map key!"),
44            Key::Map(s) => s.clone(),
45        }
46    }
47    /// Unwraps underlying usize in map variant
48    ///
49    /// # Panics
50    /// Panics if `Key` variant is `Map`
51    pub fn unwrap_array(&self) -> usize {
52        match self {
53            Key::Array(i) => *i,
54            Key::Map(_) => panic!("Expected key to be array key!"),
55        }
56    }
57}
58
59impl Deref for CompoundKey {
60    type Target = Vec<Key>;
61
62    fn deref(&self) -> &Self::Target {
63        &self.0
64    }
65}
66
67impl From<Vec<Key>> for CompoundKey {
68    fn from(keys: Vec<Key>) -> Self {
69        CompoundKey::new(keys)
70    }
71}
72
73impl TryFrom<&str> for CompoundKey {
74    type Error = ConfigurationError;
75
76    fn try_from(value: &str) -> Result<Self, Self::Error> {
77        parsing::str_to_key(value)
78            .map_err(|e| e.enrich_with_context(format!("Parsing key `{}` failed", value)))
79    }
80}
81
82impl TryFrom<String> for CompoundKey {
83    type Error = ConfigurationError;
84
85    fn try_from(value: String) -> Result<Self, Self::Error> {
86        parsing::str_to_key(value.as_ref())
87            .map_err(|e| e.enrich_with_context(format!("Parsing key `{}` failed", value)))
88    }
89}
90
91impl fmt::Display for Key {
92    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93        match self {
94            Key::Array(i) => write!(f, "[{}]", i),
95            Key::Map(k) => write!(f, "{}", k),
96        }
97    }
98}
99
100impl From<String> for Key {
101    fn from(v: String) -> Self {
102        Key::Map(v)
103    }
104}
105
106impl From<&str> for Key {
107    fn from(v: &str) -> Self {
108        Key::Map(v.to_string())
109    }
110}
111
112macro_rules! impl_key_from {
113    ($($t:ty),*) => {
114        $(impl From<$t> for Key {
115            fn from(v: $t) -> Self {
116                Key::Array(v as usize)
117            }
118        })*
119    };
120}
121
122impl_key_from!(u8, u16, u32, u64, usize);