vtcode_config/loader/
merge.rs1use crate::loader::layers::ConfigLayerMetadata;
2use hashbrown::HashMap;
3
4pub fn merge_toml_values(base: &mut toml::Value, overlay: &toml::Value) {
9 match (base, overlay) {
10 (toml::Value::Table(base_table), toml::Value::Table(overlay_table)) => {
11 for (key, value) in overlay_table {
12 if let Some(base_value) = base_table.get_mut(key) {
13 merge_toml_values(base_value, value);
14 } else {
15 base_table.insert(key.clone(), value.clone());
16 }
17 }
18 }
19 (base, overlay) => {
20 *base = overlay.clone();
21 }
22 }
23}
24
25pub fn merge_toml_values_with_origins(
27 base: &mut toml::Value,
28 overlay: &toml::Value,
29 origins: &mut HashMap<String, ConfigLayerMetadata>,
30 layer: &ConfigLayerMetadata,
31) {
32 merge_with_origins(base, overlay, "", origins, layer);
33}
34
35fn merge_with_origins(
36 base: &mut toml::Value,
37 overlay: &toml::Value,
38 path: &str,
39 origins: &mut HashMap<String, ConfigLayerMetadata>,
40 layer: &ConfigLayerMetadata,
41) {
42 match (base, overlay) {
43 (toml::Value::Table(base_table), toml::Value::Table(overlay_table)) => {
44 for (key, value) in overlay_table {
45 let child_path = if path.is_empty() {
46 key.clone()
47 } else {
48 format!("{path}.{key}")
49 };
50
51 if let Some(base_value) = base_table.get_mut(key) {
52 if base_value.is_table() && value.is_table() {
53 merge_with_origins(base_value, value, &child_path, origins, layer);
54 } else {
55 *base_value = value.clone();
56 assign_origins(value, &child_path, origins, layer);
57 }
58 } else {
59 base_table.insert(key.clone(), value.clone());
60 assign_origins(value, &child_path, origins, layer);
61 }
62 }
63 }
64 (base, overlay) => {
65 *base = overlay.clone();
66 if !path.is_empty() {
67 assign_origins(overlay, path, origins, layer);
68 }
69 }
70 }
71}
72
73fn assign_origins(
74 value: &toml::Value,
75 path: &str,
76 origins: &mut HashMap<String, ConfigLayerMetadata>,
77 layer: &ConfigLayerMetadata,
78) {
79 match value {
80 toml::Value::Table(table) => {
81 for (key, child) in table {
82 let child_path = if path.is_empty() {
83 key.clone()
84 } else {
85 format!("{path}.{key}")
86 };
87 assign_origins(child, &child_path, origins, layer);
88 }
89 }
90 _ => {
91 origins.insert(path.to_string(), layer.clone());
92 }
93 }
94}