drone_config/
lib.rs

1//! Configuration for Drone, an Embedded Operating System.
2
3#![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
15/// The name of the Drone configuration file.
16pub const CONFIG_NAME: &str = "Drone.toml";
17
18impl Config {
19    /// Reads the configuration file from the current working directory and
20    /// returns a parsed object.
21    pub fn read_from_current_dir() -> Result<Self> {
22        Self::read(Path::new("."))
23    }
24
25    /// Reads the configuration file from the `CARGO_MANIFEST_DIR` environment
26    /// variable path and returns a parsed object.
27    ///
28    /// If `CARGO_MANIFEST_DIR_OVERRIDE` environment variable is set, the
29    /// function will parse its value directly.
30    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    /// Reads the configuration file at `crate_root` and returns a parsed
43    /// object.
44    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    /// Parses config from the `string`.
57    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}