Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the Rust equivalent of a JavaScript object when encoding with msgpack?

Tags:

rust

msgpack

I'm trying to port a JavaScript library which uses msgpack for encoding JavaScript objects to Rust. I found a Rust library for msgpack encoding/decoding, but I don't get what is the equivalent input format in Rust.

This JavaScript code for encoding the object {"a": 5, "b": 6} gives the output 82 a1 61 03 a1 62 05:

const msgpack = require("msgpack-lite");
msgpack.encode(obj);

I tried representing the object as a Rust struct and encoding it using rmp-serde library

use rmp_serde::{Deserializer, Serializer};
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
pub struct Test {
    a: u32,
    b: u32,
}

fn main() {
    let mut buf = Vec::new();
    let val = Test { a: 3, b: 5 };
    val.serialize(&mut Serializer::new(&mut buf)).unwrap();
    println!("{:?}", buf);
}

I get the output [146, 3, 5]. How do I represent JSON input in Rust?

like image 845
pd176 Avatar asked Nov 30 '25 04:11

pd176


2 Answers

What is the Rust equivalent of a JavaScript object

That is a HashMap:

use rmp_serde::{Deserializer, Serializer, encode::StructMapWriter};
use serde::{Deserialize, Serialize};

use std::collections::HashMap;

#[derive(Debug, Serialize, Deserialize)]
pub struct Test {
    a: u32,
    b: u32,
}

fn main() {
    let mut buf = Vec::new();
    let mut val = HashMap::new();
    val.insert("a", 3);
    val.insert("b", 5);
    val.serialize(&mut Serializer::new(&mut buf)).unwrap();
    println!("{:x?}", buf);

    let test: Test = Deserialize::deserialize(&mut Deserializer::new(&buf[..])).unwrap();

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

    buf.clear();
    test.serialize(&mut Serializer::with(&mut buf, StructMapWriter))
        .unwrap();

    println!("{:x?}", buf);
}

This gives the expected output:

[82, a1, 61, 3, a1, 62, 5]
Test { a: 3, b: 5 }
[82, a1, 61, 3, a1, 62, 5]

As you can see, you can deserialize into something other than a HashMap but serialization will not produce the same thing because you "lost" the information that it was a HashMap. The default of rmp is to use compact serialization ("This is the default constructor, which returns a serializer that will serialize structs using compact tuple representation, without field names."), but you can tell to rmp to serialize it differently if you need to with StructMapWriter.

like image 141
Stargateur Avatar answered Dec 05 '25 07:12

Stargateur


There is actually much cleaner and convenient way of achieving the same goal. Suppose you have a struct that has different types for different values:

use rmp_serde::{Deserializer, Serializer};
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
pub struct Test {
    a: u32,
    b: String,
}

To serialize it like a json object, you'll need to:

fn main() {
    let mut buf = Vec::new();
    let val = Test { a: 3, b: "hello world".into() };
    val.serialize(&mut Serializer::new(&mut buf).with_struct_map()).unwrap();
}
like image 35
A V Avatar answered Dec 05 '25 06:12

A V



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!