2024-07-28

Rust Ten Years On


Ten years ago I wrote not one but two blog posts about a Rust project where I combined Open Street Map and Google elevation data to create 3D models of F1 tracks. Just a few months after F1 started showing a rendered 3D model of the track as part of their infographics. Obviously I'm not saying I did that... did I? (I'm just going to claim I did).

In those ten years a lot has happened - I've gained a degree; crashed my bike twice; had two jobs; moved cities three times and Rust has gone from 0.12 to 1.80. Ten years ago code you wrote last week wouldn't compile the next but since Rust got to 1.0 they have tried to keep backwards compatability through the use of editions. These allow the team to make backwards incompatible changes by making you have to opt-in to use them, and keeping the ability to compile code from older editions in the compiler.

Or at least, that's the idea. Before writing this post I had never directly compiled code from another edition, and I wasn't sure whether editions would be supported forever. What better way to put it to the test, do some archaeology, and rate the changes made around the time Rust was officialy released than to convert the old project to 1.0 Rust and try to compile the project from the blog posts?

OSM XML

The project actually comes in two crates - osmxml and osmmodels - with the latter depending on the former, so we will start with osmxml. This is responsible for reading elements - e.g. nodes and paths - from an OpenStreetMaps file. Trying to build gives us:

> cargo build
    Updating git repository `https://github.com/netvl/rust-xml.git`
error: no matching package named `rust-xml` found

Fallen at the first hurdle. If we look at the readme for this project we can see it has moved. Fixing that is quite simple:

diff --git a/Cargo.toml b/Cargo.toml
index 8fde986..45732ce 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -3,6 +3,7 @@
 name = "osmxml"
 version = "0.0.1"
 authors = ["Matthew Hall <[email protected]>"]
+edition = "2015"
 
 [lib]
 name = "osmxml"
@@ -12,5 +13,5 @@ path = "src/lib.rs"
 name = "spa"
 path = "examples/main.rs"
 
-[dependencies.rust-xml]
-git = "https://github.com/netvl/rust-xml.git"
+[dependencies]
+xml-rs = "0.8"

and now we get a real build, with errors!

error: expected expression, found `]`
  --> src/lib.rs:59:56
   |
59 |     attributes.iter().find(|attr| attr.name.local_name[] == s)
   |                                                        ^ expected expression

error: expected expression, found `]`
   --> src/lib.rs:36:43
    |
