Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to convert json to mlua::Value like c-json.decode #419

Closed
cppcoffee opened this issue Jun 12, 2024 · 4 comments
Closed

How to convert json to mlua::Value like c-json.decode #419

cppcoffee opened this issue Jun 12, 2024 · 4 comments
Labels
question Further information is requested

Comments

@cppcoffee
Copy link

cppcoffee commented Jun 12, 2024

Example code, it will compile with an error:

fn main() {
    let s = r#"{"id":123,"name":"foo"}"#;
    let value: mlua::Value = serde_json::from_str(&s).unwrap();
    println!("{:?}", value);
}

The error messsage:

error[E0277]: the trait bound `LuaValue<'_>: serde::de::Deserialize<'_>` is not satisfied
    --> src/main.rs:3:30
     |
3    |     let value: mlua::Value = serde_json::from_str(&s).unwrap();
     |                              ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `serde::de::Deserialize<'_>` is not implemented for `LuaValue<'_>`
@cppcoffee
Copy link
Author

cppcoffee commented Jun 12, 2024

This usage is to register the json_decode function on the Lua side, so it can be used similarly to the c-json library:

local value = app.json_decode('{"id":123, "name":"foo"}')
print(value.name)

@cppcoffee
Copy link
Author

Finally, I solved the problem with a layer of intermediate transformations:

fn main() {
    let s = r#"
    {
        "id": 123,
        "name": "foo"
    }
    "#;

    let lua = mlua::Lua::new();
    let tmp: serde_json::Value = serde_json::from_str(&s).unwrap();
    let value = json_to_lua_value(&lua, tmp).unwrap();

    println!("{:?}", value);
}

fn json_to_lua_value(lua: &mlua::Lua, json_value: serde_json::Value) -> mlua::Result<mlua::Value> {
    match json_value {
        serde_json::Value::Null => Ok(mlua::Value::Nil),
        serde_json::Value::Bool(b) => Ok(mlua::Value::Boolean(b)),
        serde_json::Value::Number(n) => {
            if let Some(i) = n.as_i64() {
                Ok(mlua::Value::Integer(i))
            } else if let Some(f) = n.as_f64() {
                Ok(mlua::Value::Number(f))
            } else {
                Err(mlua::Error::RuntimeError("Invalid JSON number".into()))
            }
        }
        serde_json::Value::String(s) => Ok(mlua::Value::String(lua.create_string(s)?)),
        serde_json::Value::Array(arr) => {
            let table = lua.create_table()?;
            for (i, v) in arr.iter().enumerate() {
                table.set(i + 1, json_to_lua_value(lua, v.clone())?)?;
            }
            Ok(mlua::Value::Table(table))
        }
        serde_json::Value::Object(obj) => {
            let table = lua.create_table()?;
            for (k, v) in obj.iter() {
                table.set(k.as_str(), json_to_lua_value(lua, v.clone())?)?;
            }
            Ok(mlua::Value::Table(table))
        }
    }
}

@cppcoffee
Copy link
Author

cppcoffee commented Jun 12, 2024

Isn't there a better interface for this usage? That is, it can be converted directly, without the need for a middle layer conversion

@khvzak
Copy link
Member

khvzak commented Jun 12, 2024

Isn't there a better interface for this usage? That is, it can be converted directly, without the need for a middle layer conversion

Yes, use can use LuaSerdeExt::to_value.

An example: https://github.com/mlua-rs/mlua/blob/master/examples/serialize.rs#L49

@khvzak khvzak added the question Further information is requested label Jun 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants