use crate::prelude::*;
use crate::index::{Index, IndexGenerator};
use itertools::Itertools;
use std::collections::HashMap;
use std::rc::{Rc, Weak};
use std::cell::RefCell;
use std::ops::Deref;
use std::collections::hash_map::Values;
use genawaiter;
use genawaiter::rc::Gen;
use crate::property_storage::{PropertyStore, WithProperties};
#[derive(Clone, Debug)]
pub struct Shape<T: CoordinateType> {
index: Index<Self>,
pub geometry: Geometry<T>,
parent: Weak<Shapes<T>>,
}
impl<T: CoordinateType> PartialEq for Shape<T> {
fn eq(&self, other: &Self) -> bool {
let eq = self.index == other.index &&
self.parent.strong_count() > 0 && self.parent.ptr_eq(&other.parent);
if eq {
debug_assert!(self.geometry == other.geometry,
"Geometry must be identical when the shape objects are equal."
)
}
eq
}
}
impl<T: CoordinateType> Shape<T> {
fn new<I: Into<Geometry<T>>>(index: Index<Shape<T>>,
shape: I,
parent: Weak<Shapes<T>>) -> Self {
Shape {
index,
geometry: shape.into(),
parent,
}
}
pub fn index(&self) -> Index<Self> {
self.index.clone()
}
}
#[derive(Clone, Debug, Default)]
pub struct Shapes<T>
where T: CoordinateType {
self_reference: RefCell<Weak<Self>>,
pub(super) parent_cell: Weak<Cell<T>>,
index_generator: RefCell<IndexGenerator<Shape<T>>>,
shapes: RefCell<HashMap<Index<Shape<T>>, Rc<Shape<T>>>>,
shape_properties: RefCell<HashMap<Index<Shape<T>>, PropertyStore<String>>>,
}
impl<T: CoordinateType> Deref for Shape<T> {
type Target = Geometry<T>;
fn deref(&self) -> &Self::Target {
&self.geometry
}
}
impl<T: CoordinateType> Shapes<T> {
pub fn new_rc() -> Rc<Self> {
Self::new_rc_with_parent(Weak::default())
}
pub(super) fn new_rc_with_parent(parent_cell: Weak<Cell<T>>) -> Rc<Self> {
let shapes = Shapes {
self_reference: Default::default(),
parent_cell,
index_generator: Default::default(),
shapes: Default::default(),
shape_properties: Default::default(),
};
let rc_shapes = Rc::new(shapes);
*rc_shapes.self_reference.borrow_mut() = Rc::downgrade(&rc_shapes);
rc_shapes
}
pub fn from_geometries<I: IntoIterator<Item=Geometry<T>>>(iter: I) -> Rc<Self> {
let shapes = Shapes::new_rc();
for s in iter.into_iter() {
shapes.insert(s);
}
shapes
}
pub fn insert<I: Into<Geometry<T>>>(&self, shape: I) -> Rc<Shape<T>> {
let index = self.index_generator.borrow_mut().next();
let shape = Rc::new(Shape::new(index,
shape,
self.self_reference.borrow().clone()));
self.shapes.borrow_mut().insert(index, Rc::clone(&shape));
shape
}
pub fn remove_shape(&self, shape: &Shape<T>) {
self.shapes.borrow_mut().remove(&shape.index);
}
pub fn len(&self) -> usize {
self.shapes.borrow().len()
}
pub fn is_empty(&self) -> bool {
self.shapes.borrow().is_empty()
}
pub fn each_shape(&self) -> impl Iterator<Item=Rc<Shape<T>>> + '_ {
let generator = Gen::new(|co| async move {
for s in self.shapes.borrow().values().cloned() {
co.yield_(s).await;
}
});
generator.into_iter()
}
pub fn with_shape_iter<F, R>(&self, f: F) -> R
where F: FnOnce(Values<Index<Shape<T>>, Rc<Shape<T>>>) -> R,
{
f(self.shapes.borrow().values())
}
pub fn for_each_shape<F>(&self, f: F)
where F: FnMut(&Rc<Shape<T>>),
{
self.shapes.borrow().values().for_each(f)
}
pub fn parent_cell(&self) -> Weak<Cell<T>> {
self.parent_cell.clone()
}
}
impl<T: CoordinateType> TryBoundingBox<T> for Shapes<T> {
fn try_bounding_box(&self) -> Option<Rect<T>> {
self.with_shape_iter(|it| {
it.filter_map(|s| s.try_bounding_box())
.fold1(|a, b| a.add_rect(&b))
})
}
}
impl<C: CoordinateType> WithProperties for Shape<C> {
type Key = String;
fn with_properties<F, R>(&self, f: F) -> R
where F: FnOnce(Option<&PropertyStore<Self::Key>>) -> R {
f(
self.parent
.upgrade()
.unwrap()
.shape_properties.borrow()
.get(&self.index())
)
}
fn with_properties_mut<F, R>(&self, f: F) -> R
where F: FnOnce(&mut PropertyStore<Self::Key>) -> R {
f(
self.parent
.upgrade()
.unwrap()
.shape_properties.borrow_mut()
.entry(self.index())
.or_insert(PropertyStore::default())
)
}
}