hotshot_builder_api/
api.rs1use std::{fs, path::Path};
8
9use tide_disco::api::{Api, ApiError};
10use toml::{map::Entry, Value};
11use vbs::version::StaticVersionType;
12
13pub(crate) fn load_api<State: 'static, Error: 'static, Ver: StaticVersionType + 'static>(
14 path: Option<impl AsRef<Path>>,
15 default: &str,
16 extensions: impl IntoIterator<Item = Value>,
17) -> Result<Api<State, Error, Ver>, ApiError> {
18 let mut toml = match path {
19 Some(path) => load_toml(path.as_ref())?,
20 None => toml::from_str(default).map_err(|err| ApiError::CannotReadToml {
21 reason: err.to_string(),
22 })?,
23 };
24 for extension in extensions {
25 merge_toml(&mut toml, extension);
26 }
27 Api::new(toml)
28}
29
30fn merge_toml(into: &mut Value, from: Value) {
31 if let (Value::Table(into), Value::Table(from)) = (into, from) {
32 for (key, value) in from {
33 match into.entry(key) {
34 Entry::Occupied(mut entry) => merge_toml(entry.get_mut(), value),
35 Entry::Vacant(entry) => {
36 entry.insert(value);
37 },
38 }
39 }
40 }
41}
42
43fn load_toml(path: &Path) -> Result<Value, ApiError> {
44 let bytes = fs::read(path).map_err(|err| ApiError::CannotReadToml {
45 reason: err.to_string(),
46 })?;
47 let string = std::str::from_utf8(&bytes).map_err(|err| ApiError::CannotReadToml {
48 reason: err.to_string(),
49 })?;
50 toml::from_str(string).map_err(|err| ApiError::CannotReadToml {
51 reason: err.to_string(),
52 })
53}