1#![warn(missing_docs, unsafe_op_in_unsafe_fn)]
4#![warn(clippy::pedantic)]
5#![allow(clippy::missing_errors_doc, clippy::module_name_repetitions, clippy::must_use_candidate)]
6
7mod config;
8mod format;
9
10pub use crate::{config::*, format::*};
11
12use anyhow::{anyhow, bail, Result};
13use std::{env, fs::File, io::prelude::*, path::Path};
14
15pub const CONFIG_NAME: &str = "Drone.toml";
17
18impl Config {
19 pub fn read_from_current_dir() -> Result<Self> {
22 Self::read(Path::new("."))
23 }
24
25 pub fn read_from_cargo_manifest_dir() -> Result<Self> {
31 if let Ok(string) = env::var("CARGO_MANIFEST_DIR_OVERRIDE") {
32 Self::parse(&string)
33 } else {
34 Self::read(
35 env::var_os("CARGO_MANIFEST_DIR")
36 .ok_or_else(|| anyhow!("`CARGO_MANIFEST_DIR` is not set"))?
37 .as_ref(),
38 )
39 }
40 }
41
42 pub fn read(crate_root: &Path) -> Result<Self> {
45 let crate_root = crate_root.canonicalize()?;
46 let path = crate_root.join(CONFIG_NAME);
47 if !path.exists() {
48 bail!("`{}` not exists in `{}", CONFIG_NAME, crate_root.display());
49 }
50 let mut buffer = String::new();
51 let mut file = File::open(&path)?;
52 file.read_to_string(&mut buffer)?;
53 Self::parse(&buffer)
54 }
55
56 pub fn parse(string: &str) -> Result<Self> {
58 let config = toml::from_str::<Self>(&string)?;
59 config.check_heaps()?;
60 Ok(config)
61 }
62
63 fn check_heaps(&self) -> Result<()> {
64 let Self { heap: Heap { main, extra }, .. } = self;
65 main.check_pools()?;
66 for heap in extra.values() {
67 heap.block.check_pools()?;
68 }
69 Ok(())
70 }
71}
72
73impl HeapBlock {
74 fn check_pools(&self) -> Result<()> {
75 let Self { size, pools } = self;
76 let used: u32 = pools.iter().map(|pool| pool.block * pool.capacity).sum();
77 if used != *size {
78 bail!("{}: `heap.pools` adds up to {}, but `heap.size = {}", CONFIG_NAME, used, size);
79 }
80 Ok(())
81 }
82}