Skip to main content

crypt_configs/
body.rs

1//! Config Body Object
2//! Created 6/4/2026 - Nyx
3
4use std::collections::HashMap;
5
6#[derive(Debug, PartialEq, Eq)]
7/// A Crypt Configuration object
8/// 
9/// Uses a simple map for string identifiers to [CryptObject]s.
10/// Configs can contain other nested configs, string literals, and identifiers.
11/// String literals and identifiers are both stored as a [String].
12/// 
13/// # Example
14/// 
15/// Example crypt file:
16/// 
17/// ./tests/test.crypt
18/// ```crypt
19/// version = "0.1.0";
20/// name = "Test";
21/// type = "Executable"
22/// ```
23/// 
24/// 
25/// Opening the file:
26/// ```
27/// use crypt_configs::{open_config, body::CryptObject};
28/// 
29/// let config = match open_config("tests/test.crypt") {
30///     Ok(c) => c,
31///     Err(e) => panic!("Failed to open test file!"),
32/// };
33/// 
34/// assert_eq!(config.get("version").unwrap().try_into(), Ok(&String::from("0.1.0")));
35/// assert_eq!(config.get("name").unwrap().try_into(), Ok(&String::from("Test")));
36/// assert_eq!(config.get("type").unwrap().try_into(), Ok(&String::from("Executable")));
37/// ```
38pub struct CryptConfig {
39    items: HashMap<String, CryptObject>
40}
41
42impl CryptConfig {
43    pub (crate) fn new() -> Self {
44        Self {
45            items: HashMap::new()
46        }
47    }
48
49    pub (crate) fn add_item(&mut self, identifier: String, value: CryptObject) {
50        self.items.insert(identifier, value);
51    }
52
53    /// Retrieves an item from the config
54    /// 
55    /// The object is ambiguously wrapped in a [CryptObject]. 
56    pub fn get<S>(&self, ident: S) -> Option<&CryptObject> 
57    where 
58        S: Into<String>
59    {
60        self.items.get(&ident.into())
61    } 
62}
63
64#[derive(Debug, PartialEq, Eq)]
65/// An ambiguously wrapped object in a crypt config.
66/// 
67/// crypt objects come in four variants: identifiers, string literals, 
68/// bodies (nested configs), and nulls.
69/// 
70/// CryptObject implements [TryInto] for &String and &CryptConfig for quick 
71/// conversions. More complex conversion methods are additionally implemented.
72pub enum CryptObject {
73    Identifier(String),
74    String(String),
75    Body(CryptConfig),
76    Null,
77}
78
79impl CryptObject {
80    /// Unwraps an identifier crypt object into its [String] value
81    /// 
82    /// # Panics
83    /// 
84    /// Panics if the crypt object is not an identifier. Unlike TryInto this will
85    /// not automatically convert string literals.
86    pub fn unwrap_identifier(&self) -> &String {
87        match self {
88            Self::Identifier(ident) => ident,
89            _ => panic!("Unwrapped a non-identifier crypt object!")
90        }
91    }
92
93    /// Unwraps an identifier crypt object into its [String] value
94    /// 
95    /// # Panics
96    /// 
97    /// Panics if the crypt object is not an identifier with a special 
98    /// message given by msg. Unlike TryInto this will
99    /// not automatically convert string literals.
100    pub fn expect_identifier(&self, msg: &str) -> &String {
101        match self {
102            Self::Identifier(ident) => ident,
103            _ => panic!("{}", msg)
104        }
105    }
106
107    /// Unwraps an identifier crypt object into its string value, alternatively if
108    /// the object isn't an identifier it will return the alternate string value.
109    pub fn unwrap_identifier_or<'a>(&'a self, other: &'a String) -> &'a String {
110        match self {
111            Self::Identifier(ident) => ident,
112            _ => other
113        }
114    }
115
116
117    /// Unwraps a string literal crypt object into its [String] value
118    /// 
119    /// # Panics
120    /// 
121    /// Panics if the crypt object is not an identifier. Unlike TryInto this will
122    /// not automatically convert identifier.
123    pub fn unwrap_string(&self) -> &String {
124        match self {
125            Self::String(s) => s,
126            _ => panic!("Unwrapped a non-identifier crypt object!")
127        }
128    }
129
130    /// Unwraps a string literal crypt object into its [String] value
131    /// 
132    /// # Panics
133    /// 
134    /// Panics if the crypt object is not an identifier with a special 
135    /// message given by msg. Unlike TryInto this will
136    /// not automatically convert identifiers.
137    pub fn expect_string(&self, msg: &str) -> &String {
138        match self {
139            Self::String(s) => s,
140            _ => panic!("{}", msg)
141        }
142    }
143
144    /// Unwraps a string literal crypt object into its string value, alternatively if
145    /// the object isn't a string literal it will return the alternate string value.
146    pub fn unwrap_string_or<'a>(&'a self, other: &'a String) -> &'a String {
147        match self {
148            Self::String(s) => s,
149            _ => other
150        }
151    }
152
153    /// Unwraps a string literal crypt object into its [String] value
154    /// 
155    /// # Panics
156    /// 
157    /// Panics if the crypt object is not an identifier. Unlike TryInto this will
158    /// not automatically convert identifier.
159    pub fn unwrap_nested_config(&self) -> &CryptConfig {
160        match self {
161            Self::Body(b) => b,
162            _ => panic!("Unwrapped a non-identifier crypt object!")
163        }
164    }
165
166    /// Unwraps a string literal crypt object into its [String] value
167    /// 
168    /// # Panics
169    /// 
170    /// Panics if the crypt object is not an identifier with a special 
171    /// message given by msg. Unlike TryInto this will
172    /// not automatically convert identifiers.
173    pub fn expect_nested_config(&self, msg: &str) -> &CryptConfig {
174        match self {
175            Self::Body(b) => b,
176            _ => panic!("{}", msg)
177        }
178    }
179}
180
181
182
183
184impl<'a> TryInto<&'a String> for &'a CryptObject {
185    type Error = CryptConversionError;
186
187    fn try_into(self) -> Result<&'a String, Self::Error> {
188        match self {
189            CryptObject::String(v) => Ok(v),
190            CryptObject::Identifier(id) => Ok(id),
191            _ => Err(CryptConversionError::CannotConvertToString)
192        }
193    }
194}
195
196impl<'a> TryInto<&'a CryptConfig> for &'a CryptObject {
197    type Error = CryptConversionError;
198
199    fn try_into(self) -> Result<&'a CryptConfig, Self::Error> {
200        match self {
201            CryptObject::Body(b) => Ok(b),
202            _ => Err(CryptConversionError::CannotConvertToNestedConfig)
203        }
204    }
205}
206
207
208#[derive(Debug, PartialEq, Eq)]
209pub enum CryptConversionError {
210    CannotConvertToString,
211    CannotConvertToNestedConfig,
212    CannotConvertToIdentifier,
213}
214
215impl std::fmt::Display for CryptConversionError {
216    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
217        match self {
218            Self::CannotConvertToString => write!(f, "Crypt object cannot be converted to string!"),
219            Self::CannotConvertToIdentifier => write!(f, "Crypt object cannot be converted to an identifier!"),
220            Self::CannotConvertToNestedConfig => write!(f, "Crypt object cannot be converted to a nested config!"),
221        }
222    }
223}