Last active
November 15, 2019 23:52
-
-
Save olson-sean-k/22cf2af7d03bc29577d0b48f54046827 to your computer and use it in GitHub Desktop.
A more generic mutation API for Plexus.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::fmt::Debug; | |
use std::hash::Hash; | |
use std::mem; | |
pub trait Transact<T>: Sized { | |
type Output; | |
type Error: Debug; | |
fn commit(self) -> Result<Self::Output, Self::Error>; | |
fn commit_with<F, U, E>(mut self, mut f: F) -> Result<(Self::Output, U), Self::Error> | |
where | |
F: FnMut(&mut Self) -> Result<U, E>, | |
E: Into<Self::Error>, | |
{ | |
let output = f(&mut self); | |
match output { | |
Ok(value) => self.commit().map(|output| (output, value)), | |
Err(error) => { | |
self.abort(); | |
Err(error.into()) | |
} | |
} | |
} | |
fn abort(self) {} | |
} | |
pub trait TransactFrom<T>: From<T> + Transact<T> {} | |
impl<T, U> TransactFrom<U> for T where T: From<U> + Transact<U> {} | |
pub trait Mutate<T>: Transact<T, Output = T> { | |
fn replace(target: &mut T, replacement: T) -> Replace<T, Self> | |
where | |
Self: TransactFrom<T>, | |
{ | |
Replace::replace(target, replacement) | |
} | |
} | |
impl<T, U> Mutate<U> for T where T: Transact<U, Output = U> {} | |
pub trait MappedInput: Transact<<Self as MappedInput>::Input> { | |
type Input; | |
} | |
pub type MappedOutput<T> = <T as Transact<<T as MappedInput>::Input>>::Output; | |
pub struct Replace<'a, T, M> | |
where | |
M: Mutate<T> + TransactFrom<T>, | |
{ | |
inner: Option<(&'a mut T, M)>, | |
} | |
impl<'a, T, M> Replace<'a, T, M> | |
where | |
M: Mutate<T> + TransactFrom<T>, | |
{ | |
pub fn replace(target: &'a mut T, replacement: T) -> Self { | |
let mutant = mem::replace(target, replacement); | |
Replace { | |
inner: Some((target, M::from(mutant))), | |
} | |
} | |
fn drain(&mut self) -> (&'a mut T, M) { | |
self.inner.take().unwrap() | |
} | |
fn drain_and_commit(&mut self) -> Result<&'a mut T, <Self as Transact<&'a mut T>>::Error> { | |
let (target, inner) = self.drain(); | |
let mutant = inner.commit()?; | |
mem::replace(target, mutant); | |
Ok(target) | |
} | |
fn drain_and_abort(&mut self) { | |
let (_, inner) = self.drain(); | |
inner.abort(); | |
} | |
} | |
impl<'a, T, M> AsRef<M> for Replace<'a, T, M> | |
where | |
M: Mutate<T> + TransactFrom<T>, | |
{ | |
fn as_ref(&self) -> &M { | |
&self.inner.as_ref().unwrap().1 | |
} | |
} | |
impl<'a, T, M> Drop for Replace<'a, T, M> | |
where | |
M: Mutate<T> + TransactFrom<T>, | |
{ | |
fn drop(&mut self) { | |
self.drain_and_abort() | |
} | |
} | |
impl<'a, T, M> From<&'a mut T> for Replace<'a, T, M> | |
where | |
T: Default, | |
M: Mutate<T> + TransactFrom<T>, | |
{ | |
fn from(target: &'a mut T) -> Self { | |
Self::replace(target, Default::default()) | |
} | |
} | |
impl<'a, T, M> Transact<&'a mut T> for Replace<'a, T, M> | |
where | |
M: Mutate<T> + TransactFrom<T>, | |
{ | |
type Output = &'a mut T; | |
type Error = <M as Transact<T>>::Error; | |
fn commit(mut self) -> Result<Self::Output, Self::Error> { | |
let mutant = self.drain_and_commit(); | |
mem::forget(self); | |
mutant | |
} | |
fn abort(mut self) { | |
self.drain_and_abort(); | |
mem::forget(self); | |
} | |
} | |
pub type Manifold<B> = <B as MeshBuilder>::Manifold; | |
pub type Facet<B> = <<B as MeshBuilder>::Manifold as ManifoldBuilder>::Facet; | |
pub trait MeshBuilder: MappedInput { | |
type Manifold: ManifoldBuilder<Error = Self::Error>; | |
fn manifold_with<F, T, E>( | |
&mut self, | |
f: F, | |
) -> Result<(MappedOutput<Self::Manifold>, T), Self::Error> | |
where | |
F: FnOnce(&mut Self::Manifold) -> Result<T, E>, | |
E: Into<Self::Error>; | |
} | |
pub trait ManifoldBuilder: MappedInput { | |
type Facet: FacetBuilder<Self::Key, Error = Self::Error>; | |
type Vertex; | |
type Key: Eq + Hash; | |
fn facet_with<F, T, E>(&mut self, f: F) -> Result<(MappedOutput<Self::Facet>, T), Self::Error> | |
where | |
F: FnOnce(&mut Self::Facet) -> Result<T, E>, | |
E: Into<Self::Error>; | |
fn insert_vertex(&mut self, vertex: Self::Vertex) -> Result<Self::Key, Self::Error>; | |
} | |
pub trait FacetBuilder<K>: MappedInput | |
where | |
K: Eq + Hash, | |
{ | |
type Face: Default; | |
type Key: Eq + Hash; | |
fn insert_facet<T>(&mut self, perimeter: T, face: Self::Face) -> Result<Self::Key, Self::Error> | |
where | |
T: AsRef<[K]>; | |
} | |
fn triangle<B>(mut builder: B) -> Result<B::Output, B::Error> | |
where | |
B: MeshBuilder, | |
Manifold<B>: ManifoldBuilder<Vertex = ()>, | |
Facet<B>: FacetBuilder<<Manifold<B> as ManifoldBuilder>::Key, Face = ()>, | |
{ | |
builder.manifold_with(|builder| { | |
let a = builder.insert_vertex(())?; | |
let b = builder.insert_vertex(())?; | |
let c = builder.insert_vertex(())?; | |
builder.facet_with(move |builder| builder.insert_facet(&[a, b, c], ())) | |
})?; | |
builder.commit() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment