hotshot_builder_api/
api.rs

1// Copyright (c) 2021-2024 Espresso Systems (espressosys.com)
2// This file is part of the HotShot repository.
3
4// You should have received a copy of the MIT License
5// along with the HotShot repository. If not, see <https://mit-license.org/>.
6
7use 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}