I apologize for the title. My question is not quick, so I thought I should dress it up.

I'm looking for inspiration / feedback / vocabulary on an approach I'm taking related to enums whose associated data are owned types vs borrowed types.

## disclaimer: example code has been changed to protect the innocent.

The code I'm working on is for the `geo`

crate, which is a collection of geospatial algorithms and data types. My examples below references some of the actual geospatial type names for the sake of concreteness only - their geospatial functionality isn't relevant. It's also been edited to better stand alone as an example.

## Background

The primary currency of the `geo`

crate is the `Geometry`

enum, for which each variant is an owned type of the same name (is there a conventional name for this pattern? "OneOf the bourgeoisie"?)

```
pub enum Geometry<T>
where
T: GeoNum,
{
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>),
}
```

I'm working on a feature for which I've added a reference corollary to the crate like this:

```
pub enum GeometryRef<'a, T>
where
T: GeoNum,
{
Point(&'a Point<T>),
Line(&'a Line<T>),
LineString(&'a LineString<T>),
Polygon(&'a Polygon<T>),
MultiPoint(&'a MultiPoint<T>),
MultiLineString(&'a MultiLineString<T>),
MultiPolygon(&'a MultiPolygon<T>),
GeometryCollection(&'a GeometryCollection<T>),
Rect(&'a Rect<T>),
Triangle(&'a Triangle<T>),
}
```

The back story is that, in the crates history, most functionality has been added via trait impls for individual Geometry variants.

For example consider this trait and it's many impls:

```
pub trait Contains<Rhs = Self> {
/// Returns whether `rhs` is entirely within `self`
/// ```
/// assert!(usa_polygon.contains(center_of_chicago_point))
/// assert!(!center_of_chicago_point.contains(usa_polygon))
fn contains(&self, rhs: &Rhs) -> bool;
}
impl<T: GeoNum> Contains<Point<T>> for Point<T>
{
fn contains(&self, p: &Point<T>) -> bool {
self.0 == &p.0
}
}
impl<G, T> Contains<G> for MultiPoint<T>
where
T: GeoNum,
Point<T>: Contains<G>,
{
fn contains(&self, rhs: &G) -> bool {
self.iter().any(|p| p.contains(rhs))
}
}
impl<T: GeoNum> Contains<Point<T>> for Line<T>
{
fn contains(&self, p: &Point<T>) -> bool {
// and so on
}
}
impl<T: GeoNum> Contains<Line<T>> for Line<T>
{
fn contains(&self, line: &Line<T>) -> bool {
// and so on
}
}
// ... and so on, with an `impl Contains<B> for A` for every combination of Geometry cases
```

Some traits are not implemented for every `Geometry`

variant. e.g. a trait that measures "length" might make sense for a `Line`

but not for a `Polygon`

. But for traits like `Contains`

above, which *are* implemented for every `Geometry`

variant, we typically impl that trait on `Geometry`

itself by way of a trivial delegation:

```
impl<T: GeoNum> Contains for Geometry<T> {
fn contains(&self) -> bool {
match self {
Geometry::Point(g) => g.contains(),
Geometry::Line(g) => g.contains(),
Geometry::LineString(g) => g.contains(),
... => etc.
}
}
}
```

(Since this delegation is common boilerplate, we use a macro for the actual implementation)

I'm currently adding some functionality via a new `Relate`

trait which, rather than having a bottom-up impl for every combination of variants, has a single implementation directly on Geometry. Like this:

```
impl<T: GeoFloat> Relate<T, Geometry<T>> for Geometry<T> {
fn relate(&self, other: &Geometry<T>) -> IntersectionMatrix {
// This needs a read-only borrow of the two `Geometry`
topologically_relate(self, other)
// ...not relevant to the Rust question, but for context, the above outputs topological
// relations of the two geometries as described by https://en.wikipedia.org/wiki/DE-9IM
}
}
```

So I had the above trait, implemented on `Geometry`

and it's working great. BUT sometimes I'd like to use this trait on instances of the individual inner *variant* (`Point`

, `Line`

, etc.), but the only way to do that, would require some undesirable cloning:

```
fn foo(line: &Line, polygon: &Polygon) -> Color {
# 🚨We want to avoid these clones!
let line_geometry = Geometry::Line(line.clone());
let polygon_geometry = Geometry::Polygon(polygon.clone());
if polygon_geometry.relate(line_geometry).is_contains() {
Color::Green
} else {
Color::Red
}
}
```

So I addressed this by introducing a new `GeometryRef`

wenum (as described above), which is just like the `Geometry`

enum, but each variant holds a reference, rather than an owned.

```
pub enum GeometryRef<'a, T>
where
T: GeoNum,
{
Point(&'a Point<T>),
Line(&'a Line<T>),
LineString(&'a LineString<T>),
...
}
```

And reimplemented `Relate`

and it's inner workings in terms of `GeometryRef`

like:

```
impl<T: GeoFloat> Relate<F, GeometryRef<F>> for GeometryRef<F> {
fn relate(&self, other: &GeometryRef <F>) -> IntersectionMatrix {
// Also re-wrote the internals of `topologically_relate` to use `&GeometryRef`s rather than a `&Geometry`s
// which was mostly straight forward
topologically_relate(self, other)
}
}
```

Then the problematic clones go away:

```
fn foo(line: &Line, polygon: &Polygon) -> Color {
// 🥳 no more clones 👯♂️
let line_geometry = GeometryRef::Line(line);
let polygon_geometry = GeometryRef::Polygon(polygon);
if polygon_geometry.relate(line_geometry).is_contains() {
Color::Green
} else {
Color::Red
}
}
```

So, that works! But here are the downsides:

The implementation of `topologically_relate `

internally relies on a bunch of functionality that's currently only implemented for `&Geometry`

.

So for now I've duplicated all that functionality for `GeometryRef`

. So far it's been trivial to duplicate — whereas before we had something like this:

```
impl<T> BoundingRect<T> for Geometry<T>
where
T: CoordNum,
{
type Output = Option<Rect<T>>;
fn bounding_rect(&self) -> Self::Output {
match self {
Geometry::Point(g) => Some(g.bounding_rect()),
Geometry::Line(g) => Some(g.bounding_rect()),
Geometry::LineString(g) => g.bounding_rect(),
Geometry::Polygon(g) => g.bounding_rect(),
Geometry::MultiPoint(g) => g.bounding_rect(),
Geometry::MultiLineString(g) => g.bounding_rect(),
Geometry::MultiPolygon(g) => g.bounding_rect(),
Geometry::GeometryCollection(g) => g.bounding_rect(),
Geometry::Rect(g) => Some(g.bounding_rect()),
Geometry::Triangle(g) => Some(g.bounding_rect()),
}
}
}
```

We now also need an almost identical impl like this:

```
impl<T> BoundingRect<T> for GeometryRef<'_, T>
where
T: CoordNum,
{
type Output = Option<Rect<T>>;
fn bounding_rect(&self) -> Self::Output {
match self {
GeometryRef::Point(g) => Some(g.bounding_rect()),
GeometryRef::Line(g) => Some(g.bounding_rect()),
GeometryRef::LineString(g) => g.bounding_rect(),
GeometryRef::Polygon(g) => g.bounding_rect(),
GeometryRef::MultiPoint(g) => g.bounding_rect(),
GeometryRef::MultiLineString(g) => g.bounding_rect(),
GeometryRef::MultiPolygon(g) => g.bounding_rect(),
GeometryRef::GeometryCollection(g) => g.bounding_rect(),
GeometryRef::Rect(g) => Some(g.bounding_rect()),
GeometryRef::Triangle(g) => Some(g.bounding_rect()),
}
}
}
```

## Finally, the question

This is doable... and can be cleaned up with a macro, but is there some better design that avoids all this duplication?

Or anyone have a similar experience? Or examples to point to? Horror stories? Sonnets?

One piece of advice I was given was that, if `GeometryRef`

is going to become public, it might make sense to future-proof and use a `Cow`

rather than a plain reference, since a Cow also solves the problem and might enable some future functionality without requiring introducing yet-another API change down the road. Something like:

```
pub enum GeometryCow<'a, T>
where
T: CoordNum,
{
Point(Cow<'a, Point<T>>),
Line(Cow<'a, Line<T>>),
LineString(Cow<'a, LineString<T>>),
Polygon(Cow<'a, Polygon<T>>),
MultiPoint(Cow<'a, MultiPoint<T>>),
MultiLineString(Cow<'a, MultiLineString<T>>),
MultiPolygon(Cow<'a, MultiPolygon<T>>),
GeometryCollection(Cow<'a, GeometryCollection<T>>),
Rect(Cow<'a, Rect<T>>),
Triangle(Cow<'a, Triangle<T>>),
}
```

Thank you for reading this far.