1use super::entry::LeafEntry;
2use super::error::LayoutError;
3use super::header::Header;
4use super::settings::{Endianness, Settings};
5use super::used_values::ValueSink;
6use crate::data::DataSource;
7
8use indexmap::IndexMap;
9use serde::Deserialize;
10
11struct BuildState {
13 buffer: Vec<u8>,
14 offset: usize,
15 padding_count: u32,
16}
17
18pub struct BuildConfig<'a> {
20 pub endianness: &'a Endianness,
21 pub padding: u8,
22 pub strict: bool,
23 pub word_addressing: bool,
24}
25
26#[derive(Debug, Deserialize)]
27pub struct Config {
28 pub settings: Settings,
29 #[serde(flatten)]
30 pub blocks: IndexMap<String, Block>,
31}
32
33#[derive(Debug, Deserialize)]
35pub struct Block {
36 pub header: Header,
37 pub data: Entry,
38}
39
40#[derive(Debug, Deserialize)]
42#[serde(untagged)]
43pub enum Entry {
44 Leaf(LeafEntry),
45 Branch(IndexMap<String, Entry>),
46}
47
48impl Block {
49 pub fn build_bytestream(
50 &self,
51 data_source: Option<&dyn DataSource>,
52 settings: &Settings,
53 strict: bool,
54 value_sink: &mut dyn ValueSink,
55 ) -> Result<(Vec<u8>, u32), LayoutError> {
56 let mut state = BuildState {
57 buffer: Vec::with_capacity((self.header.length as usize).min(64 * 1024)),
58 offset: 0,
59 padding_count: 0,
60 };
61 let config = BuildConfig {
62 endianness: &settings.endianness,
63 padding: self.header.padding,
64 strict,
65 word_addressing: settings.word_addressing,
66 };
67
68 let mut field_path = Vec::new();
69 Self::build_bytestream_inner(
70 &self.data,
71 data_source,
72 &mut state,
73 &config,
74 value_sink,
75 &mut field_path,
76 )?;
77
78 Ok((state.buffer, state.padding_count))
79 }
80
81 fn build_bytestream_inner(
82 table: &Entry,
83 data_source: Option<&dyn DataSource>,
84 state: &mut BuildState,
85 config: &BuildConfig,
86 value_sink: &mut dyn ValueSink,
87 field_path: &mut Vec<String>,
88 ) -> Result<(), LayoutError> {
89 match table {
90 Entry::Leaf(leaf) => {
91 let alignment = leaf.get_alignment();
92 while !state.offset.is_multiple_of(alignment) {
93 state.buffer.push(config.padding);
94 state.offset += 1;
95 state.padding_count += 1;
96 }
97
98 let bytes = leaf.emit_bytes(data_source, config, value_sink, field_path)?;
99 state.offset += bytes.len();
100 state.buffer.extend(bytes);
101 }
102 Entry::Branch(branch) => {
103 for (field_name, v) in branch.iter() {
104 let path_len = field_path.len();
105 let segments = split_field_path(field_name)?;
106 field_path.extend(segments);
107 let result = Self::build_bytestream_inner(
108 v,
109 data_source,
110 state,
111 config,
112 value_sink,
113 field_path,
114 );
115 field_path.truncate(path_len);
116 result.map_err(|e| LayoutError::InField {
117 field: field_name.clone(),
118 source: Box::new(e),
119 })?;
120 }
121 }
122 }
123 Ok(())
124 }
125}
126
127fn split_field_path(field_name: &str) -> Result<Vec<String>, LayoutError> {
128 let segments: Vec<&str> = field_name.split('.').collect();
129 if segments.iter().any(|s| s.is_empty()) {
130 return Err(LayoutError::DataValueExportFailed(format!(
131 "Invalid field path '{}'.",
132 field_name
133 )));
134 }
135 Ok(segments.into_iter().map(|s| s.to_string()).collect())
136}