Change the to/from permanent map edits APIs to be a little more ergonomic

This commit is contained in:
Dustin Carlino 2020-11-12 10:13:32 -08:00
parent c0e2401414
commit 7854823c28
6 changed files with 37 additions and 40 deletions

View File

@ -6,7 +6,7 @@ use rand::seq::SliceRandom;
use abstutil::{MapName, Timer}; use abstutil::{MapName, Timer};
use geom::{Bounds, Circle, Distance, Duration, Pt2D, Time}; use geom::{Bounds, Circle, Distance, Duration, Pt2D, Time};
use map_model::{IntersectionID, Map, PermanentMapEdits, Traversable}; use map_model::{IntersectionID, Map, Traversable};
use sim::{Analytics, Scenario, Sim, SimCallback, SimFlags}; use sim::{Analytics, Scenario, Sim, SimCallback, SimFlags};
use widgetry::{Canvas, EventCtx, GfxCtx, Prerender, SharedAppState}; use widgetry::{Canvas, EventCtx, GfxCtx, Prerender, SharedAppState};
@ -747,7 +747,7 @@ impl SharedAppState for App {
} else { } else {
abstutil::write_json( abstutil::write_json(
"edits_during_crash.json".to_string(), "edits_during_crash.json".to_string(),
&PermanentMapEdits::to_permanent(self.primary.map.get_edits(), &self.primary.map), &self.primary.map.get_edits().to_permanent(&self.primary.map),
); );
println!("Please include edits_during_crash.json in your bug report."); println!("Please include edits_during_crash.json in your bug report.");
} }

View File

