1use std::fmt;
2use std::path::Path;
3use std::str::FromStr;
4
5use crate::render::{CopperlaceValue, RenderContext, RenderError, RuleSet};
6
7#[derive(Debug, PartialEq, Eq)]
9pub enum ConfigError {
10 Parse(String),
12 Render(RenderError),
14}
15
16impl fmt::Display for ConfigError {
17 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
18 match self {
19 ConfigError::Parse(error) => write!(formatter, "failed to parse config: {error}"),
20 ConfigError::Render(error) => write!(formatter, "{error}"),
21 }
22 }
23}
24
25impl std::error::Error for ConfigError {}
26
27impl From<RenderError> for ConfigError {
28 fn from(error: RenderError) -> Self {
29 ConfigError::Render(error)
30 }
31}
32
33pub struct Copperlace {
39 ruleset: RuleSet,
40}
41
42impl Copperlace {
43 #[allow(clippy::should_implement_trait)]
49 pub fn from_str(config: &str) -> Result<Self, ConfigError> {
50 Ok(Self {
51 ruleset: ruleset_from_str(config)?,
52 })
53 }
54
55 pub fn from_file(path: impl AsRef<Path>) -> Result<Self, ConfigError> {
61 Ok(Self {
62 ruleset: ruleset_from_file(path)?,
63 })
64 }
65
66 pub fn render(&self, rule_name: &str) -> Result<String, RenderError> {
71 self.ruleset.render_rule(rule_name)
72 }
73
74 pub fn render_with_context(
79 &self,
80 rule_name: &str,
81 context: RenderContext,
82 ) -> Result<String, RenderError> {
83 self.ruleset.render_rule_with_context(rule_name, context)
84 }
85
86 pub fn render_inferred(&self, rule_name: &str) -> Result<String, RenderError> {
88 self.ruleset.render_rule_inferred(rule_name)
89 }
90
91 pub fn render_inferred_with_context(
93 &self,
94 rule_name: &str,
95 context: RenderContext,
96 ) -> Result<String, RenderError> {
97 self.ruleset
98 .render_rule_inferred_with_context(rule_name, context)
99 }
100
101 pub fn render_structured(&self, rule_name: &str) -> Result<CopperlaceValue, RenderError> {
103 self.ruleset.render_rule_structured(rule_name)
104 }
105
106 pub fn render_structured_with_context(
108 &self,
109 rule_name: &str,
110 context: RenderContext,
111 ) -> Result<CopperlaceValue, RenderError> {
112 self.ruleset
113 .render_rule_structured_with_context(rule_name, context)
114 }
115}
116
117impl FromStr for Copperlace {
118 type Err = ConfigError;
119
120 fn from_str(config: &str) -> Result<Self, Self::Err> {
121 Ok(Self {
122 ruleset: ruleset_from_str(config)?,
123 })
124 }
125}
126
127pub fn ruleset_from_str(config: &str) -> Result<RuleSet, ConfigError> {
129 let value = hocon_rs::Config::parse_str::<hocon_rs::Value>(config, None)
130 .map_err(|error| ConfigError::Parse(format!("{error:?}")))?;
131 RuleSet::from_config(value).map_err(ConfigError::Render)
132}
133
134pub fn ruleset_from_file(path: impl AsRef<Path>) -> Result<RuleSet, ConfigError> {
136 let path = path.as_ref().to_string_lossy();
137 let value = hocon_rs::Config::load(path.as_ref(), None)
138 .map_err(|error| ConfigError::Parse(format!("{error:?}")))?;
139 RuleSet::from_config(value).map_err(ConfigError::Render)
140}
141
142pub fn render_str(config: &str, rule_name: &str) -> Result<String, ConfigError> {
148 render_str_with_context(config, rule_name, RenderContext::new())
149}
150
151pub fn render_str_with_context(
153 config: &str,
154 rule_name: &str,
155 context: RenderContext,
156) -> Result<String, ConfigError> {
157 ruleset_from_str(config)?
158 .render_rule_with_context(rule_name, context)
159 .map_err(ConfigError::Render)
160}
161
162pub fn render_str_inferred(config: &str, rule_name: &str) -> Result<String, ConfigError> {
164 render_str_inferred_with_context(config, rule_name, RenderContext::new())
165}
166
167pub fn render_str_inferred_with_context(
169 config: &str,
170 rule_name: &str,
171 context: RenderContext,
172) -> Result<String, ConfigError> {
173 ruleset_from_str(config)?
174 .render_rule_inferred_with_context(rule_name, context)
175 .map_err(ConfigError::Render)
176}
177
178pub fn render_str_structured(
180 config: &str,
181 rule_name: &str,
182) -> Result<CopperlaceValue, ConfigError> {
183 render_str_structured_with_context(config, rule_name, RenderContext::new())
184}
185
186pub fn render_str_structured_with_context(
188 config: &str,
189 rule_name: &str,
190 context: RenderContext,
191) -> Result<CopperlaceValue, ConfigError> {
192 ruleset_from_str(config)?
193 .render_rule_structured_with_context(rule_name, context)
194 .map_err(ConfigError::Render)
195}
196
197pub fn render_file(path: impl AsRef<Path>, rule_name: &str) -> Result<String, ConfigError> {
203 render_file_with_context(path, rule_name, RenderContext::new())
204}
205
206pub fn render_file_with_context(
208 path: impl AsRef<Path>,
209 rule_name: &str,
210 context: RenderContext,
211) -> Result<String, ConfigError> {
212 ruleset_from_file(path)?
213 .render_rule_with_context(rule_name, context)
214 .map_err(ConfigError::Render)
215}
216
217pub fn render_file_inferred(
219 path: impl AsRef<Path>,
220 rule_name: &str,
221) -> Result<String, ConfigError> {
222 render_file_inferred_with_context(path, rule_name, RenderContext::new())
223}
224
225pub fn render_file_inferred_with_context(
227 path: impl AsRef<Path>,
228 rule_name: &str,
229 context: RenderContext,
230) -> Result<String, ConfigError> {
231 ruleset_from_file(path)?
232 .render_rule_inferred_with_context(rule_name, context)
233 .map_err(ConfigError::Render)
234}
235
236pub fn render_file_structured(
238 path: impl AsRef<Path>,
239 rule_name: &str,
240) -> Result<CopperlaceValue, ConfigError> {
241 render_file_structured_with_context(path, rule_name, RenderContext::new())
242}
243
244pub fn render_file_structured_with_context(
246 path: impl AsRef<Path>,
247 rule_name: &str,
248 context: RenderContext,
249) -> Result<CopperlaceValue, ConfigError> {
250 ruleset_from_file(path)?
251 .render_rule_structured_with_context(rule_name, context)
252 .map_err(ConfigError::Render)
253}