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}