#[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,
}
}
}
impl<T> Delta<T> {
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<R, F: FnMut(T) -> R>(self, mut transform: F) -> Delta<R> {
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<R, F: FnMut(T) -> Option<R>>(self, mut transform: F) -> Option<Delta<R>> {
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<R, F: FnMut(T) -> Option<R>>(self, mut transform: F) -> Option<Delta<R>> {
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 is_identity<F: FnOnce(&T, &T) -> bool>(self, predicate: F) -> bool {
match self {
Delta::Source(_) => false,
Delta::Target(_) => false,
Delta::Transition(source, target) => predicate(&source, &target),
}
}
}
impl<T: Copy> Delta<T> {
pub fn identity(element: T) -> Self {
Delta::Transition(element, element)
}
}
pub enum Side {
Source,
Target,
}