1use anyhow::Context;
2use config::{
3 any_err, get_or_create_module, get_or_create_sub_module, materialize_to_lua_value,
4 serialize_options,
5};
6use mlua::{Lua, LuaSerdeExt, Value as LuaValue};
7use serde_json::Value as JValue;
8
9pub fn register(lua: &Lua) -> anyhow::Result<()> {
10 let serde_mod = get_or_create_sub_module(lua, "serde")?;
11 let kumo_mod = get_or_create_module(lua, "kumo")?;
12
13 serde_mod.set("json_load", lua.create_async_function(json_load)?)?;
14 serde_mod.set("json_parse", lua.create_function(json_parse)?)?;
15 serde_mod.set("json_encode", lua.create_function(json_encode)?)?;
16 serde_mod.set(
17 "json_encode_pretty",
18 lua.create_function(json_encode_pretty)?,
19 )?;
20
21 serde_mod.set("toml_load", lua.create_async_function(toml_load)?)?;
22 serde_mod.set("toml_parse", lua.create_function(toml_parse)?)?;
23 serde_mod.set("toml_encode", lua.create_function(toml_encode)?)?;
24 serde_mod.set(
25 "toml_encode_pretty",
26 lua.create_function(toml_encode_pretty)?,
27 )?;
28
29 serde_mod.set("yaml_load", lua.create_async_function(yaml_load)?)?;
30 serde_mod.set("yaml_parse", lua.create_function(yaml_parse)?)?;
31 serde_mod.set("yaml_encode", lua.create_function(yaml_encode)?)?;
32 kumo_mod.set("json_load", lua.create_async_function(json_load)?)?;
37 kumo_mod.set("json_parse", lua.create_function(json_parse)?)?;
38 kumo_mod.set("json_encode", lua.create_function(json_encode)?)?;
39 kumo_mod.set(
40 "json_encode_pretty",
41 lua.create_function(json_encode_pretty)?,
42 )?;
43
44 kumo_mod.set("toml_load", lua.create_async_function(toml_load)?)?;
45 kumo_mod.set("toml_parse", lua.create_function(toml_parse)?)?;
46 kumo_mod.set("toml_encode", lua.create_function(toml_encode)?)?;
47 kumo_mod.set(
48 "toml_encode_pretty",
49 lua.create_function(toml_encode_pretty)?,
50 )?;
51
52 Ok(())
53}
54
55async fn json_load(lua: Lua, file_name: String) -> mlua::Result<LuaValue> {
56 let data = tokio::fs::read(&file_name)
57 .await
58 .with_context(|| format!("reading file {file_name}"))
59 .map_err(any_err)?;
60
61 let stripped = json_comments::StripComments::new(&*data);
62
63 let obj: serde_json::Value = serde_json::from_reader(stripped)
64 .with_context(|| format!("parsing {file_name} as json"))
65 .map_err(any_err)?;
66 lua.to_value_with(&obj, serialize_options())
67}
68
69fn json_parse(lua: &Lua, text: String) -> mlua::Result<LuaValue> {
70 let stripped = json_comments::StripComments::new(text.as_bytes());
71 let obj: serde_json::Value = serde_json::from_reader(stripped)
72 .with_context(|| format!("parsing {text} as json"))
73 .map_err(any_err)?;
74 lua.to_value_with(&obj, serialize_options())
75}
76
77fn json_encode(lua: &Lua, value: LuaValue) -> mlua::Result<String> {
78 let value = materialize_to_lua_value(lua, value)?;
79 serde_json::to_string(&value).map_err(any_err)
80}
81
82fn json_encode_pretty(lua: &Lua, value: LuaValue) -> mlua::Result<String> {
83 let value = materialize_to_lua_value(lua, value)?;
84 let value = serde_json::to_value(&value).map_err(any_err)?;
90 serde_json::to_string_pretty(&value).map_err(any_err)
91}
92
93async fn toml_load(lua: Lua, file_name: String) -> mlua::Result<LuaValue> {
94 let data = tokio::fs::read_to_string(&file_name)
95 .await
96 .with_context(|| format!("reading file {file_name}"))
97 .map_err(any_err)?;
98
99 let obj: toml::Value = toml::from_str(&data)
100 .with_context(|| format!("parsing {file_name} as toml"))
101 .map_err(any_err)?;
102 lua.to_value_with(&obj, serialize_options())
103}
104
105fn toml_parse(lua: &Lua, toml: String) -> mlua::Result<LuaValue> {
106 let obj: toml::Value = toml::from_str(&toml)
107 .with_context(|| format!("parsing {toml} as toml"))
108 .map_err(any_err)?;
109 lua.to_value_with(&obj, serialize_options())
110}
111
112fn toml_encode(lua: &Lua, value: LuaValue) -> mlua::Result<String> {
113 let value = materialize_to_lua_value(lua, value)?;
114 toml::to_string(&value).map_err(any_err)
115}
116
117fn toml_encode_pretty(lua: &Lua, value: LuaValue) -> mlua::Result<String> {
118 let value = materialize_to_lua_value(lua, value)?;
119 toml::to_string_pretty(&value).map_err(any_err)
120}
121
122async fn yaml_load(lua: Lua, file_name: String) -> mlua::Result<LuaValue> {
123 let data = tokio::fs::read(&file_name)
124 .await
125 .with_context(|| format!("reading file {file_name}"))
126 .map_err(any_err)?;
127
128 let value: JValue = serde_yaml::from_slice(&data)
129 .with_context(|| format!("parsing {file_name} as yaml"))
130 .map_err(any_err)?;
131 lua.to_value_with(&value, serialize_options())
132}
133
134fn yaml_parse(lua: &Lua, text: String) -> mlua::Result<LuaValue> {
135 let value: JValue = serde_yaml::from_str(&text)
136 .with_context(|| format!("parsing {text} as yaml"))
137 .map_err(any_err)?;
138 lua.to_value_with(&value, serialize_options())
139}
140
141fn yaml_encode(lua: &Lua, value: LuaValue) -> mlua::Result<String> {
142 let value = materialize_to_lua_value(lua, value)?;
143 serde_yaml::to_string(&value).map_err(any_err)
144}