How to check geometry type from geo_types

I’m new to Rust and I’m still struggling with the borrowing concept in combination with the TryFrom function from the geo_types crate.

I basically want to do different things depending on the actual Geometry type:

use geo_types::{Geometry, Point, LineString};

fn some_func(g : Geometry<f64>) {
    if let Ok(p) = Point::try_from(g) {
        print!("POINT");
    } else if let Ok(ls) = LineString::try_from(g) { 
        print!("LINESTRING");
    } else {
        print!("UNKNOWN");
    }
}

but this fails with:

error[E0382]: use of moved value: `g`
 --> src/main.rs:7:49
  |
4 | fn some_func(g : Geometry<f64>) {
  |              - move occurs because `g` has type `Geometry`, which does not implement the `Copy` trait
5 |     if let Ok(p) = Point::try_from(g) {
  |                                    - value moved here
6 |         print!("POINT");
7 |     } else if let Ok(ls) = LineString::try_from(g) { 
  |                                                 ^ value used here after move
  |
help: consider cloning the value if the performance cost is acceptable
  |
5 |     if let Ok(p) = Point::try_from(g.clone()) {
  |                                     ++++++++

So I was changing the function to take a geometry refernce:

fn some_func(g : &Geometry<f64>)

but that fails with:

the trait From<&Geometry> is not implemented for geo_types::Point<_>

Next thing I tried is to de-reference the geometry:

Point::try_from(*g)

but this also fails with:

cannot move out of *g which is behind a shared reference
move occurs because *g has type Geometry, which does not implement the Copy trait

So what can I do to get this code working or how can I do this differently?

>Solution :

Note that Geometry is an enum, so you should use pattern matching to check which variant you are using.

pub enum Geometry<T: CoordNum = f64> {
    Point(Point<T>),
    Line(Line<T>),
    LineString(LineString<T>),
    Polygon(Polygon<T>),
    MultiPoint(MultiPoint<T>),
    MultiLineString(MultiLineString<T>),
    MultiPolygon(MultiPolygon<T>),
    GeometryCollection(GeometryCollection<T>),
    Rect(Rect<T>),
    Triangle(Triangle<T>),
}

So you can rewrite your function as follows:

use geo_types::{Geometry, Point, LineString};

fn some_func(g : Geometry<f64>) {

    match g {
        Geometry::Point(_) => print!("POINT"),
        Geometry::LineString(_) => print!("LINESTRING"),
        // It's not really unknown, because there are other enum variants,
        // but I left it to not change your original (intended?) bahavior.
        _ -> print!("UNKNOWN")
    }
}

Leave a Reply