36  |                       match name.local_name[] {
    |                       -----                 ^ expected expression
    |                       |
    |                       while parsing this `match` expression
...
113 | /         parse!(self.parser, "node",
114 | |                "tag" => |attributes| self.parse_tag(attributes, &mut tags));
    | |___________________________________________________________________________- in this macro invocation
    |
    = note: this error originates in the macro `parse` (in Nightly builds, run with -Z macro-backtrace for more info)

error: expected expression, found `]`
   --> src/lib.rs:44:40
    |
44  |                       if name.local_name[] == $close_tag {
    |                                          ^ expected expression
...
113 | /         parse!(self.parser, "node",
114 | |                "tag" => |attributes| self.parse_tag(attributes, &mut tags));
    | |___________________________________________________________________________- in this macro invocation
    |
    = note: this error originates in the macro `parse` (in Nightly builds, run with -Z macro-backtrace for more info)

error: expected expression, found `]`
   --> src/lib.rs:36:43
    |
36  |                       match name.local_name[] {
    |                       -----                 ^ expected expression
    |                       |
    |                       while parsing this `match` expression
...
134 | /         parse!(self.parser, "way",
135 | |                "nd" => |attributes| Ok(nodes.push(try!(self.parse_nd(attributes)))),
136 | |                "tag" => |attributes| self.parse_tag(attributes, &mut tags));
    | |___________________________________________________________________________- in this macro invocation
    |
    = note: this error originates in the macro `parse` (in Nightly builds, run with -Z macro-backtrace for more info)

error: expected expression, found `]`
   --> src/lib.rs:44:40
    |
44  |                       if name.local_name[] == $close_tag {
    |                                          ^ expected expression
...
134 | /         parse!(self.parser, "way",
135 | |                "nd" => |attributes| Ok(nodes.push(try!(self.parse_nd(attributes)))),
136 | |                "tag" => |attributes| self.parse_tag(attributes, &mut tags));
    | |___________________________________________________________________________- in this macro invocation
    |
    = note: this error originates in the macro `parse` (in Nightly builds, run with -Z macro-backtrace for more info)

error: expected expression, found `]`
   --> src/lib.rs:36:43
    |
36  |                     match name.local_name[] {
    |                     -----                 ^ expected expression
    |                     |
    |                     while parsing this `match` expression
...
144 |         parse!(self.parser, "nd");
    |         ------------------------- in this macro invocation
    |
    = note: this error originates in the macro `parse` (in Nightly builds, run with -Z macro-backtrace for more info)

error: expected expression, found `]`
   --> src/lib.rs:44:40
    |
44  |                     if name.local_name[] == $close_tag {
    |                                        ^ expected expression
...
144 |         parse!(self.parser, "nd");
    |         ------------------------- in this macro invocation
    |
    = note: this error originates in the macro `parse` (in Nightly builds, run with -Z macro-backtrace for more info)

error: expected expression, found `]`
   --> src/lib.rs:36:43
    |
36  |                     match name.local_name[] {
    |                     -----                 ^ expected expression
    |                     |
    |                     while parsing this `match` expression
...
154 |         parse!(self.parser, "tag");
    |         -------------------------- in this macro invocation
    |
    = note: this error originates in the macro `parse` (in Nightly builds, run with -Z macro-backtrace for more info)

error: expected expression, found `]`
   --> src/lib.rs:44:40
    |
44  |                     if name.local_name[] == $close_tag {
    |                                        ^ expected expression
...
154 |         parse!(self.parser, "tag");
    |         -------------------------- in this macro invocation
    |
    = note: this error originates in the macro `parse` (in Nightly builds, run with -Z macro-backtrace for more info)

error: expected expression, found `]`
   --> src/lib.rs:36:43
    |
36  |                     match name.local_name[] {
    |                     -----                 ^ expected expression
    |                     |
    |                     while parsing this `match` expression
...
163 |         parse!(self.parser, "member");
    |         ----------------------------- in this macro invocation
    |
    = note: this error originates in the macro `parse` (in Nightly builds, run with -Z macro-backtrace for more info)

error: expected expression, found `]`
   --> src/lib.rs:44:40
    |
44  |                     if name.local_name[] == $close_tag {
    |                                        ^ expected expression
...
163 |         parse!(self.parser, "member");
    |         ----------------------------- in this macro invocation
    |
    = note: this error originates in the macro `parse` (in Nightly builds, run with -Z macro-backtrace for more info)

error: expected expression, found `]`
   --> src/lib.rs:36:43
    |
36  |                       match name.local_name[] {
    |                       -----                 ^ expected expression
    |                       |
    |                       while parsing this `match` expression
...
173 | /         parse!(self.parser, "relation",
174 | |                "member" => |attributes| Ok(members.push(try!(self.parse_member(attributes)))),
175 | |                "tag" => |attributes| self.parse_tag(attributes, &mut tags));
    | |___________________________________________________________________________- in this macro invocation
    |
    = note: this error originates in the macro `parse` (in Nightly builds, run with -Z macro-backtrace for more info)

error: expected expression, found `]`
   --> src/lib.rs:44:40
    |
44  |                       if name.local_name[] == $close_tag {
    |                                          ^ expected expression
...
173 | /         parse!(self.parser, "relation",
174 | |                "member" => |attributes| Ok(members.push(try!(self.parse_member(attributes)))),
175 | |                "tag" => |attributes| self.parse_tag(attributes, &mut tags));
    | |___________________________________________________________________________- in this macro invocation
    |
    = note: this error originates in the macro `parse` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0449]: unnecessary visibility qualifier
  --> src/lib.rs:23:9
   |
23 |         pub id: int,
   |         ^^^ `pub` not permitted here because it's implied

error[E0449]: unnecessary visibility qualifier
  --> src/lib.rs:24:9
   |
24 |         pub lat: f64, pub lng: f64,
   |         ^^^ `pub` not permitted here because it's implied

error[E0449]: unnecessary visibility qualifier
  --> src/lib.rs:24:23
   |
24 |         pub lat: f64, pub lng: f64,
   |                       ^^^ `pub` not permitted here because it's implied

error[E0449]: unnecessary visibility qualifier
  --> src/lib.rs:25:9
   |
25 |         pub visible: bool, pub tags: Tags
   |         ^^^ `pub` not permitted here because it's implied

error[E0449]: unnecessary visibility qualifier
  --> src/lib.rs:25:28
   |
25 |         pub visible: bool, pub tags: Tags
   |                            ^^^ `pub` not permitted here because it's implied

error[E0449]: unnecessary visibility qualifier
  --> src/lib.rs:27:11
   |
27 |     Way { pub id: int, pub nodes: Vec<int>, pub tags: Tags },
   |           ^^^ `pub` not permitted here because it's implied

error[E0449]: unnecessary visibility qualifier
  --> src/lib.rs:27:24
   |
27 |     Way { pub id: int, pub nodes: Vec<int>, pub tags: Tags },
   |                        ^^^ `pub` not permitted here because it's implied

error[E0449]: unnecessary visibility qualifier
  --> src/lib.rs:27:45
   |
27 |     Way { pub id: int, pub nodes: Vec<int>, pub tags: Tags },
   |                                             ^^^ `pub` not permitted here because it's implied

error[E0449]: unnecessary visibility qualifier
  --> src/lib.rs:28:16
   |
28 |     Relation { pub id: int, pub members: Vec<int>, pub tags: Tags },
   |                ^^^ `pub` not permitted here because it's implied

error[E0449]: unnecessary visibility qualifier
  --> src/lib.rs:28:29
   |
28 |     Relation { pub id: int, pub members: Vec<int>, pub tags: Tags },
   |                             ^^^ `pub` not permitted here because it's implied

error[E0449]: unnecessary visibility qualifier
  --> src/lib.rs:28:52
   |
28 |     Relation { pub id: int, pub members: Vec<int>, pub tags: Tags },
   |                                                    ^^^ `pub` not permitted here because it's implied

error[E0432]: unresolved imports `std::io::IoError`, `std::io::File`, `std::io::BufferedReader`
 --> src/lib.rs:5:15
  |
5 | use std::io::{IoError, File, BufferedReader};
  |               ^^^^^^^  ^^^^  ^^^^^^^^^^^^^^ no `BufferedReader` in `io`
  |               |        |
  |               |        no `File` in `io`
  |               no `IoError` in `io`
  |               help: a similar name exists in the module: `Error`
  |
  = help: consider importing this struct instead:
          std::fs::File

error[E0432]: unresolved import `xml::common::Attribute`
 --> src/lib.rs:7:5
  |
7 | use xml::common::Attribute;
  |     ^^^^^^^^^^^^^^^^^^^^^^ no `Attribute` in `common`
  |
help: consider importing this struct instead
  |
7 | use xml::attribute::Attribute;
  |     ~~~~~~~~~~~~~~~~~~~~~~~~~

error: cannot find attribute `deriving` in this scope
  --> src/lib.rs:12:3
   |
12 | #[deriving(Show)]
   |   ^^^^^^^^

error: cannot find attribute `deriving` in this scope
  --> src/lib.rs:20:3
   |
20 | #[deriving(Show)]
   |   ^^^^^^^^

error[E0412]: cannot find type `int` in this scope
  --> src/lib.rs:23:17
   |
23 |         pub id: int,
   |                 ^^^
   |                 |
   |                 not found in this scope
   |                 help: perhaps you intended to use this type: `i32`

error[E0412]: cannot find type `int` in this scope
  --> src/lib.rs:27:19
   |
27 |     Way { pub id: int, pub nodes: Vec<int>, pub tags: Tags },
   |                   ^^^
   |                   |
   |                   not found in this scope
   |                   help: perhaps you intended to use this type: `i32`

error[E0412]: cannot find type `int` in this scope
  --> src/lib.rs:27:39
   |
27 |     Way { pub id: int, pub nodes: Vec<int>, pub tags: Tags },
   |                                       ^^^ not found in this scope
   |
help: perhaps you intended to use this type
   |
27 |     Way { pub id: int, pub nodes: Vec<i32>, pub tags: Tags },
   |                                       ~~~
help: you might be missing a type parameter
   |
21 | pub enum OsmElement<int> {
   |                    +++++

error[E0412]: cannot find type `int` in this scope
  --> src/lib.rs:28:24
   |
28 |     Relation { pub id: int, pub members: Vec<int>, pub tags: Tags },
   |                        ^^^
   |                        |
   |                        not found in this scope
   |                        help: perhaps you intended to use this type: `i32`

error[E0412]: cannot find type `int` in this scope
  --> src/lib.rs:28:46
   |
28 |     Relation { pub id: int, pub members: Vec<int>, pub tags: Tags },
   |                                              ^^^ not found in this scope
   |
help: perhaps you intended to use this type
   |
28 |     Relation { pub id: int, pub members: Vec<i32>, pub tags: Tags },
   |                                              ~~~
help: you might be missing a type parameter
   |
21 | pub enum OsmElement<int> {
   |                    +++++

error[E0412]: cannot find type `int` in this scope
  --> src/lib.rs:65:27
   |
65 |     pub elements: HashMap<int, OsmElement>,
   |                           ^^^ not found in this scope
   |
help: perhaps you intended to use this type
   |
65 |     pub elements: HashMap<i32, OsmElement>,
   |                           ~~~
help: you might be missing a type parameter
   |
63 | pub struct Osm<int> {
   |               +++++

error[E0412]: cannot find type `Path` in this scope
  --> src/lib.rs:69:23
   |
69 |     pub fn new(path: &Path) -> Result<Osm, OsmParseError> {
   |                       ^^^^ not found in this scope
   |
help: consider importing this struct
   |
4  | use std::path::Path;
   |

error[E0422]: cannot find struct, variant or union type `StartElement` in this scope
  --> src/lib.rs:81:17
   |
81 |                 StartElement {name, attributes, ..} => try!(self.parse_start_element(name.local_name, attributes)),
   |                 ^^^^^^^^^^^^ not found in this scope
   |
help: consider importing one of these items
   |
4  | use xml::reader::XmlEvent::StartElement;
   |
4  | use xml::writer::XmlEvent::StartElement;
   |

error[E0425]: cannot find function, tuple struct or tuple variant `ParseErr` in this scope
   --> src/lib.rs:108:29
    |
108 |             _ => return Err(ParseErr(
    |                             ^^^^^^^^ not found in this scope
    |
help: consider importing this tuple variant
    |
4   | use OsmParseError::ParseErr;
    |

error[E0422]: cannot find struct, variant or union type `StartElement` in this scope
   --> src/lib.rs:35:17
    |
35  |                   StartElement {name, attributes, ..} => {
    |                   ^^^^^^^^^^^^ not found in this scope
...
113 | /         parse!(self.parser, "node",
114 | |                "tag" => |attributes| self.parse_tag(attributes, &mut tags));
    | |___________________________________________________________________________- in this macro invocation
    |
    = note: this error originates in the macro `parse` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider importing one of these items
    |
4   | use xml::reader::XmlEvent::StartElement;
    |
4   | use xml::writer::XmlEvent::StartElement;
    |

error[E0422]: cannot find struct, variant or union type `EndElement` in this scope
   --> src/lib.rs:43:17
    |
43  |                   EndElement {name, ..} => {
    |                   ^^^^^^^^^^ not found in this scope
...
113 | /         parse!(self.parser, "node",
114 | |                "tag" => |attributes| self.parse_tag(attributes, &mut tags));
    | |___________________________________________________________________________- in this macro invocation
    |
    = note: this error originates in the macro `parse` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider importing one of these items
    |
4   | use xml::reader::XmlEvent::EndElement;
    |
4   | use xml::writer::XmlEvent::EndElement;
    |

error[E0425]: cannot find function, tuple struct or tuple variant `ParseErr` in this scope
   --> src/lib.rs:51:43
    |
51  |                   EndDocument => return Err(ParseErr("Premature end".to_string())),
    |                                             ^^^^^^^^ not found in this scope
...
113 | /         parse!(self.parser, "node",
114 | |                "tag" => |attributes| self.parse_tag(attributes, &mut tags));
    | |___________________________________________________________________________- in this macro invocation
    |
    = note: this error originates in the macro `parse` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider importing this tuple variant
    |
4   | use OsmParseError::ParseErr;
    |

error[E0422]: cannot find struct, variant or union type `Node` in this scope
   --> src/lib.rs:116:34
    |
116 |         self.elements.insert(id, Node{id: id, lat: lat, lng: lng,
    |                                  ^^^^
   --> /build/rustc-1.69.0-src/library/core/src/option.rs:567:5
    |
    = note: similarly named variant `None` defined here
    |
help: a variant with a similar name exists
    |
116 |         self.elements.insert(id, None{id: id, lat: lat, lng: lng,
    |                                  ~~~~
help: consider importing this variant
    |
4   | use OsmElement::Node;
    |

error[E0412]: cannot find type `int` in this scope
   --> src/lib.rs:122:77
    |
122 |     fn parse_int_attr(&self, k: &str, attributes: Vec<Attribute>) -> Result<int, OsmParseError> {
    |                                                                             ^^^ not found in this scope
    |
help: perhaps you intended to use this type
    |
122 |     fn parse_int_attr(&self, k: &str, attributes: Vec<Attribute>) -> Result<i32, OsmParseError> {
    |                                                                             ~~~
help: you might be missing a type parameter
    |
68  | impl<int> Osm {
    |     +++++

error[E0425]: cannot find function, tuple struct or tuple variant `ParseErr` in this scope
   --> src/lib.rs:125:25
    |
125 |             None => Err(ParseErr("Could not find id/ref attribute".to_string())),
    |                         ^^^^^^^^ not found in this scope
    |
help: consider importing this tuple variant
    |
4   | use OsmParseError::ParseErr;
    |

error[E0422]: cannot find struct, variant or union type `StartElement` in this scope
   --> src/lib.rs:35:17
    |
35  |                   StartElement {name, attributes, ..} => {
    |                   ^^^^^^^^^^^^ not found in this scope
...
134 | /         parse!(self.parser, "way",
135 | |                "nd" => |attributes| Ok(nodes.push(try!(self.parse_nd(attributes)))),
136 | |                "tag" => |attributes| self.parse_tag(attributes, &mut tags));
    | |___________________________________________________________________________- in this macro invocation
    |
    = note: this error originates in the macro `parse` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider importing one of these items
    |
4   | use xml::reader::XmlEvent::StartElement;
    |
4   | use xml::writer::XmlEvent::StartElement;
    |

error[E0422]: cannot find struct, variant or union type `EndElement` in this scope
   --> src/lib.rs:43:17
    |
43  |                   EndElement {name, ..} => {
    |                   ^^^^^^^^^^ not found in this scope
...
134 | /         parse!(self.parser, "way",
135 | |                "nd" => |attributes| Ok(nodes.push(try!(self.parse_nd(attributes)))),
136 | |                "tag" => |attributes| self.parse_tag(attributes, &mut tags));
    | |___________________________________________________________________________- in this macro invocation
    |
    = note: this error originates in the macro `parse` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider importing one of these items
    |
4   | use xml::reader::XmlEvent::EndElement;
    |
4   | use xml::writer::XmlEvent::EndElement;
    |

error[E0425]: cannot find function, tuple struct or tuple variant `ParseErr` in this scope
   --> src/lib.rs:51:43
    |
51  |                   EndDocument => return Err(ParseErr("Premature end".to_string())),
    |                                             ^^^^^^^^ not found in this scope
...
134 | /         parse!(self.parser, "way",
135 | |                "nd" => |attributes| Ok(nodes.push(try!(self.parse_nd(attributes)))),
136 | |                "tag" => |attributes| self.parse_tag(attributes, &mut tags));
    | |___________________________________________________________________________- in this macro invocation
    |
    = note: this error originates in the macro `parse` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider importing this tuple variant
    |
4   | use OsmParseError::ParseErr;
    |

error[E0422]: cannot find struct, variant or union type `Way` in this scope
   --> src/lib.rs:138:34
    |
138 |         self.elements.insert(id, Way {id: id, nodes: nodes, tags: tags});
    |                                  ^^^ not found in this scope
    |
help: consider importing this variant
    |
4   | use OsmElement::Way;
    |

error[E0412]: cannot find type `int` in this scope
   --> src/lib.rs:142:66
    |
142 |     fn parse_nd(&mut self, attributes: Vec<Attribute>) -> Result<int, OsmParseError> {
    |                                                                  ^^^ not found in this scope
    |
help: perhaps you intended to use this type
    |
142 |     fn parse_nd(&mut self, attributes: Vec<Attribute>) -> Result<i32, OsmParseError> {
    |                                                                  ~~~
help: you might be missing a type parameter
    |
68  | impl<int> Osm {
    |     +++++

error[E0422]: cannot find struct, variant or union type `StartElement` in this scope
   --> src/lib.rs:35:17
    |
35  |                 StartElement {name, attributes, ..} => {
    |                 ^^^^^^^^^^^^ not found in this scope
...
144 |         parse!(self.parser, "nd");
    |         ------------------------- in this macro invocation
    |
    = note: this error originates in the macro `parse` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider importing one of these items
    |
4   | use xml::reader::XmlEvent::StartElement;
    |
4   | use xml::writer::XmlEvent::StartElement;
    |

error[E0422]: cannot find struct, variant or union type `EndElement` in this scope
   --> src/lib.rs:43:17
    |
43  |                 EndElement {name, ..} => {
    |                 ^^^^^^^^^^ not found in this scope
...
144 |         parse!(self.parser, "nd");
    |         ------------------------- in this macro invocation
    |
    = note: this error originates in the macro `parse` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider importing one of these items
    |
4   | use xml::reader::XmlEvent::EndElement;
    |
4   | use xml::writer::XmlEvent::EndElement;
    |

error[E0425]: cannot find function, tuple struct or tuple variant `ParseErr` in this scope
   --> src/lib.rs:51:43
    |
51  |                 EndDocument => return Err(ParseErr("Premature end".to_string())),
    |                                           ^^^^^^^^ not found in this scope
...
144 |         parse!(self.parser, "nd");
    |         ------------------------- in this macro invocation
    |
    = note: this error originates in the macro `parse` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider importing this tuple variant
    |
4   | use OsmParseError::ParseErr;
    |

error[E0425]: cannot find function, tuple struct or tuple variant `ParseErr` in this scope
   --> src/lib.rs:151:29
    |
151 |             _ => return Err(ParseErr("Tag must have a k and a v attribute".to_string()))
    |                             ^^^^^^^^ not found in this scope
    |
help: consider importing this tuple variant
    |
4   | use OsmParseError::ParseErr;
    |

error[E0422]: cannot find struct, variant or union type `StartElement` in this scope
   --> src/lib.rs:35:17
    |
35  |                 StartElement {name, attributes, ..} => {
    |                 ^^^^^^^^^^^^ not found in this scope
...
154 |         parse!(self.parser, "tag");
    |         -------------------------- in this macro invocation
    |
    = note: this error originates in the macro `parse` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider importing one of these items
    |
4   | use xml::reader::XmlEvent::StartElement;
    |
4   | use xml::writer::XmlEvent::StartElement;
    |

error[E0422]: cannot find struct, variant or union type `EndElement` in this scope
   --> src/lib.rs:43:17
    |
43  |                 EndElement {name, ..} => {
    |                 ^^^^^^^^^^ not found in this scope
...
154 |         parse!(self.parser, "tag");
    |         -------------------------- in this macro invocation
    |
    = note: this error originates in the macro `parse` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider importing one of these items
    |
4   | use xml::reader::XmlEvent::EndElement;
    |
4   | use xml::writer::XmlEvent::EndElement;
    |

error[E0425]: cannot find function, tuple struct or tuple variant `ParseErr` in this scope
   --> src/lib.rs:51:43
    |
51  |                 EndDocument => return Err(ParseErr("Premature end".to_string())),
    |                                           ^^^^^^^^ not found in this scope
...
154 |         parse!(self.parser, "tag");
    |         -------------------------- in this macro invocation
    |
    = note: this error originates in the macro `parse` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider importing this tuple variant
    |
4   | use OsmParseError::ParseErr;
    |

error[E0412]: cannot find type `int` in this scope
   --> src/lib.rs:160:70
    |
160 |     fn parse_member(&mut self, attributes: Vec<Attribute>) -> Result<int, OsmParseError> {
    |                                                                      ^^^ not found in this scope
    |
help: perhaps you intended to use this type
    |
160 |     fn parse_member(&mut self, attributes: Vec<Attribute>) -> Result<i32, OsmParseError> {
    |                                                                      ~~~
help: you might be missing a type parameter
    |
68  | impl<int> Osm {
    |     +++++

error[E0422]: cannot find struct, variant or union type `StartElement` in this scope
   --> src/lib.rs:35:17
    |
35  |                 StartElement {name, attributes, ..} => {
    |                 ^^^^^^^^^^^^ not found in this scope
...
163 |         parse!(self.parser, "member");
    |         ----------------------------- in this macro invocation
    |
    = note: this error originates in the macro `parse` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider importing one of these items
    |
4   | use xml::reader::XmlEvent::StartElement;
    |
4   | use xml::writer::XmlEvent::StartElement;
    |

error[E0422]: cannot find struct, variant or union type `EndElement` in this scope
   --> src/lib.rs:43:17
    |
43  |                 EndElement {name, ..} => {
    |                 ^^^^^^^^^^ not found in this scope
...
163 |         parse!(self.parser, "member");
    |         ----------------------------- in this macro invocation
    |
    = note: this error originates in the macro `parse` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider importing one of these items
    |
4   | use xml::reader::XmlEvent::EndElement;
    |
4   | use xml::writer::XmlEvent::EndElement;
    |

error[E0425]: cannot find function, tuple struct or tuple variant `ParseErr` in this scope
   --> src/lib.rs:51:43
    |
51  |                 EndDocument => return Err(ParseErr("Premature end".to_string())),
    |                                           ^^^^^^^^ not found in this scope
...
163 |         parse!(self.parser, "member");
    |         ----------------------------- in this macro invocation
    |
    = note: this error originates in the macro `parse` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider importing this tuple variant
    |
4   | use OsmParseError::ParseErr;
    |

error[E0422]: cannot find struct, variant or union type `StartElement` in this scope
   --> src/lib.rs:35:17
    |
35  |                   StartElement {name, attributes, ..} => {
    |                   ^^^^^^^^^^^^ not found in this scope
...
173 | /         parse!(self.parser, "relation",
174 | |                "member" => |attributes| Ok(members.push(try!(self.parse_member(attributes)))),
175 | |                "tag" => |attributes| self.parse_tag(attributes, &mut tags));
    | |___________________________________________________________________________- in this macro invocation
    |
    = note: this error originates in the macro `parse` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider importing one of these items
    |
4   | use xml::reader::XmlEvent::StartElement;
    |
4   | use xml::writer::XmlEvent::StartElement;
    |

error[E0422]: cannot find struct, variant or union type `EndElement` in this scope
   --> src/lib.rs:43:17
    |
43  |                   EndElement {name, ..} => {
    |                   ^^^^^^^^^^ not found in this scope
...
173 | /         parse!(self.parser, "relation",
174 | |                "member" => |attributes| Ok(members.push(try!(self.parse_member(attributes)))),
175 | |                "tag" => |attributes| self.parse_tag(attributes, &mut tags));
    | |___________________________________________________________________________- in this macro invocation
    |
    = note: this error originates in the macro `parse` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider importing one of these items
    |
4   | use xml::reader::XmlEvent::EndElement;
    |
4   | use xml::writer::XmlEvent::EndElement;
    |

error[E0425]: cannot find function, tuple struct or tuple variant `ParseErr` in this scope
   --> src/lib.rs:51:43
    |
51  |                   EndDocument => return Err(ParseErr("Premature end".to_string())),
    |                                             ^^^^^^^^ not found in this scope
...
173 | /         parse!(self.parser, "relation",
174 | |                "member" => |attributes| Ok(members.push(try!(self.parse_member(attributes)))),
175 | |                "tag" => |attributes| self.parse_tag(attributes, &mut tags));
    | |___________________________________________________________________________- in this macro invocation
    |
    = note: this error originates in the macro `parse` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider importing this tuple variant
    |
4   | use OsmParseError::ParseErr;
    |

error[E0422]: cannot find struct, variant or union type `Relation` in this scope
   --> src/lib.rs:177:34
    |
177 |         self.elements.insert(id, Relation{id: id, members: members, tags: tags});
    |                                  ^^^^^^^^ not found in this scope
    |
help: consider importing this variant
    |
4   | use OsmElement::Relation;
    |

error[E0603]: module `events` is private
  --> src/lib.rs:8:18
   |
8  | use xml::reader::events::*;
   |                  ^^^^^^ private module
   |
note: the module `events` is defined here
  --> /home/mjh/.cargo/registry/src/github.com-1ecc6299db9ec823/xml-rs-0.8.20/src/reader.rs:20:1
   |
20 | mod events;
   | ^^^^^^^^^^

error[E0554]: `#![feature]` may not be used on the stable release channel
 --> src/lib.rs:1:1
  |
1 | #![feature(globs, macro_rules, struct_variant, slicing_syntax)]
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the attribute
  |
  = help: the feature `slicing_syntax` has been stable since `1.0.0` and no longer requires an attribute to enable
  = help: the feature `slicing_syntax` has been stable since `1.0.0` and no longer requires an attribute to enable
  = help: the feature `slicing_syntax` has been stable since `1.0.0` and no longer requires an attribute to enable
  = help: the feature `slicing_syntax` has been stable since `1.0.0` and no longer requires an attribute to enable

warning: use of deprecated macro `try`: use the `?` operator instead
  --> src/lib.rs:74:9
   |
74 |         try!(s.parse());
   |         ^^^
   |
   = note: `#[warn(deprecated)]` on by default

warning: use of deprecated macro `try`: use the `?` operator instead
  --> src/lib.rs:81:56
   |
81 |                 StartElement {name, attributes, ..} => try!(self.parse_start_element(name.local_name, attributes)),
   |                                                        ^^^

warning: use of deprecated macro `try`: use the `?` operator instead
  --> src/lib.rs:93:27
   |
93 |             "relation" => try!(self.parse_relation(attributes)),
   |                           ^^^

warning: use of deprecated macro `try`: use the `?` operator instead
  --> src/lib.rs:94:23
   |
94 |             "node" => try!(self.parse_node(attributes)),
   |                       ^^^

warning: use of deprecated macro `try`: use the `?` operator instead
  --> src/lib.rs:95:22
   |
95 |             "way" => try!(self.parse_way(attributes)),
   |                      ^^^

warning: use of deprecated macro `try`: use the `?` operator instead
   --> src/lib.rs:130:18
    |
130 |         let id = try!(self.parse_int_attr("id", attributes));
    |                  ^^^

warning: use of deprecated macro `try`: use the `?` operator instead
   --> src/lib.rs:143:17
    |
143 |         let i = try!(self.parse_int_attr("ref", attributes));
    |                 ^^^

warning: use of deprecated macro `try`: use the `?` operator instead
   --> src/lib.rs:161:17
    |
161 |         let i = try!(self.parse_int_attr("ref", attributes));
    |                 ^^^

warning: use of deprecated macro `try`: use the `?` operator instead
   --> src/lib.rs:169:18
    |
169 |         let id = try!(self.parse_int_attr("id", attributes));
    |                  ^^^

warning: the feature `globs` has been stable since 1.0.0 and no longer requires an attribute to enable
 --> src/lib.rs:1:12
  |
1 | #![feature(globs, macro_rules, struct_variant, slicing_syntax)]
  |            ^^^^^
  |
  = note: `#[warn(stable_features)]` on by default

warning: the feature `macro_rules` has been stable since 1.0.0 and no longer requires an attribute to enable
 --> src/lib.rs:1:19
  |
1 | #![feature(globs, macro_rules, struct_variant, slicing_syntax)]
  |                   ^^^^^^^^^^^

warning: the feature `struct_variant` has been stable since 1.0.0 and no longer requires an attribute to enable
 --> src/lib.rs:1:32
  |
1 | #![feature(globs, macro_rules, struct_variant, slicing_syntax)]
  |                                ^^^^^^^^^^^^^^

warning: the feature `slicing_syntax` has been stable since 1.0.0 and no longer requires an attribute to enable
 --> src/lib.rs:1:48
  |
1 | #![feature(globs, macro_rules, struct_variant, slicing_syntax)]
  |                                                ^^^^^^^^^^^^^^

error[E0599]: no method named `as_slice` found for struct `String` in the current scope
  --> src/lib.rs:92:20
   |
92 |         match name.as_slice() {
   |                    ^^^^^^^^ method not found in `String`

error[E0425]: cannot find function `from_str` in this scope
   --> src/lib.rs:102:66
    |
102 |         let id  = find_attribute(&attributes, "id").and_then(|v| from_str(v));
    |                                                                  ^^^^^^^^ not found in this scope

error[E0425]: cannot find function `from_str` in this scope
   --> src/lib.rs:103:68
    |
103 |         let lat  = find_attribute(&attributes, "lat").and_then(|v| from_str(v));
    |                                                                    ^^^^^^^^ not found in this scope

error[E0425]: cannot find function `from_str` in this scope
   --> src/lib.rs:104:68
    |
104 |         let lng  = find_attribute(&attributes, "lon").and_then(|v| from_str(v));
    |                                                                    ^^^^^^^^ not found in this scope

error[E0425]: cannot find function `from_str` in this scope
   --> src/lib.rs:105:76
    |
105 |         let visible  = find_attribute(&attributes, "visible").and_then(|v| from_str(v));
    |                                                                            ^^^^^^^^ not found in this scope

warning: unreachable statement
   --> src/lib.rs:116:9
    |
33  | /         loop {
34  | |             match $parser.next() {
35  | |                 StartElement {name, attributes, ..} => {
36  | |                     match name.local_name[] {
...   |
53  | |             }
54  | |         }
    | |_________- any code following this expression is unreachable
...
116 | /         self.elements.insert(id, Node{id: id, lat: lat, lng: lng,
117 | |                                       visible: visible, tags: tags});
    | |_____________________________________________________________________^ unreachable statement
    |
    = note: `#[warn(unreachable_code)]` on by default

error[E0425]: cannot find function `from_str` in this scope
   --> src/lib.rs:123:66
    |
123 |         return match find_attribute(&attributes, k).and_then(|v| from_str(v)) {
    |                                                                  ^^^^^^^^ not found in this scope

warning: unreachable statement
   --> src/lib.rs:138:9
    |
33  | /         loop {
34  | |             match $parser.next() {
35  | |                 StartElement {name, attributes, ..} => {
36  | |                     match name.local_name[] {
...   |
53  | |             }
54  | |         }
    | |_________- any code following this expression is unreachable
...
138 |           self.elements.insert(id, Way {id: id, nodes: nodes, tags: tags});
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable statement

warning: unreachable expression
   --> src/lib.rs:145:9
    |
33  | /         loop {
34  | |             match $parser.next() {
35  | |                 StartElement {name, attributes, ..} => {
36  | |                     match name.local_name[] {
...   |
53  | |             }
54  | |         }
    | |_________- any code following this expression is unreachable
...
145 |           Ok(i)
    |           ^^^^^ unreachable expression

warning: unreachable statement
   --> src/lib.rs:156:9
    |
33  | /         loop {
34  | |             match $parser.next() {
35  | |                 StartElement {name, attributes, ..} => {
36  | |                     match name.local_name[] {
...   |
53  | |             }
54  | |         }
    | |_________- any code following this expression is unreachable
...
156 |           tags.insert(k.to_string(), v.to_string());
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable statement

warning: unreachable expression
   --> src/lib.rs:165:9
    |
33  | /         loop {
34  | |             match $parser.next() {
35  | |                 StartElement {name, attributes, ..} => {
36  | |                     match name.local_name[] {
...   |
53  | |             }
54  | |         }
    | |_________- any code following this expression is unreachable
...
165 |           Ok(i)
    |           ^^^^^ unreachable expression

warning: unreachable statement
   --> src/lib.rs:177:9
    |
33  | /         loop {
34  | |             match $parser.next() {
35  | |                 StartElement {name, attributes, ..} => {
36  | |                     match name.local_name[] {
...   |
53  | |             }
54  | |         }
    | |_________- any code following this expression is unreachable
...
177 |           self.elements.insert(id, Relation{id: id, members: members, tags: tags});
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable statement

Some errors have detailed explanations: E0412, E0422, E0425, E0432, E0449, E0554, E0599, E0603.
For more information about an error, try `rustc --explain E0412`.
warning: `osmxml` (lib) generated 19 warnings
error: could not compile `osmxml` due to 71 previous errors; 19 warnings emitted

Just the 1000 lines of diagnostics and 71 errors - an error every one and a half lines of source code! It appears that nine years on rustc still has support for the original release of Rust, it's just our project is a little bit behind and has some 1.0 features.

Slicing Strings

First up is this mysterious syntax (the []):

attributes.iter().find(|attr| attr.name.local_name[] == s)

I've not been able to find a reference for when this change happened, but from memory (and context) this syntax allowed you to get the borrowed string type (&str) from the owned string type (String).

Verdict: Positive
Errors left: 70

What's in(t) a name?

error[E0412]: cannot find type `int` in this scope
   --> src/lib.rs:142:66
    |
142 |     fn parse_nd(&mut self, attributes: Vec<Attribute>) -> Result<int, OsmParseError> {
    |                                                                  ^^^ not found in this scope

This one was a surprise to me - as late as a few months before 1.0 the name for a word sized, signed integer was int. Nowadays of course it is isize which I think is much better. int is already confusing enough in C(++) where it is compiler dependent without including it in Rust. This naming has also been taken by Zig.

Verdict: Positive
Errors left: 61

Public fields in enum variants

error[E0449]: unnecessary visibility qualifier
  --> src/lib.rs:27:11
   |
27 |     Way { pub id: int, pub nodes: Vec<int>, pub tags: Tags },
   |           ^^^ `pub` not permitted here because it's implied

If you have an enum variant which stores data you no longer need to mark those fields as public if the enum is public - they are assumed to be. I can see both sides of this. I feel like if you are going to implement visibility you should apply it to everything, but on the other hand is there any case where a consumer of a library really wants to be able to pattern match on an enum, but not get the data out of it?

Verdict: Ambivalent
Errors left: 50

Enum variants are namespaced

error[E0422]: cannot find struct, variant or union type `Relation` in this scope
   --> src/lib.rs:177:34
    |
177 |         self.elements.insert(id, Relation{id: id, members: members, tags: tags});
    |                                  ^^^^^^^^ not found in this scope

Before 1.0 the variants of an enum were accessible just by their names (i.e. not though the enum type). This is still the case for some special enums - e.g. Result and Option where you can construct instances of them using Ok/Err or Some/None directly. In general I am all for explicitness so I like this change. It also means you can have a variant named the same as some other type, which is a nice win.

Verdict: Positive
Errors left: 26

from_str

error[E0425]: cannot find function `from_str` in this scope
   --> src/lib.rs:102:66
    |
102 |         let id  = find_attribute(&attributes, "id").and_then(|v| from_str(v));
    |                                                                  ^^^^^^^^ not found in this scope

Here we have a change from 1.0 itself - from_str was deprecated in favour of the more generic From::from.

Verdict: Positive
Errors left: 21

as_slice

error[E0599]: no method named `as_slice` found for struct `String` in the current scope
  --> src/lib.rs:92:20
   |
92 |         match name.as_slice() {
   |                    ^^^^^^^^ method not found in `String`

as_slice was renamed to as_str - pretty straight forward.

Verdict: Positive
Errors left: 20

Verious import errors

A few things were moved, e.g. File was moved from std::io to std::fs and IoError was renamed to Error, given it was already in the std::io module.

Verdict: Positive
Errors left: 12

derive

error: cannot find attribute `deriving` in this scope
  --> src/lib.rs:12:3
   |
12 | #[deriving(Show)]
   |   ^^^^^^^^

deriving was renamed derive and Show was renamed Debug. I prefer the original naming, if only because I had a misspent youth messing around with Haskell.

Verdict: Negative
Errors left: 6

OSM Models

That was it for osmxml, other than fixing things to use the new XML crate. Moving onto the models part - which creates a Wavefront obj file from a given element - we were depending on a long dead package rust-http. The first step was to remove it and we will replace it later.

> cargo build
warning: use of deprecated macro `try`: use the `?` operator instead
  --> /home/mjh/Documents/Programming/osmxml/src/lib.rs:82:9
   |
82 |         try!(s.parse());
   |         ^^^
   |
   = note: `#[warn(deprecated)]` on by default

warning: use of deprecated macro `try`: use the `?` operator instead
  --> /home/mjh/Documents/Programming/osmxml/src/lib.rs:89:66
   |
89 |                 XmlEvent::StartElement {name, attributes, ..} => try!(self.parse_start_element(name.local_name, attributes)),
   |                                                                  ^^^

warning: use of deprecated macro `try`: use the `?` operator instead
   --> /home/mjh/Documents/Programming/osmxml/src/lib.rs:101:27
    |
101 |             "relation" => try!(self.parse_relation(attributes)),
    |                           ^^^

warning: use of deprecated macro `try`: use the `?` operator instead
   --> /home/mjh/Documents/Programming/osmxml/src/lib.rs:102:23
    |
102 |             "node" => try!(self.parse_node(attributes)),
    |                       ^^^

warning: use of deprecated macro `try`: use the `?` operator instead
   --> /home/mjh/Documents/Programming/osmxml/src/lib.rs:103:22
    |
103 |             "way" => try!(self.parse_way(attributes)),
    |                      ^^^

warning: use of deprecated macro `try`: use the `?` operator instead
   --> /home/mjh/Documents/Programming/osmxml/src/lib.rs:45:35
    |
45  |                           $($tag => try!($method(attributes)),)*
    |                                     ^^^
...
127 | /         parse!(self.parser, "node",
128 | |                "tag" => |attributes| self.parse_tag(attributes, &mut tags));
    | |___________________________________________________________________________- in this macro invocation
    |
    = note: this warning originates in the macro `parse` (in Nightly builds, run with -Z macro-backtrace for more info)

warning: use of deprecated macro `try`: use the `?` operator instead
   --> /home/mjh/Documents/Programming/osmxml/src/lib.rs:144:18
    |
144 |         let id = try!(self.parse_int_attr("id", attributes));
    |                  ^^^

warning: use of deprecated macro `try`: use the `?` operator instead
   --> /home/mjh/Documents/Programming/osmxml/src/lib.rs:45:35
    |
45  |                           $($tag => try!($method(attributes)),)*
    |                                     ^^^
...
148 | /         parse!(self.parser, "way",
149 | |                "nd" => |attributes| {
150 | |                     nodes.push(try!(self.parse_nd(attributes)));
151 | |                     ParseResult::Ok(())
152 | |                 },
153 | |                "tag" => |attributes| self.parse_tag(attributes, &mut tags));
    | |___________________________________________________________________________- in this macro invocation
    |
    = note: this warning originates in the macro `parse` (in Nightly builds, run with -Z macro-backtrace for more info)

warning: use of deprecated macro `try`: use the `?` operator instead
   --> /home/mjh/Documents/Programming/osmxml/src/lib.rs:150:32
    |
150 |                     nodes.push(try!(self.parse_nd(attributes)));
    |                                ^^^

warning: use of deprecated macro `try`: use the `?` operator instead
   --> /home/mjh/Documents/Programming/osmxml/src/lib.rs:160:17
    |
160 |         let i = try!(self.parse_int_attr("ref", attributes));
    |                 ^^^

warning: use of deprecated macro `try`: use the `?` operator instead
   --> /home/mjh/Documents/Programming/osmxml/src/lib.rs:178:17
    |
178 |         let i = try!(self.parse_int_attr("ref", attributes));
    |                 ^^^

warning: use of deprecated macro `try`: use the `?` operator instead
   --> /home/mjh/Documents/Programming/osmxml/src/lib.rs:186:18
    |
186 |         let id = try!(self.parse_int_attr("id", attributes));
    |                  ^^^

warning: use of deprecated macro `try`: use the `?` operator instead
   --> /home/mjh/Documents/Programming/osmxml/src/lib.rs:45:35
    |
45  |                           $($tag => try!($method(attributes)),)*
    |                                     ^^^
...
190 | /         parse!(self.parser, "relation",
191 | |                "member" => |attributes| {
192 | |                     members.push(try!(self.parse_member(attributes)));
193 | |                     ParseResult::Ok(())
194 | |                 },
195 | |                "tag" => |attributes| self.parse_tag(attributes, &mut tags));
    | |___________________________________________________________________________- in this macro invocation
    |
    = note: this warning originates in the macro `parse` (in Nightly builds, run with -Z macro-backtrace for more info)

warning: use of deprecated macro `try`: use the `?` operator instead
   --> /home/mjh/Documents/Programming/osmxml/src/lib.rs:192:34
    |
192 |                     members.push(try!(self.parse_member(attributes)));
    |                                  ^^^

warning: unused variable: `attributes`
   --> /home/mjh/Documents/Programming/osmxml/src/lib.rs:43:47
    |
43  |                 XmlEvent::StartElement {name, attributes, ..} => {
    |                                               ^^^^^^^^^^-
    |                                               |
    |                                               help: try removing the field
...
161 |         parse!(self.parser, "nd");
    |         ------------------------- in this macro invocation
    |
    = note: `#[warn(unused_variables)]` on by default
    = note: this warning originates in the macro `parse` (in Nightly builds, run with -Z macro-backtrace for more info)

warning: unused variable: `attributes`
   --> /home/mjh/Documents/Programming/osmxml/src/lib.rs:43:47
    |
43  |                 XmlEvent::StartElement {name, attributes, ..} => {
    |                                               ^^^^^^^^^^-
    |                                               |
    |                                               help: try removing the field
...
171 |         parse!(self.parser, "tag");
    |         -------------------------- in this macro invocation
    |
    = note: this warning originates in the macro `parse` (in Nightly builds, run with -Z macro-backtrace for more info)

warning: unused variable: `attributes`
   --> /home/mjh/Documents/Programming/osmxml/src/lib.rs:43:47
    |
43  |                 XmlEvent::StartElement {name, attributes, ..} => {
    |                                               ^^^^^^^^^^-
    |                                               |
    |                                               help: try removing the field
...
180 |         parse!(self.parser, "member");
    |         ----------------------------- in this macro invocation
    |
    = note: this warning originates in the macro `parse` (in Nightly builds, run with -Z macro-backtrace for more info)

warning: `osmxml` (lib) generated 17 warnings (run `cargo fix --lib -p osmxml` to apply 3 suggestions)
   Compiling osmmodels v0.0.1 (/home/mjh/Documents/Programming/osmmodels)
error: cannot find attribute `deriving` in this scope
 --> src/lib.rs:1:3
  |
1 | #[deriving(Show)]
  |   ^^^^^^^^

error: cannot find attribute `deriving` in this scope
  --> src/lib.rs:19:3
   |
19 | #[deriving(Show)]
   |   ^^^^^^^^

error[E0412]: cannot find type `int` in this scope
 --> src/lib.rs:4:14
  |
4 |     Face(Vec<int>)
  |              ^^^ not found in this scope
  |
help: perhaps you intended to use this type
  |
4 |     Face(Vec<i32>)
  |              ~~~
help: you might be missing a type parameter
  |
2 | pub enum WavefrontValue<int> {
  |                        +++++

error[E0531]: cannot find tuple struct or tuple variant `Vertex` in this scope
  --> src/lib.rs:10:13
   |
10 |             Vertex(x, y, z) => format!("v {} {} {}", x, y, z),
   |             ^^^^^^ not found in this scope
   |
help: consider importing this tuple variant
   |
1  | use WavefrontValue::Vertex;
   |

error[E0531]: cannot find tuple struct or tuple variant `Face` in this scope
  --> src/lib.rs:11:13
   |
11 |             Face(ref locs) =>  {
   |             ^^^^ not found in this scope
   |
help: consider importing this tuple variant
   |
1  | use WavefrontValue::Face;
   |

error[E0425]: cannot find function, tuple struct or tuple variant `Vertex` in this scope
  --> src/lib.rs:35:26
   |
35 |         self.values.push(Vertex(x, y, z));
   |                          ^^^^^^ not found in this scope
   |
help: consider importing this tuple variant
   |
1  | use WavefrontValue::Vertex;
   |

error[E0412]: cannot find type `int` in this scope
  --> src/lib.rs:38:41
   |
38 |     pub fn add_face(&mut self, vec: Vec<int>) {
   |                                         ^^^ not found in this scope
   |
help: perhaps you intended to use this type
   |
38 |     pub fn add_face(&mut self, vec: Vec<i32>) {
   |                                         ~~~
help: you might be missing a type parameter
   |
24 | impl<int> Wavefront {
   |     +++++

error[E0425]: cannot find function, tuple struct or tuple variant `Face` in this scope
  --> src/lib.rs:39:26
   |
39 |         self.values.push(Face(vec));
   |                          ^^^^ not found in this scope
   |
help: consider importing this tuple variant
   |
1  | use WavefrontValue::Face;
   |

warning: use of deprecated method `std::slice::<impl [T]>::connect`: renamed to join
  --> src/lib.rs:31:14
   |
31 |         vals.connect("\n")
   |              ^^^^^^^
   |
   = note: `#[warn(deprecated)]` on by default

Some errors have detailed explanations: E0412, E0425, E0531.
For more information about an error, try `rustc --explain E0412`.
warning: `osmmodels` (lib) generated 1 warning
error: could not compile `osmmodels` due to 8 previous errors; 1 warning emitted

Just the eight errors this time, even with a crate missing. Next we fixed up enum variants being namespaced and the int and as_slice renames which actually brought us up to 24 errors.

Vec API changes

error[E0599]: no method named `push_all` found for struct `Vec<_>` in the current scope
   --> src/main.rs:156:17
    |
156 |         heights.push_all(get_heights_request(api.as_str(), chunk));
    |                 ^^^^^^^^ help: there is a method with a similar name: `push`

error[E0599]: no method named `concat_vec` found for struct `Vec<Vec<(f64, f64)>>` in the current scope
   --> src/main.rs:168:21
    |
168 |     let flat = ways.concat_vec();
    |                     ^^^^^^^^^^ help: there is a method with a similar name: `concat`

error[E0425]: cannot find function `unzip` in module `std::vec`
   --> src/main.rs:171:52
    |
171 |     let (xs, ys): (Vec<f64>, Vec<f64>) = std::vec::unzip(flat.iter().map(|&(lat, lng)| latlng_to_metres(lat, lng)));
    |                                                    ^^^^^ not found in `std::vec`

There was some renaming here - push_all to extend_from_slice, concat_vec to concat and unzip became a method on iterators.

Verdict: Ambivalent
Errors left: 17

fail!ure

error: cannot find macro `fail` in this scope
  --> src/main.rs:48:14
   |
48 |         _ => fail!("expand_relation must be passed a relation"),
   |              ^^^^

Another quite simple one - fail! was renamed to panic!. fail! was a bad name given programmers tend to use it to describe everything from recoverable errors to assertions tripping.

Verdict: Positive
Errors left: 11

We then update to the latest cgmath and fixup the int rename to get down to 7 errors.

find to get

Hashmap find was renamed get.

Verdict: Ambivalent
Errors left: 5

We then fixed some enum variants and the fact that argument parsing and environment variables had moved to different places, for 2 errors left

Using a new HTTP library

Now I just had to rewrite the code that got the elevation data from Google. To start with I was going to use hyper until I realised that it is async, and this edition is pre-async. With that ruling hyper our I settled on reqwest, which is easier to use in my opinion.

I also needed to replace the json library I used and I naturally chose serde. With that done, the new function was quite easy to write:

 fn get_heights_request(api: &str, latlngs: &[(f64, f64)]) -> Vec<f64> {
-    let mut heights = Vec::new();
     let s: Vec<String> = latlngs.iter()
                                 .map(|&(lat,lng)| format!("{},{}", lat, lng))
                                 .collect();
-    let url = Url::parse(format!(
+
+    let txt = reqwest::blocking::get(format!(
         "https://maps.googleapis.com/maps/api/elevation/json?key={}&locations={}",
         api,
-        s.connect("|")).as_str()).unwrap();
-    let request: RequestWriter = RequestWriter::new(Get, url).unwrap();
-    let mut response = match request.read_response() {
-        Ok(r) => r,
-        Err(e) => panic!("Could not read response")
-    };
-    let body = response.read_to_end().unwrap();
-    let s = str::from_utf8(body.as_str()).expect("body from_utf8");
-    let json: json::Json = json::from_str(s).unwrap();
-    for res in json.find(&"results".to_string()).unwrap().as_list().unwrap().iter() {
-        heights.push(res.find(&"elevation".to_string()).unwrap().as_number().unwrap());
+        s.connect("|")).as_str()).unwrap().text().unwrap();
+
+    let mut heights = Vec::new();
+    let json: Value = serde_json::from_str(txt.as_str()).unwrap();
+    for res in json["results"].as_array().unwrap() {
+        heights.push(res["elevation"].as_number().unwrap().as_f64().unwrap());
     }
     heights
 }

And that is it - it works!

Summary

Almost all of the changes Rust made leading up to 1.0 were positive in my opinion. I'm also very impressed at how the edition system has worked. Being able to compile 1.0 code after several breaking changes without using a different compiler is pretty nice! I think updating the code from 0.12 to 1.0 took a few hours in total which is quite a lot given how small a project is. Clearly a lot changed leading up to 1.0. It's also cool that the original XML library I used is still getting updates today, ten years on, and was largely the same. It feels like there is a lot of churn in the Rust ecosystem, but maybe that just isn't true.

Looking back at the code I am bit embarassed. I pretty much ignored error handling in osmmodels, prefering to panic! (or fail! as it was then) or unwrap Results and Options. I think I am much more disciplined nowadays even in case where it doesn't really matter like sideprojects.

It is interesting that Haskell came up in passing in this blog post. I feel like ten years ago I was very interested in "complicated" languages. Haskellers/Rustaceans please don't come for me, I mean languages with a lot of abstraction power. After years of writing C and Go professionally I tend to gravitate to languages that are more simple and require you to just get down and dirty and write the code. It will be interesting to see what I think about that in another decade. And how many more times I've falled off my bike too. Stay tuned!