Skip to content

Commit

Permalink
feat: Add support for setting/adding entire tables/arrays (#40)
Browse files Browse the repository at this point in the history
  • Loading branch information
simifalaye authored Oct 31, 2024
1 parent 29cf397 commit caee16f
Show file tree
Hide file tree
Showing 2 changed files with 166 additions and 47 deletions.
91 changes: 75 additions & 16 deletions spec/parse_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -79,39 +79,98 @@ describe("parse", function()
local expected = toml_content:format("2.0.0")
assert.equal(expected, tostring(result))
end)
it("Can add value to table", function()
local toml_content = [[
[rocks.neorg]
version = "1.0.0"
]]
local result = toml_edit.parse(toml_content)
local rock = result.rocks.neorg
rock.opt = false
local expected = [[
[rocks.neorg]
version = "1.0.0"
opt = false
]]
assert.equal(expected, tostring(result))
end)
it("Can set entire table", function()
local toml_content = [[
[rocks]
[rocks.neorg]
version = "1.0.0"
]]
local result = toml_edit.parse(toml_content)
result.rocks = {
neorg = { version = "2.0.0", pin = true },
}
local expected = [[
[rocks]
[rocks.neorg]
version = "2.0.0"
pin = true
]]
assert.equal(expected, tostring(result))
end)
it("Can add entire table", function()
local result = toml_edit.parse([[]])
result.rocks = {
neorg = { version = "2.0.0", pin = true },
}
local expected = [[
[rocks]
[rocks.neorg]
version = "2.0.0"
pin = true
]]
assert.equal(expected, tostring(result))
end)
it("Can set value in array", function()
local toml_content = [[
my_arr = ["%s", "item2"]
]]
my_arr = ["%s", "item2"]
]]
local result = toml_edit.parse(toml_content)
result.my_arr[1] = "item1_changed"
local expected = toml_content:format("item1_changed")
assert.equal(expected, tostring(result))
end)
it("Can add value to array", function()
local toml_content = [[
my_arr = ["item1", "item2"]
]]
my_arr = ["item1", "item2"]
]]
local result = toml_edit.parse(toml_content)
result.my_arr[3] = "item3"
local new_toml_content = [[
my_arr = ["item1", "item2", "%s"]
]]
local expected = new_toml_content:format("item3")
local expected = [[
my_arr = ["item1", "item2", "item3"]
]]
assert.equal(expected, tostring(result))
end)
it("Can add value to table", function()
it("Can set entire array", function()
local toml_content = [[
[rocks.neorg]
version = "1.0.0"
my_arr = ["item1", "item2"]
]]
local result = toml_edit.parse(toml_content)
local rock = result.rocks.neorg
rock.opt = false
result.my_arr = { "new_item1", "new_item2" }
local expected = [[
[rocks.neorg]
version = "1.0.0"
opt = false
my_arr = ["new_item1", "new_item2"]
]]
assert.equal(expected, tostring(result))
end)
it("Cannot use complex types in lists", function()
local result = toml_edit.parse([[]])
assert.error(function()
result.my_arr = { { "new_item1" }, { "new_item2" } }
end)
assert.equal([[]], tostring(result))
end)
it("Can add entire array", function()
local result = toml_edit.parse([[]])
result.my_arr = { "new_item1", "new_item2" }
local expected = [[
my_arr = ["new_item1", "new_item2"]
]]
assert.equal(expected, tostring(result))
end)
Expand Down
122 changes: 91 additions & 31 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,15 @@ where
toml_edit::Value::Float(float) => Ok(lua.to_value(&float.value())),
toml_edit::Value::Boolean(bool) => Ok(lua.to_value(&bool.value())),
_ => Err(mlua::Error::RuntimeError(format!(
"toml-edit: cannot parse {}: {} yet",
"toml-edit: expected value to be a basic value type in array, got {}: {}",
array_value.type_name(),
array_value
))),
},
None => Ok(Ok(Value::Nil)),
},
_ => Err(mlua::Error::RuntimeError(format!(
"toml-edit: expected value to be an array type {}: {}",
"toml-edit: expected value to be an array type, got {}: {}",
value.type_name(),
value
))),
Expand Down Expand Up @@ -241,6 +241,7 @@ where
path.push(key.to_str()?.to_string());

