1use anyhow::{bail, Context, Result};
2use serde::Deserialize;
3use walrus::{ir::Value, ConstExpr, DataKind, ExportItem, GlobalKind, Module};
4
5use crate::walrus_ops::{bump_stack_global, get_active_data_segment};
6
7#[derive(Deserialize, Debug, Clone, Default)]
8#[serde(deny_unknown_fields)]
9pub struct Config {
10 #[serde(default)]
12 pub overrides: Vec<(String, String)>,
13}
14
15pub(crate) fn create_config<'a>(module: &'a mut Module, config: &Config) -> Result<()> {
16 let config_ptr_addr = {
17 let config_ptr_export = module
18 .exports
19 .iter()
20 .find(|expt| expt.name.as_str() == "CONFIG")
21 .context("Adapter 'CONFIG' is not exported")?;
22 let ExportItem::Global(config_ptr_global) = config_ptr_export.item else {
23 bail!("Adapter 'config' not a global");
24 };
25 let GlobalKind::Local(ConstExpr::Value(Value::I32(config_ptr_addr))) =
26 &module.globals.get(config_ptr_global).kind
27 else {
28 bail!("Adapter 'config' not a local I32 global value");
29 };
30 *config_ptr_addr as u32
31 };
32
33 let memory = module.get_memory_id()?;
34
35 let mut field_data_vec: Vec<&str> = Vec::new();
38 let mut sorted_overrides = config.overrides.clone();
39 sorted_overrides.sort_by(|(a, _), (b, _)| a.cmp(b));
40 for (key, value) in &sorted_overrides {
41 field_data_vec.push(key.as_ref());
42 field_data_vec.push(value.as_ref());
43 }
44
45 let mut field_data_bytes = Vec::new();
46 for str in field_data_vec {
47 assert!(field_data_bytes.len() % 4 == 0);
48 field_data_bytes.extend_from_slice(&(str.len() as u32).to_le_bytes());
50 let str_bytes = str.as_bytes();
51 field_data_bytes.extend_from_slice(str_bytes);
52 let rem = str_bytes.len() % 4;
53 if rem > 0 {
55 field_data_bytes.extend((0..4 - rem).map(|_| 0));
56 }
57 }
58
59 if field_data_bytes.len() % 8 != 0 {
60 field_data_bytes.resize(field_data_bytes.len() + 4, 0);
61 }
62
63 let field_data_addr = if field_data_bytes.len() > 0 {
64 let field_data_addr = bump_stack_global(module, field_data_bytes.len() as i32)?;
66
67 module.data.add(
69 DataKind::Active {
70 memory,
71 offset: ConstExpr::Value(Value::I32(field_data_addr as i32)),
72 },
73 field_data_bytes,
74 );
75 Some(field_data_addr)
76 } else {
77 None
78 };
79
80 let (data, data_offset) = get_active_data_segment(module, memory, config_ptr_addr)?;
97 let bytes = data.value.as_mut_slice();
98
99 let host_field_cnt = config.overrides.len() as u32;
100 bytes[data_offset + 4..data_offset + 8].copy_from_slice(&host_field_cnt.to_le_bytes());
101 if let Some(field_data_addr) = field_data_addr {
102 bytes[data_offset + 8..data_offset + 12].copy_from_slice(&field_data_addr.to_le_bytes());
103 }
104
105 Ok(())
106}