#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Delta<T> {
Source(T),
Target(T),
Transition(T, T),
}
impl<T> Delta<T> {
pub fn new(source: T, target: T) -> Self {
Self::Transition(source, target)
}
pub fn from_option_source(source: Option<T>, target: T) -> Self {
match source {
Some(source) => Self::Transition(source, target),
None => Self::Target(target),
}
}
pub fn from_option_target(source: T, target: Option<T>) -> Self {
match target {
Some(target) => Self::Transition(source, target),
None => Self::Source(source),
}
}
pub fn from_options(source: Option<T>, target: Option<T>) -> Option<Self> {
match (source, target) {
(Some(source), Some(target)) => Some(Self::Transition(source, target)),
(Some(source), None) => Some(Self::Source(source)),
(None, Some(target)) => Some(Self::Target(target)),
(None, None) => None,
}
}
pub fn source(&self) -> Option<&T> {
match self {
Delta::Source(source) => Some(source),
Delta::Target(_) => None,
Delta::Transition(source, _) => Some(source),
}
}
pub fn target(&self) -> Option<&T> {
match self {
Delta::Source(_) => None,
Delta::Target(target) => Some(target),
Delta::Transition(_, target) => Some(target),
}
}
pub fn map<U, F: FnMut(T) -> U>(self, mut transform: F) -> Delta<U> {
match self {
Delta::Source(source) => Delta::Source(transform(source)),
Delta::Target(target) => Delta::Target(transform(target)),
Delta::Transition(source, target) => {
Delta::Transition(transform(source), transform(target))
}
}
}
pub fn map_any<U, F: FnMut(T) -> Option<U>>(self, mut transform: F) -> Option<Delta<U>> {
match self {
Delta::Source(source) => transform(source).map(Delta::Source),
Delta::Target(target) => transform(target).map(Delta::Target),
Delta::Transition(source, target) => {
let source = transform(source);
let target = transform(target);
if let Some(source) = source {
if let Some(target) = target {
Some(Delta::Transition(source, target))
} else {
Some(Delta::Source(source))
}
} else {
target.map(Delta::Target)
}
}
}
}
pub fn map_all<U, F: FnMut(T) -> Option<U>>(self, mut transform: F) -> Option<Delta<U>> {
match self {
Delta::Source(source) => transform(source).map(Delta::Source),
Delta::Target(target) => transform(target).map(Delta::Target),
Delta::Transition(source, target) => {
let source = transform(source);
let target = transform(target);
if let Some(source) = source {
target.map(|target| Delta::Transition(source, target))
} else {
None
}
}
}
}
pub fn resolve(self, side: Side) -> T {
match side {
Side::Source => match self {
Delta::Source(source) => source,
Delta::Target(target) => target,
Delta::Transition(source, _) => source,
},
Side::Target => match self {
Delta::Source(source) => source,
Delta::Target(target) => target,
Delta::Transition(_, target) => target,
},
}
}
pub fn first(self) -> T {
self.resolve(Side::Source)
}
pub fn last(self) -> T {
self.resolve(Side::Target)
}
pub fn merge<F: FnOnce(T, T) -> T>(self, coalesce: F) -> T {
match self {
Delta::Source(source) => source,
Delta::Target(target) => target,
Delta::Transition(source, target) => coalesce(source, target),
}
}
pub fn identity(element: T) -> Self
where
T: Copy,
{
Delta::Transition(element, element)
}
pub fn is_identity_by<F: FnOnce(&T, &T) -> bool>(self, predicate: F) -> bool {
match self {
Delta::Source(_) => false,
Delta::Target(_) => false,
Delta::Transition(source, target) => predicate(&source, &target),
}
}
pub fn is_identity(self) -> bool
where
T: PartialEq,
{
self.is_identity_by(|s, t| s == t)
}
pub const fn as_ref(&self) -> Delta<&T> {
match *self {
Delta::Source(ref source) => Delta::Source(source),
Delta::Target(ref target) => Delta::Target(target),
Delta::Transition(ref source, ref target) => Delta::Transition(source, target),
}
}
pub const fn as_mut(&mut self) -> Delta<&mut T> {
match *self {
Delta::Source(ref mut source) => Delta::Source(source),
Delta::Target(ref mut target) => Delta::Target(target),
Delta::Transition(ref mut source, ref mut target) => Delta::Transition(source, target),
}
}
pub fn as_deref(&self) -> Delta<&T::Target>
where
T: std::ops::Deref,
{
self.as_ref().map(|x| x.deref())
}
pub fn as_deref_mut(&mut self) -> Delta<&mut T::Target>
where
T: std::ops::DerefMut,
{
self.as_mut().map(|x| x.deref_mut())
}
}
impl<T> Delta<&mut T> {
pub const fn copied(self) -> Delta<T>
where
T: Copy,
{
match self {
Delta::Source(&mut source) => Delta::Source(source),
Delta::Target(&mut target) => Delta::Target(target),
Delta::Transition(&mut source, &mut target) => Delta::Transition(source, target),
}
}
pub fn cloned(self) -> Delta<T>
where
T: Clone,
{
match self {
Delta::Source(source) => Delta::Source(source.clone()),
Delta::Target(target) => Delta::Target(target.clone()),
Delta::Transition(source, target) => Delta::Transition(source.clone(), target.clone()),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Side {
Source,
Target,
}