indexmap-rs/indexmap

Ordered Serialization

Closed this issue · 3 comments

Hi, rust noob here (couple of hours under my belt), trying to serialize a map with the same order as insertion, but unable to do so:

error[E0432]: unresolved import `indexmap::map::serde_seq`
  --> src/main.rs:3:5
   |
3  | use indexmap::map::serde_seq;
   |     ^^^^^^^^^^^^^^^^^^^^^^^^ no `serde_seq` in `map`
   |
note: found an item that was configured out
  --> /home/makina/.cargo/registry/src/index.crates.io-6f17d22bba15001f/indexmap-2.0.2/src/map.rs:10:9
   |
10 | pub mod serde_seq;
   |         ^^^^^^^^^
   = note: the item is gated behind the `serde` feature

Here the sample code:

use indexmap::IndexMap;
use indexmap::map::serde_seq;


#[derive(Serialize)]
struct MyStruct {
 #[serde(with = "indexmap::map::serde_seq")]
 data: IndexMap<String, String>,
}

 let mut map = IndexMap::new();

 map.insert(String::from("banana"), String::from("1"));
 map.insert(String::from("apple"), String::from("3"));
 let my_struct = MyStruct { data: map };
 let serialized = serde_json::to_string(&my_struct).expect("Serialization failed");
 println!("{}", serialized);

My cargo:

[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
indexmap = { version = "2.0.2", feature = ["serde"] }

From this documentation, I understood that I should be able to serialize with order.

Many thanks in advance.

Your example works for me, after adding use serde::Serialize; and wrapping the code starting at let in fn main(). Are you perhaps using multiple workspaces where the features are not the same in all instances?

Also, you don't need use indexmap::map::serde_seq; if you're also writing that full path in the serde(with = ...), so you could either remove that use or change to serde(with = "serde_seq"). (But that's just an "unused" warning as-is.)

The serde_seq mode will serialize as a list of key-value pairs, like:

{"data":[["banana","1"],["apple","3"]]}

If you want it to look like a JSON object with order, there's a serde_json feature "preserve_order" for that, which even uses IndexMap itself! Then without the serde(with) annotation, the default serialization output in-order looks like:

{"data":{"banana":"1","apple":"3"}}

Actually, I think that "preserve_order" feature only matters for serde_json::Map as found in its generic Value representation. When you serialize directly to_string, it seems to preserve the order regardless.

Feel free to reopen if you have further questions!