These are three minimal examples demonstrating GeoJSON parsing using Rust. In order to run them, you'll need at least Stable Rust 1.34. In most cases, the easiest way to do this is using Rustup.
If you aren't familiar with it, it may be helpful to familiarise yourself with the GeoJSON spec, as this should make it obvious why e.g. Feature
geometries in rust-geojson
are Option
.
The example GeoJSON used is deliberately baroque: GeometryCollection
isn't in wide use, and the use of nested GeometryCollection
s is discouraged by the spec, being all but unknown "in the wild". Nevertheless, if we need to e.g. extract all Polygon
objects in an arbitrary GeoJSON file, we have to be able to process them – this turns out to be relatively painless using a recursive function.
The example code could be more minimal, but this is an ideal use case for Rayon in order to parallelise the processing, so iterators have been substituted for for { … }
loops to faciliate its use, leading to the requirement for Rust 1.21 or later. If you'd prefer to use for
loops and avoid iterators, the plain
branch is available.
Three different approaches to parsing GeoJSON are shown:
borrowed.rs
shows parsing using only borrowed data, and does not consume the GeoJSON, clone any part of it, or allocate – you're free to usegeojson
again as soon asprocess_geojson
returns. Run it using cargo:cargo run --bin borrowed
owned.rs
shows parsing and conversion toGeo
types, which necessarily consumes the GeoJSON, asGeo
's primitives currently require owned data. To faciliate conversions of this kind,rust-geojson
provides theconversion::try_into
trait for this on itsValue
structs. This approach is the most flexible, especially if you need to add or remove data, as opposed to modifying it. Run it using cargo:cargo run --bin owned
borrowed_modify.rs
(Run it using cargo:cargo run --bin borrowed_modify
) shows parsing and modification of geometries using only mutably borrowed data. The core idea can be seen incalculate_hull()
: ordinarily,take()
could be used to remove theT
from anOption<T>
– in this case aGeometry
– convert itsvalue
to aGeo
type, and modify it before replacing it. However, this approach will only work for theFeature
type; input which contains top-levelGeometry
and/orGeometryCollection
types can't be modified in this way, due to the lack ofOption
. However, a more general approach involvingstd::mem::replace
, is possible:- We match against
&mut Geometry
(which allGeoJson
enum variants are guaranteed to have) on itsvalue
, wrapping that in anOption
- This is passed to the conversion function
- In the conversion function, a non-allocating
Geo
placeholder geometry is constructed, converted into aValue
, and swapped for theValue
we wish to modify, usingreplace
. The original geometry can then be modified or freely used, before being swapped back into the borrowedGeometry.value
, before the function returns.
- We match against
The polylabel_cmd
crate contains more advanced parsing and conversion code which has the same structure as these examples.