@ -421,7 +421,7 @@ impl State<App> for Proposals {
Box::new(move |ctx, app| { Box::new(move |ctx, app| {
// Apply edits before setting up the sandbox, for simplicity // Apply edits before setting up the sandbox, for simplicity
let maybe_err = ctx.loading_screen("apply edits", |ctx, mut timer| { let maybe_err = ctx.loading_screen("apply edits", |ctx, mut timer| {
match PermanentMapEdits::from_permanent(edits, &app.primary.map) { match edits.to_edits(&app.primary.map) {
Ok(edits) => { Ok(edits) => {
apply_map_edits(ctx, app, edits); apply_map_edits(ctx, app, edits);
app.primary app.primary

View File

@ -316,9 +316,7 @@ fn handle_command(
let mut edits = map.get_edits().clone(); let mut edits = map.get_edits().clone();
edits.commands.clear(); edits.commands.clear();
edits.compress(map); edits.compress(map);
Ok(abstutil::to_json(&PermanentMapEdits::to_permanent( Ok(abstutil::to_json(&edits.to_permanent(map)))
&edits, map,
)))
} }
"/map/get-edit-road-command" => { "/map/get-edit-road-command" => {
let r = RoadID(params["id"].parse::<usize>()?); let r = RoadID(params["id"].parse::<usize>()?);
@ -415,7 +413,7 @@ impl LoadSim {
let mut map = Map::new(scenario.map_name.path(), timer); let mut map = Map::new(scenario.map_name.path(), timer);
if let Some(perma) = self.edits.clone() { if let Some(perma) = self.edits.clone() {
let edits = PermanentMapEdits::from_permanent(perma, &map).unwrap(); let edits = perma.to_edits(&map).unwrap();
map.must_apply_edits(edits, timer); map.must_apply_edits(edits, timer);
map.recalculate_pathfinding_after_edits(timer); map.recalculate_pathfinding_after_edits(timer);
} }

View File

@ -147,15 +147,15 @@ impl MapEdits {
} }
pub fn load(map: &Map, path: String, timer: &mut Timer) -> Result<MapEdits, String> { pub fn load(map: &Map, path: String, timer: &mut Timer) -> Result<MapEdits, String> {
match abstutil::maybe_read_json(path.clone(), timer) { match abstutil::maybe_read_json::<PermanentMapEdits>(path.clone(), timer) {
Ok(perma) => PermanentMapEdits::from_permanent(perma, map), Ok(perma) => perma.to_edits(map),
Err(_) => { Err(_) => {
// The JSON format may have changed, so attempt backwards compatibility. // The JSON format may have changed, so attempt backwards compatibility.
let bytes = abstutil::slurp_file(&path).map_err(|err| err.to_string())?; let bytes = abstutil::slurp_file(&path).map_err(|err| err.to_string())?;
let contents = std::str::from_utf8(&bytes).map_err(|err| err.to_string())?; let contents = std::str::from_utf8(&bytes).map_err(|err| err.to_string())?;
let value = serde_json::from_str(contents).map_err(|err| err.to_string())?; let value = serde_json::from_str(contents).map_err(|err| err.to_string())?;
let perma = compat::upgrade(value, map)?; let perma = compat::upgrade(value, map)?;
PermanentMapEdits::from_permanent(perma, map) perma.to_edits(map)
} }
} }
} }
@ -168,7 +168,7 @@ impl MapEdits {
abstutil::write_json( abstutil::write_json(
abstutil::path_edits(map.get_name(), &self.edits_name), abstutil::path_edits(map.get_name(), &self.edits_name),
&PermanentMapEdits::to_permanent(self, map), &self.to_permanent(map),
); );
} }

View File

@ -129,33 +129,36 @@ impl PermanentEditCmd {
} }
} }
impl PermanentMapEdits { impl MapEdits {
pub fn to_permanent(edits: &MapEdits, map: &Map) -> PermanentMapEdits { /// Encode the edits in a permanent format, referring to more-stable OSM IDs.
pub fn to_permanent(&self, map: &Map) -> PermanentMapEdits {
PermanentMapEdits { PermanentMapEdits {
map_name: map.get_name().clone(), map_name: map.get_name().clone(),
edits_name: edits.edits_name.clone(), edits_name: self.edits_name.clone(),
// Increase this every time there's a schema change // Increase this every time there's a schema change
version: 4, version: 4,
proposal_description: edits.proposal_description.clone(), proposal_description: self.proposal_description.clone(),
proposal_link: edits.proposal_link.clone(), proposal_link: self.proposal_link.clone(),
commands: edits.commands.iter().map(|cmd| cmd.to_perma(map)).collect(), commands: self.commands.iter().map(|cmd| cmd.to_perma(map)).collect(),
merge_zones: edits.merge_zones, merge_zones: self.merge_zones,
} }
} }
}
/// Load edits from the permanent form, looking up the map IDs by the hopefully stabler OSM IDs. impl PermanentMapEdits {
/// Validate that the basemap hasn't changed in important ways. /// Transform permanent edits to MapEdits, looking up the map IDs by the hopefully stabler OSM
pub fn from_permanent(perma: PermanentMapEdits, map: &Map) -> Result<MapEdits, String> { /// IDs. Validate that the basemap hasn't changed in important ways.
pub fn to_edits(self, map: &Map) -> Result<MapEdits, String> {
let mut edits = MapEdits { let mut edits = MapEdits {
edits_name: perma.edits_name, edits_name: self.edits_name,
proposal_description: perma.proposal_description, proposal_description: self.proposal_description,
proposal_link: perma.proposal_link, proposal_link: self.proposal_link,
commands: perma commands: self
.commands .commands
.into_iter() .into_iter()
.map(|cmd| cmd.to_cmd(map)) .map(|cmd| cmd.to_cmd(map))
.collect::<Result<Vec<EditCmd>, String>>()?, .collect::<Result<Vec<EditCmd>, String>>()?,
merge_zones: perma.merge_zones, merge_zones: self.merge_zones,
changed_roads: BTreeSet::new(), changed_roads: BTreeSet::new(),
original_intersections: BTreeMap::new(), original_intersections: BTreeMap::new(),
@ -165,19 +168,19 @@ impl PermanentMapEdits {
Ok(edits) Ok(edits)
} }
/// Load edits from the permanent form, looking up the map IDs by the hopefully stabler OSM IDs. /// Transform permanent edits to MapEdits, looking up the map IDs by the hopefully stabler OSM
/// Strip out commands that're broken. /// IDs. Strip out commands that're broken.
pub fn from_permanent_permissive(perma: PermanentMapEdits, map: &Map) -> MapEdits { pub fn to_edits_permissive(self, map: &Map) -> MapEdits {
let mut edits = MapEdits { let mut edits = MapEdits {
edits_name: perma.edits_name, edits_name: self.edits_name,
proposal_description: perma.proposal_description, proposal_description: self.proposal_description,
proposal_link: perma.proposal_link, proposal_link: self.proposal_link,
commands: perma commands: self
.commands .commands
.into_iter() .into_iter()
.filter_map(|cmd| cmd.to_cmd(map).ok()) .filter_map(|cmd| cmd.to_cmd(map).ok())
.collect(), .collect(),
merge_zones: perma.merge_zones, merge_zones: self.merge_zones,
changed_roads: BTreeSet::new(), changed_roads: BTreeSet::new(),
original_intersections: BTreeMap::new(), original_intersections: BTreeMap::new(),

View File

@ -138,14 +138,10 @@ fn check_proposals() -> Result<(), String> {
) { ) {
Ok(perma) => { Ok(perma) => {
let map = map_model::Map::new(perma.map_name.path(), &mut timer); let map = map_model::Map::new(perma.map_name.path(), &mut timer);
if let Err(err) = map_model::PermanentMapEdits::from_permanent(perma.clone(), &map) if let Err(err) = perma.clone().to_edits(&map) {
{
abstutil::write_json( abstutil::write_json(
"repair_attempt.json".to_string(), "repair_attempt.json".to_string(),
&map_model::PermanentMapEdits::to_permanent( &perma.to_edits_permissive(&map).to_permanent(&map),
&map_model::PermanentMapEdits::from_permanent_permissive(perma, &map),
&map,
),
); );
return Err(format!("{} is out-of-date: {}", name, err)); return Err(format!("{} is out-of-date: {}", name, err));
} }