7

How can I deserialise JSON {"arr":[1,2,3,4]} without performing a heap allocation using serde_json_core or similar? It performs one allocation currently. I see serde_json_core uses the heapless crate but I am unsure exactly how to make them work together.

#[derive(Deserialize)]
struct MyStruct {
    arr: Vec<u64>,
}

fn main() {
    let j = r#"{"arr":[1,2,3,4]}"#;

    let r: serde_json_core::de::Result<(MyStruct, usize)> = serde_json_core::from_str(j);
    let (out, _) = r.unwrap();

    println!("First value: {}.",  out.arr[0]);
}

I am using serde_json_core = 0.4.0.

9
  • 1
    Do you know the exact size of the array in advance? If so, you can simply deserialize to a fixed-sized array [u64; N]. If not, you need to decide on a maximum possible array size you want to be able to deserialize. You need to preallocate everything on the stack, so you can't support arbitrary sizes. Using Vec is not an option, since it will allocate if it contains any elements. Commented Nov 15, 2021 at 14:57
  • Thanks, I know the array must be less than or equal to 10 elements long. Unfortunately if I do [u64; 10] I get 'called 'Result::unwrap()' on an 'Err' value: CustomError'. I need the array size to be exactly 4 ([u64; 4]) to work. Commented Nov 15, 2021 at 15:14
  • For a variable size, you can't use a fixed-sized array. You need to use some stack-allocated vector-like data structure, e.g. heapless::Vec. You should be able to add use serde_json_core::heapless::Vec; to your code, and then add 10 as second template parameter to the Vec inside MyStruct. Commented Nov 15, 2021 at 15:40
  • That was my initial hope when using serde_json_core however the Deserialize trait is not implemented for all the varieties of heapless::Vec: the trait 'Deserialize<'_>' is not implemented for 'serde_json_core::heapless ::Vec<u64, 4_usize>. I could implement the Deserialize myself for the Vec capacity I want but was hoping I didn't have to do that. Commented Nov 15, 2021 at 17:21
  • 1
    You need to enable the serde feature for heapless to get the impl. Commented Nov 15, 2021 at 19:07

1 Answer 1

4

The serde-json-core crate can deserialize JSON arrays into any type that implements the Deserialize trait. If you want to avoid memory allocations, you need to pick a container that does not allocate.

If the size of the array is known in advance, you can simply use a fixed-sized array, i.e. [T; N]. This will return a deserialization error if the size of JSON array is not exactly N.

If the size of the JSON array is variable with a known upper limit, you can use one of various vector-like stack-allocated datastructures. One such option is the heapless::Vec, which implements Deserialize if you enable the serde feature for heapless. In your Cargo.yaml file, you can do this like this:

heapless = { version = "0.7", features = ["serde"] }

If you use the same version of heapless that your version of serde-json-core depends on, it will only be included in your build once.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.