mirror of https://codeberg.org/topola/topola.git
234 lines
6.9 KiB
Rust
234 lines
6.9 KiB
Rust
// SPDX-FileCopyrightText: 2024 Topola contributors
|
|
//
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
use core::fmt;
|
|
use std::{collections::HashMap, hash::Hash, marker::PhantomData};
|
|
|
|
use crate::{
|
|
drawing::graph::{GetLayer, Retag},
|
|
graph::{GenericIndex, GetPetgraphIndex},
|
|
};
|
|
|
|
use super::{AccessBendWeight, AccessDotWeight, AccessSegWeight, GetWidth};
|
|
|
|
pub trait ApplyGeometryEdit<
|
|
PW: GetWidth + GetLayer + TryInto<DW> + TryInto<SW> + TryInto<BW> + Retag<PI> + Copy,
|
|
DW: AccessDotWeight<PW> + GetLayer,
|
|
SW: AccessSegWeight<PW> + GetLayer,
|
|
BW: AccessBendWeight<PW> + GetLayer,
|
|
CW: Copy,
|
|
PI: GetPetgraphIndex + TryInto<DI> + TryInto<SI> + TryInto<BI> + Eq + Hash + Copy,
|
|
DI: GetPetgraphIndex + Into<PI> + Eq + Hash + Copy,
|
|
SI: GetPetgraphIndex + Into<PI> + Eq + Hash + Copy,
|
|
BI: GetPetgraphIndex + Into<PI> + Eq + Hash + Copy,
|
|
>
|
|
{
|
|
fn apply(&mut self, edit: &GeometryEdit<PW, DW, SW, BW, CW, PI, DI, SI, BI>);
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct GeometryEdit<PW, DW, SW, BW, CW, PI, DI, SI, BI> {
|
|
pub(super) dots: HashMap<DI, (Option<DW>, Option<DW>)>,
|
|
pub(super) segs: HashMap<SI, (Option<((DI, DI), SW)>, Option<((DI, DI), SW)>)>,
|
|
pub(super) bends: HashMap<BI, (Option<((DI, DI, DI), BW)>, Option<((DI, DI, DI), BW)>)>,
|
|
pub(super) compounds: HashMap<GenericIndex<CW>, (Option<(Vec<PI>, CW)>, Option<(Vec<PI>, CW)>)>,
|
|
primitive_weight_marker: PhantomData<PW>,
|
|
}
|
|
|
|
impl<
|
|
PW: GetWidth + GetLayer + TryInto<DW> + TryInto<SW> + TryInto<BW> + Retag<PI> + Copy,
|
|
DW: AccessDotWeight<PW> + GetLayer,
|
|
SW: AccessSegWeight<PW> + GetLayer,
|
|
BW: AccessBendWeight<PW> + GetLayer,
|
|
CW: Copy,
|
|
PI: GetPetgraphIndex + TryInto<DI> + TryInto<SI> + TryInto<BI> + Eq + Hash + Copy,
|
|
DI: GetPetgraphIndex + Into<PI> + Eq + Hash + Copy,
|
|
SI: GetPetgraphIndex + Into<PI> + Eq + Hash + Copy,
|
|
BI: GetPetgraphIndex + Into<PI> + Eq + Hash + Copy,
|
|
> GeometryEdit<PW, DW, SW, BW, CW, PI, DI, SI, BI>
|
|
{
|
|
pub fn new() -> Self {
|
|
Self {
|
|
dots: HashMap::new(),
|
|
segs: HashMap::new(),
|
|
bends: HashMap::new(),
|
|
compounds: HashMap::new(),
|
|
primitive_weight_marker: PhantomData,
|
|
}
|
|
}
|
|
|
|
pub fn reverse(&self) -> Self {
|
|
Self {
|
|
dots: self
|
|
.dots
|
|
.clone()
|
|
.into_iter()
|
|
.map(|(k, v)| (k, (v.1, v.0)))
|
|
.collect(),
|
|
segs: self
|
|
.segs
|
|
.clone()
|
|
.into_iter()
|
|
.map(|(k, v)| (k, (v.1, v.0)))
|
|
.collect(),
|
|
bends: self
|
|
.bends
|
|
.clone()
|
|
.into_iter()
|
|
.map(|(k, v)| (k, (v.1, v.0)))
|
|
.collect(),
|
|
compounds: self
|
|
.compounds
|
|
.clone()
|
|
.into_iter()
|
|
.map(|(k, v)| (k, (v.1, v.0)))
|
|
.collect(),
|
|
primitive_weight_marker: PhantomData,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Recordable objects are objects to which a [recorder](`GeometryEdit`) can be attached,
|
|
/// the specialized methods working on `&mut` [`Recording`] then (are to be expected to)
|
|
/// also write changes to the passed `recorder`, and can also be replayed or rolled back
|
|
/// via [`ApplyGeometryEdit`].
|
|
pub trait Recordable {
|
|
type PW: GetWidth
|
|
+ GetLayer
|
|
+ TryInto<Self::DW>
|
|
+ TryInto<Self::SW>
|
|
+ TryInto<Self::BW>
|
|
+ Retag<Self::PI>
|
|
+ Copy;
|
|
type DW: AccessDotWeight<Self::PW> + GetLayer;
|
|
type SW: AccessSegWeight<Self::PW> + GetLayer;
|
|
type BW: AccessBendWeight<Self::PW> + GetLayer;
|
|
type CW: Copy;
|
|
type PI: GetPetgraphIndex
|
|
+ TryInto<Self::DI>
|
|
+ TryInto<Self::SI>
|
|
+ TryInto<Self::BI>
|
|
+ Copy
|
|
+ Eq
|
|
+ Hash;
|
|
type DI: GetPetgraphIndex + Into<Self::PI> + Copy + Eq + Hash;
|
|
type SI: GetPetgraphIndex + Into<Self::PI> + Copy + Eq + Hash;
|
|
type BI: GetPetgraphIndex + Into<Self::PI> + Copy + Eq + Hash;
|
|
|
|
#[inline(always)]
|
|
fn recording<'a>(
|
|
&'a mut self,
|
|
recorder: &'a mut GeometryEdit<
|
|
Self::PW,
|
|
Self::DW,
|
|
Self::SW,
|
|
Self::BW,
|
|
Self::CW,
|
|
Self::PI,
|
|
Self::DI,
|
|
Self::SI,
|
|
Self::BI,
|
|
>,
|
|
) -> Recording<'a, Self> {
|
|
Recording {
|
|
inner: self,
|
|
recorder,
|
|
}
|
|
}
|
|
}
|
|
|
|
pub type RecordingEdit<T: Recordable + ?Sized> = GeometryEdit<
|
|
<T as Recordable>::PW,
|
|
<T as Recordable>::DW,
|
|
<T as Recordable>::SW,
|
|
<T as Recordable>::BW,
|
|
<T as Recordable>::CW,
|
|
<T as Recordable>::PI,
|
|
<T as Recordable>::DI,
|
|
<T as Recordable>::SI,
|
|
<T as Recordable>::BI,
|
|
>;
|
|
|
|
pub struct Recording<'a, T: Recordable + ?Sized> {
|
|
pub inner: &'a mut T,
|
|
pub recorder: &'a mut RecordingEdit<T>,
|
|
}
|
|
|
|
impl<'a, T> fmt::Debug for Recording<'a, T>
|
|
where
|
|
T: Recordable + fmt::Debug + ?Sized,
|
|
<T as Recordable>::PW: fmt::Debug,
|
|
<T as Recordable>::DW: fmt::Debug,
|
|
<T as Recordable>::SW: fmt::Debug,
|
|
<T as Recordable>::BW: fmt::Debug,
|
|
<T as Recordable>::CW: fmt::Debug,
|
|
<T as Recordable>::PI: fmt::Debug,
|
|
<T as Recordable>::DI: fmt::Debug,
|
|
<T as Recordable>::SI: fmt::Debug,
|
|
<T as Recordable>::BI: fmt::Debug,
|
|
{
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
f.debug_struct("Recording")
|
|
.field("inner", &self.inner)
|
|
.field("recorder", &self.recorder)
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
// this is a hack, but it allows us to not needing as much boilerplate for delegations
|
|
impl<'a, T: Recordable + ?Sized> core::ops::Deref for Recording<'a, T> {
|
|
type Target = T;
|
|
|
|
#[inline(always)]
|
|
fn deref(&self) -> &T {
|
|
self.inner
|
|
}
|
|
}
|
|
|
|
impl<'a, T>
|
|
ApplyGeometryEdit<
|
|
<T as Recordable>::PW,
|
|
<T as Recordable>::DW,
|
|
<T as Recordable>::SW,
|
|
<T as Recordable>::BW,
|
|
<T as Recordable>::CW,
|
|
<T as Recordable>::PI,
|
|
<T as Recordable>::DI,
|
|
<T as Recordable>::SI,
|
|
<T as Recordable>::BI,
|
|
> for Recording<'a, T>
|
|
where
|
|
T: Recordable
|
|
+ ?Sized
|
|
+ ApplyGeometryEdit<
|
|
<T as Recordable>::PW,
|
|
<T as Recordable>::DW,
|
|
<T as Recordable>::SW,
|
|
<T as Recordable>::BW,
|
|
<T as Recordable>::CW,
|
|
<T as Recordable>::PI,
|
|
<T as Recordable>::DI,
|
|
<T as Recordable>::SI,
|
|
<T as Recordable>::BI,
|
|
>,
|
|
{
|
|
#[inline(always)]
|
|
fn apply(
|
|
&mut self,
|
|
edit: &GeometryEdit<
|
|
<T as Recordable>::PW,
|
|
<T as Recordable>::DW,
|
|
<T as Recordable>::SW,
|
|
<T as Recordable>::BW,
|
|
<T as Recordable>::CW,
|
|
<T as Recordable>::PI,
|
|
<T as Recordable>::DI,
|
|
<T as Recordable>::SI,
|
|
<T as Recordable>::BI,
|
|
>,
|
|
) {
|
|
self.inner.apply(edit)
|
|
}
|
|
}
|