Skip to content

Commit

Permalink
refactor: add traversal
Browse files Browse the repository at this point in the history
  • Loading branch information
waynevanson committed Sep 4, 2023
1 parent 042aa7b commit 155b5fa
Show file tree
Hide file tree
Showing 3 changed files with 177 additions and 10 deletions.
90 changes: 87 additions & 3 deletions packages/uischema/src/optics/optional.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
use std::marker::PhantomData;

pub trait OptionalRef {}
pub trait OptionalRef {
type Source;
type Target;

pub trait OptionalMut: OptionalRef {}
fn get_optional_ref(&self, source: Self::Source) -> Option<Self::Target>;
fn set_ref(&self, target: Self::Target) -> Self::Source;
}

pub trait OptionalMut: OptionalRef {
fn get_optional_mut(&mut self, source: Self::Source) -> Option<Self::Target>;
fn set_mut(&mut self, target: Self::Target) -> Self::Source;
}

pub trait Optional: OptionalMut {}
pub trait Optional: OptionalMut {
fn get_optional(&self, source: Self::Source) -> Option<Self::Target>;
fn set_mut(self, target: Self::Target) -> Self::Source;
}

pub struct OptionalId<S> {
phantom: PhantomData<S>,
Expand All @@ -17,3 +29,75 @@ impl<S> Default for OptionalId<S> {
}
}
}

impl<S> OptionalRef for OptionalId<S> {
type Source = S;
type Target = S;

fn get_optional_ref(&self, source: Self::Source) -> Option<Self::Target> {
Some(source)
}

fn set_ref(&self, target: Self::Target) -> Self::Source {
target
}
}

impl<S> OptionalMut for OptionalId<S> {
fn get_optional_mut(&mut self, source: Self::Source) -> Option<Self::Target> {
Some(source)
}

fn set_mut(&mut self, target: Self::Target) -> Self::Source {
target
}
}

struct OptionalInvariantMap<O, F, G> {
optional: O,
covariant: F,
contravariant: G,
}

impl<O, F, G, S, A, B> OptionalRef for OptionalInvariantMap<O, F, G>
where
O: OptionalRef<Source = S, Target = A>,
F: Fn(A) -> B,
G: Fn(B) -> A,
{
type Source = S;
type Target = B;

fn get_optional_ref(&self, source: Self::Source) -> Option<Self::Target> {
// Option::map is FnOnce, not Fn
#[allow(clippy::manual_map)]
match self.optional.get_optional_ref(source) {
Some(a) => Some((self.covariant)(a)),
None => None,
}
}

fn set_ref(&self, target: Self::Target) -> Self::Source {
self.optional.set_ref((self.contravariant)(target))
}
}

impl<O, F, G, S, A, B> OptionalMut for OptionalInvariantMap<O, F, G>
where
O: OptionalMut<Source = S, Target = A>,
F: Fn(A) -> B,
G: Fn(B) -> A,
{
fn get_optional_mut(&mut self, source: Self::Source) -> Option<Self::Target> {
// Option::map is FnOnce, not Fn
#[allow(clippy::manual_map)]
match self.optional.get_optional_ref(source) {
Some(a) => Some((self.covariant)(a)),
None => None,
}
}

fn set_mut(&mut self, target: Self::Target) -> Self::Source {
self.optional.set_ref((self.contravariant)(target))
}
}
1 change: 1 addition & 0 deletions packages/uischema/src/optics/prism.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pub trait PrismRef {
type Target;

fn get_option_ref(&self, source: Self::Source) -> Option<Self::Target>;
fn set_ref() {}
}

pub trait PrismMut: PrismRef {
Expand Down
96 changes: 89 additions & 7 deletions packages/uischema/src/optics/traversal.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,102 @@
use std::iter::FromIterator;
use std::{iter::FromIterator, marker::PhantomData};

pub trait TraversalRef {
type Source;
type Target;
type Container: FromIterator<Self::Target> + IntoIterator<Item = Self::Target>;
type Container;

fn get_all_ref(&self, source: Self::Source) -> Self::Container;
fn set_all_ref(&self, source: Self::Source, target: Self::Target) -> Self::Container;
fn set_all_ref(&self, source: Self::Source, target: Self::Target) -> Self::Source;
}

pub trait TraversalMut: TraversalRef {
fn get_all_mut(&self, source: Self::Source) -> Self::Container;
fn set_all_mut(&self, source: Self::Source, target: Self::Target) -> Self::Container;
fn get_all_mut(&mut self, source: Self::Source) -> Self::Container;
fn set_all_mut(&mut self, source: Self::Source, target: Self::Target) -> Self::Source;
}

pub trait Traversal: TraversalMut {
fn get_all(&self, source: Self::Source) -> Self::Container;
fn set_all(&self, source: Self::Source, target: Self::Target) -> Self::Container;
fn get_all(self, source: Self::Source) -> Self::Container;
fn set_all(self, source: Self::Source, target: Self::Target) -> Self::Source;
}

pub struct TraversalId<I> {
phantom: PhantomData<I>,
}

impl<I> TraversalRef for TraversalId<I>
where
I: FromIterator<I::Item> + IntoIterator,
I::Item: Clone,
{
type Source = I;
type Target = I::Item;
type Container = I;

fn get_all_ref(&self, source: Self::Source) -> Self::Container {
source
}

fn set_all_ref(&self, source: Self::Source, target: Self::Target) -> Self::Source {
source.into_iter().map(|_| target.clone()).collect()
}
}

impl<I> TraversalMut for TraversalId<I>
where
I: FromIterator<I::Item> + IntoIterator,
I::Item: Clone,
{
fn get_all_mut(&mut self, source: Self::Source) -> Self::Container {
source
}

fn set_all_mut(&mut self, source: Self::Source, target: Self::Target) -> Self::Source {
source.into_iter().map(|_| target.clone()).collect()
}
}

impl<I> Traversal for TraversalId<I>
where
I: FromIterator<I::Item> + IntoIterator,
I::Item: Clone,
{
fn get_all(self, source: Self::Source) -> Self::Container {
source
}

fn set_all(self, source: Self::Source, target: Self::Target) -> Self::Source {
source.into_iter().map(|_| target.clone()).collect()
}
}

pub struct TraversalInvariantMap<T, F, G> {
traversal: T,
covariant: F,
contravariant: G,
}

impl<T, F, G, B> TraversalRef for TraversalInvariantMap<T, F, G>
where
T: TraversalRef,
T::Container: IntoIterator<Item = T::Target> + FromIterator<B>,
T::Target: Clone,
F: Fn(T::Target) -> B,
G: Fn(B) -> T::Target,
{
type Source = T::Source;
type Target = B;
type Container = T::Container;

fn get_all_ref(&self, source: Self::Source) -> Self::Container {
self.traversal
.get_all_ref(source)
.into_iter()
.map(|target| (self.covariant)(target))
.collect()
}

fn set_all_ref(&self, source: Self::Source, target: Self::Target) -> Self::Source {
self.traversal
.set_all_ref(source, (self.contravariant)(target))
}
}

0 comments on commit 155b5fa

Please sign in to comment.