Skip to content

Commit c223586

Browse files
committed
Completely replace cfg::Table with toml::Table + helper functions; parse Tables from CLI and config.toml
1 parent 6b2c66d commit c223586

File tree

3 files changed

+71
-108
lines changed

3 files changed

+71
-108
lines changed

toybox-cfg/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ edition.workspace = true
77
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
88

99
[dependencies]
10-
toml = "0.8.10"
10+
toml = {version="0.8.10", features=["preserve_order"]}
1111
anyhow.workspace = true
1212
tracing.workspace = true
1313
log.workspace = true

toybox-cfg/src/lib.rs

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11

22
pub mod prelude {}
33

4-
pub mod table;
5-
use table::{Table, Value};
4+
mod table;
5+
use toml::{Table, Value};
66

7-
use std::path::{PathBuf};
87
use tracing::instrument;
98

109
use toybox_vfs::{Vfs, PathKind};
@@ -27,8 +26,6 @@ pub struct Config {
2726
/// Combined config with overrides applied.
2827
// TODO(pat.m): this is basically a cache but maybe I don't need this
2928
resolved: Table,
30-
31-
save_path: PathBuf,
3229
}
3330

3431
impl Config {
@@ -38,14 +35,15 @@ impl Config {
3835
let mut config = Self::default();
3936

4037
if vfs.path_exists(PathKind::Config, "config.toml") {
41-
config.base = Table::from_file(vfs, PathKind::Config, "config.toml")?;
38+
config.base = table::load_from_vfs(vfs, PathKind::Config, "config.toml")?;
39+
4240
} else {
43-
log::info!("Couldn't load config - writing defaults to {}", config.save_path.display());
41+
log::info!("Couldn't load config - writing defaults to '{}'", vfs.local_data_root().display());
4442
// TODO(pat.m): defaults?
45-
config.base.save_to_file(vfs, PathKind::Config, "config.toml")?;
43+
table::save_to_vfs(&config.base, vfs, PathKind::Config, "config.toml")?;
4644
}
4745

48-
config.arguments = Table::from_cli()?;
46+
config.arguments = table::load_from_cli()?;
4947

5048
// TODO(pat.m): resolve
5149

@@ -57,17 +55,19 @@ impl Config {
5755
#[instrument(skip_all, name="cfg Config::save")]
5856
pub fn save(&self, vfs: &Vfs) -> anyhow::Result<()> {
5957
// TODO(pat.m): extra resolve?
60-
self.base.save_to_file(vfs, PathKind::Config, "config.toml")
58+
table::save_to_vfs(&self.base, vfs, PathKind::Config, "config.toml")
6159
}
6260

6361
#[instrument(skip_all, name="cfg Config::commit")]
6462
pub fn commit(&mut self) {
65-
self.base.merge_from(&self.preview);
66-
self.arguments.remove_values_in(&self.preview);
63+
// self.base.merge_from(&self.preview);
64+
// self.arguments.remove_values_in(&self.preview);
6765

6866
// TODO(pat.m): this may not be needed if preview config is automatically added to resolved
6967
self.preview = Table::new();
7068
self.resolved = Table::new();
69+
70+
todo!();
7171
}
7272

7373
#[instrument(skip_all, name="cfg Config::revert")]
@@ -83,24 +83,34 @@ impl Config {
8383
// return Some(value)
8484
// }
8585

86-
if let Some(value) = self.preview.get_value(key) {
86+
if let Some(value) = table::get_value(&self.preview, key) {
8787
// self.resolved.set_value(key, value.clone());
8888
return Some(value)
8989
}
9090

91-
if let Some(value) = self.arguments.get_value(key) {
91+
if let Some(value) = table::get_value(&self.arguments, key) {
9292
// self.resolved.set_value(key, value.clone());
9393
return Some(value)
9494
}
9595

96-
if let Some(value) = self.base.get_value(key) {
96+
if let Some(value) = table::get_value(&self.base, key) {
9797
// self.resolved.set_value(key, value.clone());
9898
return Some(value)
9999
}
100100

101101
None
102102
}
103103

104+
pub fn get_bool(&self, key: &str) -> Option<bool> {
105+
self.get_value(key)
106+
.and_then(Value::as_bool)
107+
}
108+
109+
pub fn get_string(&self, key: &str) -> Option<&str> {
110+
self.get_value(key)
111+
.and_then(Value::as_str)
112+
}
113+
104114
// pub fn get_value_or(&mut self, key: &str, default: impl Into<Value>) -> &Value {
105115
// }
106116
}

toybox-cfg/src/table.rs

Lines changed: 45 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,117 +1,70 @@
1-
use std::collections::HashMap;
21
use std::path::Path;
32

3+
use toml::{Table, Value};
44
use toybox_vfs::{Vfs, PathKind};
55

6+
// /// Copy or replace values present in `other`
7+
// pub fn merge_from(&mut self, _other: &Table) {
8+
// todo!()
9+
// }
610

7-
#[derive(Debug, Clone, Default)]
8-
pub struct Table {
9-
data: HashMap<String, Value>,
10-
}
11-
12-
13-
impl Table {
14-
pub fn new() -> Table {
15-
Table::default()
16-
}
17-
18-
pub fn from_file(vfs: &Vfs, kind: PathKind, path: impl AsRef<Path>) -> anyhow::Result<Table> {
19-
let data = vfs.load_string(kind, path)?;
20-
let raw: toml::Table = toml::from_str(&data)?;
21-
let _ = dbg!(raw);
11+
// /// Recursively remove values from this table that are present in `other`
12+
// pub fn remove_values_in(&mut self, _other: &Table) {
13+
// todo!()
14+
// }
2215

23-
Ok(Table::default())
24-
}
2516

26-
pub fn from_cli() -> anyhow::Result<Table> {
27-
let mut args = std::env::args();
28-
let _ = args.next(); // skip first arg
2917

30-
let _ = dbg!(args);
31-
32-
Ok(Table::default())
33-
}
34-
35-
pub fn save_to_file(&self, vfs: &Vfs, kind: PathKind, path: impl AsRef<Path>) -> anyhow::Result<()> {
36-
let toml = self.to_toml();
37-
let string = toml::to_string_pretty(&toml)?;
38-
vfs.save_data(kind, path, &string)
39-
}
18+
pub fn load_from_vfs(vfs: &Vfs, kind: PathKind, path: impl AsRef<Path>) -> anyhow::Result<Table> {
19+
let data = vfs.load_string(kind, path)?;
20+
toml::from_str(&data).map_err(Into::into)
21+
}
4022

41-
/// Copy or replace values present in `other`
42-
pub fn merge_from(&mut self, _other: &Table) {
43-
todo!()
44-
}
23+
pub fn load_from_cli() -> anyhow::Result<Table> {
24+
let mut args = std::env::args();
25+
let _ = args.next(); // skip first arg
4526

46-
/// Recursively remove values from this table that are present in `other`
47-
pub fn remove_values_in(&mut self, _other: &Table) {
48-
todo!()
49-
}
27+
let mut table = Table::default();
5028

51-
pub fn get_value(&self, key: &str) -> Option<&Value> {
52-
if let Some((key, tail)) = key.split_once('.') {
53-
let subtable = self.data.get(key)?
54-
.as_table()?;
29+
for arg in args {
30+
let Some((key, value_str)) = arg.split_once('=') else {
31+
log::warn!("Failed to parse CLI argument: '{arg}'");
32+
continue
33+
};
5534

56-
subtable.get_value(tail)
57-
} else {
58-
self.data.get(key)
59-
}
35+
set_value(&mut table, key.trim(), Value::String(value_str.trim().into()));
6036
}
6137

62-
pub fn set_value(&mut self, key: &str, value: Value) {
63-
if let Some((key, tail)) = key.split_once('.') {
64-
let subtable = self.data.entry(key.into())
65-
.or_insert(Value::Table(Default::default()))
66-
.as_table_mut()
67-
.expect("Trying to add value to non-table value");
68-
69-
subtable.set_value(tail, value);
70-
71-
} else {
72-
self.data.insert(key.into(), value);
73-
}
74-
}
38+
Ok(table)
39+
}
7540

76-
fn to_toml(&self) -> toml::Table {
77-
let mut tbl = toml::Table::new();
41+
pub fn save_to_vfs(table: &Table, vfs: &Vfs, kind: PathKind, path: impl AsRef<Path>) -> anyhow::Result<()> {
42+
let string = toml::to_string_pretty(table)?;
43+
vfs.save_data(kind, path, &string)
44+
}
7845

79-
for (key, value) in self.data.iter() {
80-
let value = match value {
81-
Value::String(string) => toml::Value::String(string.clone()),
82-
Value::Table(table) => toml::Value::Table(table.to_toml()),
83-
Value::Bool(b) => toml::Value::Boolean(*b),
84-
};
46+
pub fn get_value<'t>(table: &'t Table, key: &str) -> Option<&'t Value> {
47+
if let Some((key, tail)) = key.split_once('.') {
48+
let subtable = table.get(key)?
49+
.as_table()?;
8550

86-
tbl.insert(key.clone(), value);
87-
}
51+
get_value(subtable, tail)
8852

89-
tbl
53+
} else {
54+
table.get(key)
9055
}
9156
}
9257

58+
pub fn set_value(table: &mut Table, key: &str, value: Value) {
59+
if let Some((key, tail)) = key.split_once('.') {
60+
let subtable = table.entry(key)
61+
.or_insert(Value::Table(Default::default()))
62+
.as_table_mut()
63+
.expect("Trying to add value to non-table value");
9364

65+
set_value(subtable, tail, value);
9466

95-
96-
#[derive(Debug, Clone)]
97-
pub enum Value {
98-
String(String),
99-
Table(Table),
100-
Bool(bool),
101-
}
102-
103-
impl Value {
104-
pub fn as_table(&self) -> Option<&Table> {
105-
match self {
106-
Value::Table(tbl) => Some(tbl),
107-
_ => None
108-
}
109-
}
110-
111-
pub fn as_table_mut(&mut self) -> Option<&mut Table> {
112-
match self {
113-
Value::Table(tbl) => Some(tbl),
114-
_ => None
115-
}
67+
} else {
68+
table.insert(key.into(), value);
11669
}
11770
}

0 commit comments

Comments
 (0)