mlua-json 1.0.1

A Rust-native implementation of LuaRocks openresty/lua-cjson or grafi/lunajson for mlua.
use mlua::{Error, ExternalError, Lua, Value};
use std::collections::HashMap;

pub fn encode(_lua: &Lua, value: &Value) -> Result<Option<String>, Error> {
    if value.is_nil() {
        Ok(None)
    } else if value.is_boolean() {
        Ok(Some(value.as_boolean().unwrap().to_string()))
    } else if value.is_integer() {
        Ok(Some(value.as_integer().unwrap().to_string()))
    } else if value.is_number() {
        Ok(Some(value.as_number().unwrap().to_string()))
    } else if value.is_string() {
        Ok(Some(serde_json::to_string(&value).map_err(|e| e.into_lua_err())?))
    } else if value.is_table() {
        let res_json = serde_json::to_string(&value).map_err(|e| e.into_lua_err())?;
        let m: HashMap<serde_json::Value, serde_json::Value> =
            serde_json::from_str(&res_json).map_err(|e| e.into_lua_err())?;
        Ok(Some(serde_json::to_string(&m).map_err(|e| e.into_lua_err())?))
    } else {
        Ok(None)
    }
}

#[cfg(test)]
mod tests {
    use mlua::Lua;
    use std::error::Error;

    #[test]
    fn can_encode_a_boolean() -> Result<(), Box<dyn Error>> {
        let lua = Lua::new();
        crate::preload(&lua)?;
        let result: String = lua
            .load(
                r#"
                local json = require('json')
                return json.encode(true)
            "#,
            )
            .eval()?;
        assert_eq!(result, "true");
        Ok(())
    }

    #[test]
    fn can_encode_a_nil() -> Result<(), Box<dyn Error>> {
        let lua = Lua::new();
        crate::preload(&lua)?;
        let result: Option<String> = lua
            .load(
                r#"
                local json = require('json')
                return json.encode(nil)
            "#,
            )
            .eval()?;
        assert!(result.is_none());
        Ok(())
    }

    #[test]
    fn can_encode_a_number() -> Result<(), Box<dyn Error>> {
        let lua = Lua::new();
        crate::preload(&lua)?;
        let result: String = lua
            .load(
                r#"
                local json = require('json')
                return json.encode(123)
            "#,
            )
            .eval()?;
        assert_eq!(result, "123");
        Ok(())
    }

    #[test]
    fn can_encode_a_string() -> Result<(), Box<dyn Error>> {
        let lua = Lua::new();
        crate::preload(&lua)?;
        let result: String = lua
            .load(
                r#"
                local json = require('json')
                return json.encode('abc')
            "#,
            )
            .eval()?;
        assert_eq!(result, "\"abc\"");
        Ok(())
    }

    #[test]
    fn can_encode_a_table() -> Result<(), Box<dyn Error>> {
        let lua = Lua::new();
        crate::preload(&lua)?;
        let result: String = lua
            .load(
                r#"
                local json = require('json')
                return json.encode({abc = '123', def = 456, ghi = true, jkl = {7,8,9}})
            "#,
            )
            .eval()?;
        assert!(result.contains(r#""abc":"123""#));
        assert!(result.contains(r#""def":456"#));
        assert!(result.contains(r#""ghi":true"#));
        assert!(result.contains(r#""jkl":[7,8,9]"#));
        Ok(())
    }
}