agent_block_mcp/
lua_json.rs1use mlua::prelude::*;
9
10pub fn lua_to_json(_lua: &Lua, val: LuaValue) -> LuaResult<serde_json::Value> {
17 lua_to_json_inner(&val, 0)
18}
19
20fn lua_to_json_inner(val: &LuaValue, depth: usize) -> LuaResult<serde_json::Value> {
21 const MAX_DEPTH: usize = 128;
22 if depth > MAX_DEPTH {
23 return Err(LuaError::external(format!(
24 "Lua table nesting too deep for JSON (limit: {MAX_DEPTH})"
25 )));
26 }
27 match val {
28 LuaValue::Nil => Ok(serde_json::Value::Null),
29 LuaValue::LightUserData(u) if u.0.is_null() => Ok(serde_json::Value::Null),
32 LuaValue::Boolean(b) => Ok(serde_json::Value::Bool(*b)),
33 LuaValue::Integer(i) => Ok(serde_json::Value::Number((*i).into())),
34 LuaValue::Number(n) => serde_json::Number::from_f64(*n)
35 .map(serde_json::Value::Number)
36 .ok_or_else(|| LuaError::external(format!("cannot convert {n} to JSON number"))),
37 LuaValue::String(s) => Ok(serde_json::Value::String(s.to_str()?.to_string())),
38 LuaValue::Table(t) => {
39 let len = t.raw_len();
40 if len > 0 {
41 let mut arr = Vec::with_capacity(len);
42 for i in 1..=len {
43 let v: LuaValue = t.raw_get(i)?;
44 arr.push(lua_to_json_inner(&v, depth + 1)?);
45 }
46 Ok(serde_json::Value::Array(arr))
47 } else {
48 let mut map = serde_json::Map::new();
49 for pair in t.clone().pairs::<LuaValue, LuaValue>() {
50 let (k, v) = pair?;
51 let key = match k {
52 LuaValue::String(s) => s.to_str()?.to_string(),
53 LuaValue::Integer(i) => i.to_string(),
54 LuaValue::Number(n) => n.to_string(),
55 other => {
56 return Err(LuaError::external(format!(
57 "unsupported table key type for JSON: {}",
58 other.type_name()
59 )));
60 }
61 };
62 map.insert(key, lua_to_json_inner(&v, depth + 1)?);
63 }
64 Ok(serde_json::Value::Object(map))
65 }
66 }
67 other => Err(LuaError::external(format!(
68 "unsupported type for JSON conversion: {}",
69 other.type_name()
70 ))),
71 }
72}
73
74pub fn json_to_lua(lua: &Lua, val: serde_json::Value) -> LuaResult<LuaValue> {
89 json_to_lua_inner(lua, &val, 0)
90}
91
92fn json_to_lua_inner(lua: &Lua, val: &serde_json::Value, depth: usize) -> LuaResult<LuaValue> {
93 const MAX_DEPTH: usize = 128;
94 if depth > MAX_DEPTH {
95 return Err(LuaError::external(format!(
96 "JSON nesting too deep (limit: {MAX_DEPTH})"
97 )));
98 }
99 match val {
100 serde_json::Value::Null => Ok(LuaValue::NULL),
101 serde_json::Value::Bool(b) => Ok(LuaValue::Boolean(*b)),
102 serde_json::Value::Number(n) => {
103 if let Some(i) = n.as_i64() {
104 Ok(LuaValue::Integer(i))
105 } else if let Some(f) = n.as_f64() {
106 Ok(LuaValue::Number(f))
107 } else {
108 Err(LuaError::external(format!(
109 "JSON number {n} is not representable as i64 or f64"
110 )))
111 }
112 }
113 serde_json::Value::String(s) => lua.create_string(s).map(LuaValue::String),
114 serde_json::Value::Array(arr) => {
115 let table = lua.create_table()?;
116 for (i, v) in arr.iter().enumerate() {
117 table.set(i + 1, json_to_lua_inner(lua, v, depth + 1)?)?;
118 }
119 Ok(LuaValue::Table(table))
120 }
121 serde_json::Value::Object(map) => {
122 let table = lua.create_table()?;
123 for (k, v) in map {
124 table.set(k.as_str(), json_to_lua_inner(lua, v, depth + 1)?)?;
125 }
126 Ok(LuaValue::Table(table))
127 }
128 }
129}