diff --git a/sim/src/driving.rs b/sim/src/driving.rs index a863884348..ddb63c52d0 100644 --- a/sim/src/driving.rs +++ b/sim/src/driving.rs @@ -7,6 +7,7 @@ use geom::{Angle, Pt2D}; use intersections::{IntersectionPolicy, StopSign, TrafficSignal}; use map_model::{LaneID, LaneType, Map, TurnID}; use multimap::MultiMap; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std; use std::collections::{BTreeMap, HashSet, VecDeque}; use std::f64; @@ -214,10 +215,33 @@ pub struct DrivingSimState { // Using BTreeMap instead of HashMap so iteration is deterministic. pub(crate) cars: BTreeMap, lanes: Vec, + // See https://github.com/serde-rs/json/issues/402. + #[serde(serialize_with = "serialize_turn_map")] + #[serde(deserialize_with = "deserialize_turn_map")] turns: BTreeMap, intersections: Vec, } +fn serialize_turn_map( + map: &BTreeMap, + s: S, +) -> Result { + map.iter() + .map(|(a, b)| (a.clone(), b.clone())) + .collect::>() + .serialize(s) +} +fn deserialize_turn_map<'de, D: Deserializer<'de>>( + d: D, +) -> Result, D::Error> { + let vec = >::deserialize(d)?; + let mut map = BTreeMap::new(); + for (k, v) in vec { + map.insert(k, v); + } + Ok(map) +} + impl DrivingSimState { pub fn new(map: &Map) -> DrivingSimState { let mut intersections: Vec = Vec::new(); diff --git a/sim/src/walking.rs b/sim/src/walking.rs index cf52bc7fab..e50be15c07 100644 --- a/sim/src/walking.rs +++ b/sim/src/walking.rs @@ -3,6 +3,7 @@ use dimensioned::si; use draw_ped::DrawPedestrian; use map_model::{Lane, LaneID, Map, Turn, TurnID}; use multimap::MultiMap; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std; use std::collections::VecDeque; use {On, PedestrianID}; @@ -105,11 +106,34 @@ impl Pedestrian { pub struct WalkingSimState { // Trying a different style than driving for storing things peds_per_sidewalk: MultiMap, + #[serde(serialize_with = "serialize_turn_map")] + #[serde(deserialize_with = "deserialize_turn_map")] peds_per_turn: MultiMap, id_counter: usize, } +fn serialize_turn_map( + map: &MultiMap, + s: S, +) -> Result { + // TODO maybe need to sort by TurnID to have deterministic output + map.iter() + .map(|(a, b)| (a.clone(), b.clone())) + .collect::>() + .serialize(s) +} +fn deserialize_turn_map<'de, D: Deserializer<'de>>( + d: D, +) -> Result, D::Error> { + let vec = >::deserialize(d)?; + let mut map = MultiMap::new(); + for (k, v) in vec { + map.insert(k, v); + } + Ok(map) +} + impl WalkingSimState { pub fn new() -> WalkingSimState { WalkingSimState { diff --git a/sim/tests/determinism.rs b/sim/tests/determinism.rs index 36e13a2d96..cdca8874cc 100644 --- a/sim/tests/determinism.rs +++ b/sim/tests/determinism.rs @@ -3,6 +3,16 @@ extern crate control; extern crate map_model; extern crate sim; +#[test] +fn serialization() { + // This assumes this map has been built + let input = "../data/small.abst"; + + let map = map_model::Map::new(input, &map_model::Edits::new()).expect("Couldn't load map"); + let sim = sim::Sim::new(&map, Some(42)); + abstutil::write_json("/tmp/sim_state.json", &sim).unwrap(); +} + #[test] fn from_scratch() { // This assumes this map has been built @@ -11,8 +21,6 @@ fn from_scratch() { let spawn_count = 1000; println!("Creating two simulations"); - // TODO bundle all of the layers of the map together in some super-struct, so this - // initialization and plumbing is easier let map = map_model::Map::new(input, &map_model::Edits::new()).expect("Couldn't load map"); let control_map = control::ControlMap::new(&map);