Skip to main content

mint_core/layout/
mod.rs

1pub mod block;
2mod conversions;
3mod entry;
4pub mod error;
5pub mod header;
6pub mod scalar_type;
7pub mod settings;
8pub mod used_values;
9pub mod value;
10
11use block::Config;
12use error::LayoutError;
13use std::collections::hash_map::Entry;
14use std::path::Path;
15use toml::Value as TomlValue;
16
17pub fn load_layout(filename: &str) -> Result<Config, LayoutError> {
18    let text = std::fs::read_to_string(filename)
19        .map_err(|_| LayoutError::FileError(format!("failed to open file: {}", filename)))?;
20
21    let ext = Path::new(filename)
22        .extension()
23        .and_then(|s| s.to_str())
24        .map(|s| s.to_ascii_lowercase())
25        .unwrap_or_default();
26
27    match ext.as_str() {
28        "toml" => parse_toml_layout_with_context(&text, &format!("file {}", filename)),
29        "yaml" | "yml" => parse_yaml_layout_with_context(&text, &format!("file {}", filename)),
30        _ => Err(LayoutError::FileError(
31            "Unsupported layout file format; use .toml or .yaml".to_owned(),
32        )),
33    }
34}
35
36pub fn parse_toml_layout(text: &str) -> Result<Config, LayoutError> {
37    parse_toml_layout_with_context(text, "TOML layout")
38}
39
40pub fn parse_yaml_layout(text: &str) -> Result<Config, LayoutError> {
41    parse_yaml_layout_with_context(text, "YAML layout")
42}
43
44fn parse_toml_layout_with_context(text: &str, context: &str) -> Result<Config, LayoutError> {
45    let raw: TomlValue = toml::from_str(text)
46        .map_err(|e| LayoutError::FileError(format!("failed to parse {}: {}", context, e)))?;
47    let mut cfg: Config = raw
48        .try_into()
49        .map_err(|e| LayoutError::FileError(format!("failed to parse {}: {}", context, e)))?;
50    promote_block_header_consts(&mut cfg)?;
51    Ok(cfg)
52}
53
54fn parse_yaml_layout_with_context(text: &str, context: &str) -> Result<Config, LayoutError> {
55    let mut cfg: Config = serde_yaml::from_str(text)
56        .map_err(|e| LayoutError::FileError(format!("failed to parse {}: {}", context, e)))?;
57    promote_block_header_consts(&mut cfg)?;
58    Ok(cfg)
59}
60
61fn promote_block_header_consts(cfg: &mut Config) -> Result<(), LayoutError> {
62    for (block_name, block) in &cfg.blocks {
63        insert_promoted_const(
64            &mut cfg.mint.consts,
65            format!("{block_name}.start_address"),
66            block.header.start_address,
67        )?;
68        insert_promoted_const(
69            &mut cfg.mint.consts,
70            format!("{block_name}.length"),
71            block.header.length,
72        )?;
73    }
74    Ok(())
75}
76
77fn insert_promoted_const(
78    consts: &mut std::collections::HashMap<String, value::ValueSource>,
79    name: String,
80    value: u32,
81) -> Result<(), LayoutError> {
82    match consts.entry(name) {
83        Entry::Occupied(entry) => Err(LayoutError::FileError(format!(
84            "[mint.const] key '{}' collides with auto-promoted block header const",
85            entry.key()
86        ))),
87        Entry::Vacant(entry) => {
88            entry.insert(value::ValueSource::Single(value::DataValue::U64(
89                u64::from(value),
90            )));
91            Ok(())
92        }
93    }
94}