---
# System prepended metadata

title: Untitled

---

```
#[allow(unused_variables)]

use std::ops::Add;

#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Point {
    x: f64,
    y: f64,
}

impl Point {
    pub fn new(x: i64, y: i64) -> Self {
        Self {
            x: x as f64,
            y: y as f64,
        }
    }

    pub fn magnitude(&self) -> f64 {
        f64::sqrt(f64::powf(self.x, 2.0) + f64::powf(self.y, 2.0))
    }

    pub fn dist(&self, other: Point) -> f64 {
        let dx = other.x - self.x;
        let dy = other.y - self.y;

        f64::sqrt(f64::powf(dx, 2.0) + f64::powf(dy, 2.0))
    }
}

impl Add for Point {
    type Output = Point;

    fn add(self, other: Point) -> Point {
        Point {
            x: self.x + other.x,
            y: self.y + other.y,
        }
    }
}

trait Circumference {
    fn circumference(&self) -> f64;
}

pub struct Polygon {
    points: Vec<Point>,
}

impl Polygon {
    pub fn new() -> Self {
        Self {
            points: Vec::new(),
        }
    }

    pub fn add_point(&mut self, point: Point) {
        self.points.push(point);
    }

    pub fn left_most_point(&self) -> Option<Point> {
        self.points.iter().min_by(|a, b| a.x.partial_cmp(&b.x).unwrap()).cloned()
    }

    fn iter(&self) -> std::slice::Iter<Point> {
        self.points.iter()
    }
}

impl Circumference for Polygon {
    fn circumference(&self) -> f64 {
        let p1 = &self.points;
        let mut p2 = self.points.clone();

        p2.rotate_right(1);

        let mut sum = 0.0;

        for i in 0..p1.len() {
            sum += p1[i].dist(p2[i]);            
        }

        sum
    }
}

pub struct Circle {
    center: Point,
    radius: f64
}

impl Circle {
    pub fn new(center: Point, radius: i64) -> Self {
        Self {
            center,
            radius: radius as f64,
        }
    }
}

impl Circumference for Circle {
    fn circumference(&self) -> f64 {
        2.0 * std::f64::consts::PI * self.radius
    }
}

pub enum Shape {
    Polygon(Polygon),
    Circle(Circle),
}

// impl Shape {
//     pub fn from(obj: dyn Any) -> Shape {
//         match obj {
//             Polygon => Shape::Polygon(obj),
//             Circle => Shape::Circle(obj),
//         }
//     }
// }

impl Shape {
    // pub fn from(obj: dyn Any) -> Shape {
    //     match obj {
    //         Polygon => Shape::Polygon(obj.downcast_ref::<crate::Polygon>()),
    //         Circle => Shape::Circle(obj.downcast_ref::<crate::Circle>()),
    //     }
    // }

    // pub fn from(polygon: Polygon) -> Self {
    //     Shape::Polygon(polygon)
    // }

    // pub fn from(circle: Circle) -> Self {
    //     Shape::Circle(circle)
    // }
}

impl From<Polygon> for Shape {
    fn from(polygon: Polygon) -> Self {
        Shape::Polygon(polygon)
    }
}

impl From<Circle> for Shape {
    fn from(circle: Circle) -> Self {
        Shape::Circle(circle)
    }
}

impl Circumference for Shape {
    fn circumference(&self) -> f64 {
        match self {
            Shape::Polygon(polygon) => polygon.circumference(),
            Shape::Circle(circle) => circle.circumference(),
        }
    }
}


#[cfg(test)]
mod tests {
    use super::*;

    fn round_two_digits(x: f64) -> f64 {
        (x * 100.0).round() / 100.0
    }

    #[test]
    fn test_point_magnitude() {
        let p1 = Point::new(12, 13);
        assert_eq!(round_two_digits(p1.magnitude()), 17.69);
    }

    #[test]
    fn test_point_dist() {
        let p1 = Point::new(10, 10);
        let p2 = Point::new(14, 13);
        assert_eq!(round_two_digits(p1.dist(p2)), 5.00);
    }

    #[test]
    fn test_point_add() {
        let p1 = Point::new(16, 16);
        let p2 = p1 + Point::new(-4, 3);
        assert_eq!(p2, Point::new(12, 19));
    }

    #[test]
    fn test_polygon_left_most_point() {
        let p1 = Point::new(12, 13);
        let p2 = Point::new(16, 16);

        let mut poly = Polygon::new();
        poly.add_point(p1);
        poly.add_point(p2);
        assert_eq!(poly.left_most_point(), Some(p1));
    }

    #[test]
    fn test_polygon_iter() {
        let p1 = Point::new(12, 13);
        let p2 = Point::new(16, 16);

        let mut poly = Polygon::new();
        poly.add_point(p1);
        poly.add_point(p2);

        let points = poly.iter().cloned().collect::<Vec<_>>();
        assert_eq!(points, vec![Point::new(12, 13), Point::new(16, 16)]);
    }

    #[test]
    fn test_shape_circumferences() {
        let mut poly = Polygon::new();
        poly.add_point(Point::new(12, 13));
        poly.add_point(Point::new(17, 11));
        poly.add_point(Point::new(16, 16));
        let shapes = vec![
            Shape::from(poly),
            Shape::from(Circle::new(Point::new(10, 20), 5)),
        ];
        let circumferences = shapes
            .iter()
            .map(Shape::circumference)
            .map(round_two_digits)
            .collect::<Vec<_>>();
        assert_eq!(circumferences, vec![15.48, 31.42]);
    }
}

#[allow(dead_code)]
fn main() {}
```
