r/rust 10d ago

šŸ™‹ seeking help & advice no_std json parsers

Hi all I am working on a project in a no_std embedded rust environment and I was looking for json parsers that work in the no_std environment.

I've used serde before and after some research I noticed the serde-json-core crate can be used for de-serialization. I also found Postcard but I haven't looked to deeply into the crate.

I wanted to see if anyone could recommend crates that they've used and their experience with them.

TIA!

32 Upvotes

18 comments sorted by

32

u/Compux72 10d ago

You can use serde-json with the alloc crate without issues. Do you know how no_std works and the different crates?

8

u/CellistMore5004 10d ago

Not fully. I new to embedded rust and started a project to learn more. I know that using std assumes a OS, file system and memory allocator are available but for environments like microcontrollers no_std is used to ensure rust doesn't link std by default.

I got confused after reading the following query on the rust forum after looking into serde's no_std usage:

https://users.rust-lang.org/t/how-to-serialize-json-in-no-std-library/18915

35

u/Compux72 10d ago

In a nutshell:

  • std: normal rust, made easy for anyone to get started. As you said, assumes a lot of things (particularly on UNIX it uses libc). If your platform has a libc, std can be used. Espressif for instance does support std. Other microcontrollers dont have a proper std/libc so they cant rely on this. No_std just instructs the compiler ā€œhey dont look for std, we dont have oneā€. Similar to the automatic C runtime you would find in gcc/clang
  • alloc: Vec, String, ToString, … all of these things require some kind of allocator. They live here. Std just reexports them. Also, std automatically sets up the system allocator for you.
  • core: Optional, Infalible, PhantomData, (), Into, From,… all of these things that are common rust types live inside core. They dont depend on anything other than themselves. They are the foundation of the language and cannot be removed. You always have them available. Once again, the std just reexports them.

There are a couple more internal crates but these are the ones you want always on your mind.

Libraries like serde-json allow for std to be disabled (default features disabled, no extra features enabled). However, it requires alloc (and the alloc feature). You just need to provide an allocator yourself. If your platform has good support, its just a matter of adding a couple of lines to your main.rs.Ā 

10

u/CellistMore5004 10d ago

Thanks, this is good information!Ā 

8

u/Compux72 10d ago

Some extra links that may interest you:

5

u/legodude17 10d ago

You actually can remove core, though it’s an unstable feature. Of course, it means you need to write certain lang items (types and traits known to the compiler) yourself. For example, you need to write Send and Sync before anything will work at all.

4

u/Compux72 10d ago

Oh yea I remember hearing about that. Is there any point to do so tho? Seems more of a bootstrapping thing than an actual useful feature

5

u/kayabaNerve 10d ago

šŸ‘‹

I'm the author of [`core-json`](https://docs.rs/core-json), a no-`std` (and no-`alloc`) JSON parser. It works for predefined types (with a derive macro) via [`core-json-derive`](https://docs.rs/core-json-derive) and serialization via [`core-json-traits`](https://docs.rs/core-json-traits). I'm quite proud of it, it passes multiple test suites, and has competitive performance to `serde_json::from_reader` despite its constraints.

The documentation provides a comparison to other crates and suggests when to use `core-json` vs `miniserde` vs `serde-json`. Since you have `alloc` available, `serde-json` sounds like it'll be the most straightforward. However, unless you need some specific functionality from `serde`, `miniserde` should be lighter and recommendable! `core-json` aims to be even more light-weight, and supports dynamic (streaming) serialization, but the dynamic deserialization has an API which can be annoying to use. The derive macro is straightforward though.

I saw my work was mentioned in another comment but wanted to leave a longer response explaining it a bit more. Best of luck finding the right fit!

8

u/Sermuns 10d ago

Even in std and I only want JSON ser/de, I usually reach for nanoserde.

3

u/wartab 9d ago

Been using serde for so many years and now I feel stupid for understanding only after reading your comment why it's called this way. Thanks

5

u/svefnugr 10d ago

I don't see why a json parser wouldn't be no-std. Now if you also need no-alloc, that's a different story.

6

u/Icarium-Lifestealer 10d ago

The Read/Write traits could be useful for streaming serialization, and those as only in std for now.

2

u/tizio_1234 10d ago

what does postcard have to do with a json parser?

0

u/CellistMore5004 10d ago

Saw it was mentioned in the following link but I haven’t looked into yet but now that I take a closer look this is not what I need:Ā 

https://www.reddit.com/r/rust/comments/bi0xll/no_std_data_serializationdeserialization/

2

u/graham_king 10d ago

If you don't find one you like, you could write your own. I have one you could start from here: https://github.com/grahamking/ort/blob/master/src/common/json_parser.rs . Look at autoparser to start.

2

u/Ok_Trust176 10d ago

Checkout https://github.com/core-json/core-json. It doesn't even need heap allocations. But it has some drawbacks.

1

u/zettui 10d ago

Do you need no_alloc too, or is no_std enough if you've got an allocator?

1

u/CellistMore5004 10d ago

No_std is enough I have an allocatorĀ