let mut binding = table_newindex_document.borrow_mut();
let mut created_last_entry = false;
let entry: &mut toml_edit::Item =
path.clone()
.into_iter()
Expand All @@ -252,6 +253,7 @@ where
let entry = entry.as_table_like_mut().unwrap();

if entry.get_mut(next_key.as_str()).is_none() {
created_last_entry = true;
entry.insert(
next_key.as_str(),
toml_edit::Item::Table(toml_edit::Table::default()),
Expand All @@ -261,38 +263,96 @@ where
entry.get_mut(next_key.as_str()).unwrap()
});

*entry = match value {
Value::Nil => toml_edit::Item::None,
Value::String(str) => toml_edit::value(str.to_str()?.to_string()),
Value::Number(number) => {
toml_edit::value(lua.from_value::<mlua::Number>(Value::Number(number))?)
}
Value::Integer(int) => {
toml_edit::value(lua.from_value::<mlua::Integer>(Value::Integer(int))?)
fn convert_lua_value_to_toml_item<'lua>(
lua: &'lua Lua,
value: &Value,
is_parent_array: bool,
) -> Result<toml_edit::Item> {
match value {
Value::Nil => Ok(toml_edit::Item::None),
Value::String(str) => Ok(toml_edit::value(str.to_str()?.to_string())),
Value::Number(number) => Ok(toml_edit::value(
lua.from_value::<mlua::Number>(Value::Number(*number))?,
)),
Value::Integer(int) => Ok(toml_edit::value(
lua.from_value::<mlua::Integer>(Value::Integer(*int))?,
)),
Value::Boolean(bool) => Ok(toml_edit::value(*bool)),
Value::Table(table) => {
if is_parent_array {
return Err(mlua::Error::MetaMethodTypeError {
method: "__newindex".into(),
type_name: value.type_name(),
message: Some("only basic value types allowed in lists".into()),
});
}
// Determine if table is array by checking the keys
let mut is_array = true;
for table_pair in table.clone().pairs::<Value, Value>() {
let (table_key, _) = table_pair?;
if !table_key.is_integer() {
is_array = false;
break;
}
}
if is_array {
let mut item = toml_edit::Item::Value(toml_edit::Value::Array(
toml_edit::Array::default(),
));
for array_value in table.clone().sequence_values::<Value>() {
if let Some(toml_value) = convert_lua_value_to_toml_item(
lua,
&array_value.clone()?,
true,
)?
.as_value()
{
item.as_array_mut().unwrap().push(toml_value);
}
}
Ok(item)
} else {
let mut item = toml_edit::Item::Table(toml_edit::Table::default());
for table_pair in table.clone().pairs::<Value, Value>() {
let (table_key, table_value) = table_pair?;
if let Value::String(table_key_str) = table_key {
let _ = item.as_table_mut().unwrap().insert(
table_key_str.to_str()?,
convert_lua_value_to_toml_item(
lua,
&table_value,
false,
)?,
);
}
}
Ok(item)
}
}
_ => {
return Err(mlua::Error::MetaMethodTypeError {
method: "__newindex".into(),
type_name: value.type_name(),
message: Some(
"provided type is not allowed in TOML document".into(),
),
});
}
}
Value::Boolean(bool) => toml_edit::value(bool),
Value::Table(_table) => {
// Update state data within Lua
// for pair in tbl.pairs() {
// let (key, value): (mlua::Value, mlua::Value) = pair?;

// table.set(key, value)?;
// }

// TODO: The previous invocations just updated everything, so make this now
// return a table that allows access to those values.
toml_edit::Item::Table(toml_edit::Table::default())
}

match convert_lua_value_to_toml_item(lua, &value, false) {
Ok(item) => {
*entry = item;
Ok(())
}
_ => {
return Err(mlua::Error::MetaMethodTypeError {
method: "__newindex".into(),
type_name: value.type_name(),
message: Some("provided type is not allowed in TOML document".into()),
})
Err(e) => {
if created_last_entry {
*entry = toml_edit::Item::None;
}
Err(e)
}
};

Ok(())
}
},
)?,
)?;
Expand Down

0 comments on commit caee16f

Please sign in to comment.