lune_std_serde/
encode_decode.rs1use mlua::prelude::*;
2
3use serde_json::Value as JsonValue;
4use serde_yaml2::wrapper::YamlNodeWrapper as YamlValue;
5use toml::Value as TomlValue;
6
7const LUA_SERIALIZE_OPTIONS: LuaSerializeOptions = LuaSerializeOptions::new()
9 .set_array_metatable(false)
10 .serialize_none_to_null(false)
11 .serialize_unit_to_null(false);
12
13const LUA_DESERIALIZE_OPTIONS: LuaDeserializeOptions = LuaDeserializeOptions::new()
15 .sort_keys(true)
16 .deny_recursive_tables(false)
17 .deny_unsupported_types(true);
18
19#[derive(Debug, Clone, Copy)]
25pub enum EncodeDecodeFormat {
26 Json,
27 JsonC,
28 Yaml,
29 Toml,
30}
31
32impl FromLua for EncodeDecodeFormat {
33 fn from_lua(value: LuaValue, _: &Lua) -> LuaResult<Self> {
34 if let LuaValue::String(s) = &value {
35 match s.to_string_lossy().to_ascii_lowercase().trim() {
36 "json" => Ok(Self::Json),
37 "jsonc" => Ok(Self::JsonC),
38 "yaml" => Ok(Self::Yaml),
39 "toml" => Ok(Self::Toml),
40 kind => Err(LuaError::FromLuaConversionError {
41 from: value.type_name(),
42 to: "EncodeDecodeFormat".to_string(),
43 message: Some(format!(
44 "Invalid format '{kind}', valid formats are: json, yaml, toml"
45 )),
46 }),
47 }
48 } else {
49 Err(LuaError::FromLuaConversionError {
50 from: value.type_name(),
51 to: "EncodeDecodeFormat".to_string(),
52 message: None,
53 })
54 }
55 }
56}
57
58#[derive(Debug, Clone, Copy)]
64pub struct EncodeDecodeConfig {
65 pub format: EncodeDecodeFormat,
66 pub pretty: bool,
67}
68
69impl From<EncodeDecodeFormat> for EncodeDecodeConfig {
70 fn from(format: EncodeDecodeFormat) -> Self {
71 Self {
72 format,
73 pretty: false,
74 }
75 }
76}
77
78impl From<(EncodeDecodeFormat, bool)> for EncodeDecodeConfig {
79 fn from(value: (EncodeDecodeFormat, bool)) -> Self {
80 Self {
81 format: value.0,
82 pretty: value.1,
83 }
84 }
85}
86
87pub fn encode(value: LuaValue, lua: &Lua, config: EncodeDecodeConfig) -> LuaResult<LuaString> {
95 let bytes = match config.format {
96 EncodeDecodeFormat::Json | EncodeDecodeFormat::JsonC => {
97 let serialized: JsonValue = lua.from_value_with(value, LUA_DESERIALIZE_OPTIONS)?;
98 if config.pretty {
99 serde_json::to_vec_pretty(&serialized).into_lua_err()?
100 } else {
101 serde_json::to_vec(&serialized).into_lua_err()?
102 }
103 }
104 EncodeDecodeFormat::Yaml => {
105 let serialized: YamlValue = lua.from_value_with(value, LUA_DESERIALIZE_OPTIONS)?;
106 serde_yaml2::to_string(serialized)
107 .into_lua_err()?
108 .into_bytes()
109 }
110 EncodeDecodeFormat::Toml => {
111 let serialized: TomlValue = lua.from_value_with(value, LUA_DESERIALIZE_OPTIONS)?;
112 let s = if config.pretty {
113 toml::to_string_pretty(&serialized).into_lua_err()?
114 } else {
115 toml::to_string(&serialized).into_lua_err()?
116 };
117 s.as_bytes().to_vec()
118 }
119 };
120 lua.create_string(bytes)
121}
122
123pub fn decode(
131 bytes: impl AsRef<[u8]>,
132 lua: &Lua,
133 config: EncodeDecodeConfig,
134) -> LuaResult<LuaValue> {
135 let bytes = bytes.as_ref();
136 match config.format {
137 EncodeDecodeFormat::Json => {
138 let value: JsonValue = serde_json::from_slice(bytes).into_lua_err()?;
139 lua.to_value_with(&value, LUA_SERIALIZE_OPTIONS)
140 }
141 EncodeDecodeFormat::JsonC => {
142 let string: String = String::from_utf8(bytes.to_vec()).into_lua_err()?;
143 let value: JsonValue =
144 jsonc_parser::parse_to_serde_value(&string, &jsonc_parser::ParseOptions::default())
145 .map(|v| v.unwrap_or(JsonValue::Null))
146 .into_lua_err()?;
147 lua.to_value_with(&value, LUA_SERIALIZE_OPTIONS)
148 }
149 EncodeDecodeFormat::Yaml => {
150 let string: String = String::from_utf8(bytes.to_vec()).into_lua_err()?;
151 let value: YamlValue = serde_yaml2::from_str(&string).into_lua_err()?;
152 lua.to_value_with(&value, LUA_SERIALIZE_OPTIONS)
153 }
154 EncodeDecodeFormat::Toml => {
155 if let Ok(s) = String::from_utf8(bytes.to_vec()) {
156 let value: TomlValue = toml::from_str(&s).into_lua_err()?;
157 lua.to_value_with(&value, LUA_SERIALIZE_OPTIONS)
158 } else {
159 Err(LuaError::RuntimeError(
160 "TOML must be valid utf-8".to_string(),
161 ))
162 }
163 }
164 }
165}