Skip to content

Instantly share code, notes, and snippets.

@olson-sean-k
Last active November 15, 2019 23:52
Show Gist options
  • Save olson-sean-k/22cf2af7d03bc29577d0b48f54046827 to your computer and use it in GitHub Desktop.
Save olson-sean-k/22cf2af7d03bc29577d0b48f54046827 to your computer and use it in GitHub Desktop.
A more generic mutation API for Plexus.
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