use crate::kind::*;
use crate::ops::*;
use std::ops::*;
fn binary_map_unwrap_or<T, U, R, F>(x: &Optional<T>, y: &Optional<U>, default: R, f: F) -> R where
F: FnOnce(&T, &U) -> R
{
if let Some(ref x) = x.as_ref() {
if let Some(ref y) = y.as_ref() {
return f(x, y)
}
}
default
}
fn binary_value_map_unwrap_or<T, U, R, F>(x: &Optional<T>, y: &U, default: R, f: F) -> R where
F: FnOnce(&T, &U) -> R
{
x.as_ref().map_or(default, |x| f(x, y))
}
fn binary_value_map<T, U, R, F>(x: Optional<T>, y: U, f: F) -> Optional<R> where
F: FnOnce(T, U) -> R
{
x.unwrap().map_or(Optional::empty(), |x|
Optional::singleton(f(x, y)))
}
fn binary_map<T, U, R, F>(x: Optional<T>, y: Optional<U>, f: F) -> Optional<R> where
F: FnOnce(T, U) -> R
{
x.unwrap().map_or(Optional::empty(), |x|
y.unwrap().map_or(Optional::empty(), |y|
Optional::singleton(f(x, y))))
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct Optional<T>
{
value: Option<T>
}
impl<T> Optional<T>
{
pub fn wrap(value: Option<T>) -> Optional<T> {
Optional {
value: value
}
}
pub fn unwrap(self) -> Option<T> {
self.value
}
}
impl<T> Collection for Optional<T> {
type Item = T;
}
impl<T> Deref for Optional<T>
{
type Target = Option<T>;
fn deref<'a>(&'a self) -> &'a Option<T> {
&self.value
}
}
impl<T> DerefMut for Optional<T>
{
fn deref_mut<'a>(&'a mut self) -> &'a mut Option<T> {
&mut self.value
}
}
impl<T> Cardinality for Optional<T>
{
type Size = usize;
fn size(&self) -> usize {
self.is_some() as usize
}
}
impl<T> Singleton for Optional<T>
{
fn singleton(value: T) -> Optional<T> {
Optional::wrap(Some(value))
}
}
impl<T> Empty for Optional<T>
{
fn empty() -> Optional<T> {
Optional::wrap(None)
}
}
impl<T> Intersection<Optional<T>> for Optional<T> where
T: Clone + PartialEq
{
type Output = Optional<T>;
fn intersection(&self, other: &Optional<T>) -> Self::Output {
if self.is_empty() || other.is_empty() || self != other {
Optional::empty()
}
else {
self.clone()
}
}
}
impl<T> Intersection<T> for Optional<T> where
T: Clone + PartialEq
{
type Output = Optional<T>;
fn intersection(&self, other: &T) -> Self::Output {
if self.is_empty() || self.as_ref().unwrap() != other {
Optional::empty()
}
else {
self.clone()
}
}
}
macro_rules! primitive_optional_intersection_operation
{
( $( $source:ty ),* ) =>
{$(
impl Intersection<Optional<$source>> for $source
{
type Output = Optional<$source>;
fn intersection(&self, other: &Optional<$source>) -> Self::Output {
other.intersection(self)
}
}
)*}
}
primitive_optional_intersection_operation!(i8,u8,i16,u16,i32,u32,i64,u64,isize,usize,f32,f64,bool,char);
impl<T> Difference<Optional<T>> for Optional<T> where
T: Clone + PartialEq
{
type Output = Optional<T>;
fn difference(&self, other: &Optional<T>) -> Self::Output {
if self.is_empty() || self == other {
Optional::empty()
}
else {
self.clone()
}
}
}
impl<T> Difference<T> for Optional<T> where
T: Clone + PartialEq
{
type Output = Optional<T>;
fn difference(&self, other: &T) -> Self::Output {
if self.is_empty() || self.as_ref().unwrap() == other {
Optional::empty()
}
else {
self.clone()
}
}
}
macro_rules! primitive_optional_difference_operation
{
( $( $source:ty ),* ) =>
{$(
impl Difference<Optional<$source>> for $source
{
type Output = Optional<$source>;
fn difference(&self, other: &Optional<$source>) -> Self::Output {
if other.is_empty() || self != other.as_ref().unwrap() {
Optional::singleton(self.clone())
}
else {
Optional::empty()
}
}
}
)*}
}
primitive_optional_difference_operation!(i8,u8,i16,u16,i32,u32,i64,u64,isize,usize,f32,f64,bool,char);
impl<T, U> Disjoint<Optional<U>> for Optional<T> where
T: Disjoint<U>
{
fn is_disjoint(&self, other: &Optional<U>) -> bool {
self.is_empty() || other.is_empty() ||
self.as_ref().unwrap().is_disjoint(other.as_ref().unwrap())
}
}
impl<T, U> Disjoint<U> for Optional<T> where
T: Disjoint<U>,
U: GroundType
{
fn is_disjoint(&self, other: &U) -> bool {
self.is_empty() ||
self.as_ref().unwrap().is_disjoint(other)
}
}
macro_rules! primitive_optional_disjoint_operation
{
( $( $source:ty ),* ) =>
{$(
impl<T> Disjoint<Optional<T>> for $source where
T: Disjoint<$source>
{
fn is_disjoint(&self, other: &Optional<T>) -> bool {
other.is_disjoint(self)
}
}
)*}
}
primitive_optional_disjoint_operation!(i8,u8,i16,u16,i32,u32,i64,u64,isize,usize,f32,f64,bool,char);
impl<T> Contains for Optional<T> where
T: Eq
{
fn contains(&self, value: &T) -> bool {
self.as_ref().map_or(false, |x| x == value)
}
}
impl<T> Subset<Optional<T>> for Optional<T> where
T: Subset
{
fn is_subset(&self, other: &Optional<T>) -> bool {
if self.is_empty() { true }
else if other.is_empty() { false }
else {
self.as_ref().unwrap().is_subset(other.as_ref().unwrap())
}
}
}
impl<T> ProperSubset<Optional<T>> for Optional<T> where
T: Subset + PartialEq
{
fn is_proper_subset(&self, other: &Optional<T>) -> bool {
self.is_subset(other) && self != other
}
}
impl<T, U> Overlap<Optional<U>> for Optional<T> where
T: Overlap<U>
{
fn overlap(&self, other: &Optional<U>) -> bool {
binary_map_unwrap_or(self, other, false, T::overlap)
}
}
impl<T, U> Overlap<U> for Optional<T> where
T: Overlap<U>,
U: GroundType
{
fn overlap(&self, other: &U) -> bool {
binary_value_map_unwrap_or(self, other, false, T::overlap)
}
}
macro_rules! primitive_optional_overlap_operation
{
( $( $source:ty ),* ) =>
{$(
impl<T> Overlap<Optional<T>> for $source where
T: Overlap<$source>
{
fn overlap(&self, other: &Optional<T>) -> bool {
other.overlap(self)
}
}
)*}
}
primitive_optional_overlap_operation!(i8,u8,i16,u16,i32,u32,i64,u64,isize,usize,f32,f64,bool,char);
impl<T, U, R> Add<Optional<U>> for Optional<T> where
T: Add<U, Output=R>
{
type Output = Optional<R>;
fn add(self, other: Optional<U>) -> Self::Output {
binary_map(self, other, T::add)
}
}
impl<T, U, R> Add<U> for Optional<T> where
T: Add<U, Output=R>,
U: GroundType
{
type Output = Optional<R>;
fn add(self, other: U) -> Self::Output {
binary_value_map(self, other, T::add)
}
}
macro_rules! add_optional_arithmetics
{
( $( $source:ty ),* ) =>
{$(
impl<T, R> Add<Optional<T>> for $source where
T: Add<$source, Output=R>
{
type Output = Optional<R>;
fn add(self, rhs: Optional<T>) -> Self::Output {
rhs + self
}
}
)*}
}
add_optional_arithmetics!(i8,u8,i16,u16,i32,u32,i64,u64,isize,usize,f32,f64,bool,char);
impl<T, U, R> Sub<Optional<U>> for Optional<T> where
T: Sub<U, Output=R>
{
type Output = Optional<R>;
fn sub(self, other: Optional<U>) -> Self::Output {
binary_map(self, other, T::sub)
}
}
impl<T, U, R> Sub<U> for Optional<T> where
T: Sub<U, Output=R>,
U: GroundType
{
type Output = Optional<R>;
fn sub(self, other: U) -> Self::Output {
binary_value_map(self, other, T::sub)
}
}
macro_rules! sub_optional_arithmetics
{
( $( $source:ty ),* ) =>
{$(
impl Sub<Optional<$source>> for $source
{
type Output = Optional<$source>;
fn sub(self, other: Optional<$source>) -> Self::Output {
binary_value_map(other, self, |x, y| y - x)
}
}
)*}
}
sub_optional_arithmetics!(i8,u8,i16,u16,i32,u32,i64,u64,isize,usize,f32,f64);
impl<T, U, R> Mul<Optional<U>> for Optional<T> where
T: Mul<U, Output=R>
{
type Output = Optional<R>;
fn mul(self, other: Optional<U>) -> Self::Output {
binary_map(self, other, T::mul)
}
}
impl<T, U, R> Mul<U> for Optional<T> where
T: Mul<U, Output=R>,
U: GroundType
{
type Output = Optional<R>;
fn mul(self, other: U) -> Self::Output {
binary_value_map(self, other, T::mul)
}
}
macro_rules! mul_optional_arithmetics
{
( $( $source:ty ),* ) =>
{$(
impl<T, R> Mul<Optional<T>> for $source where
T: Mul<$source, Output=R>
{
type Output = Optional<R>;
fn mul(self, other: Optional<T>) -> Self::Output {
other.mul(self)
}
}
)*}
}
mul_optional_arithmetics!(i8,u8,i16,u16,i32,u32,i64,u64,isize,usize,f32,f64,bool,char);
#[allow(non_upper_case_globals)]
#[cfg(test)]
mod tests {
use super::*;
const empty: Optional<i32> = Optional { value: None };
const zero: Optional<i32> = Optional { value: Some(0) };
const ten: Optional<i32> = Optional { value: Some(10) };
#[test]
fn cardinality_test() {
assert_eq!(empty.size(), 0);
assert_eq!(zero.size(), 1);
assert_eq!(ten.size(), 1);
assert!(empty.is_empty());
assert!(!empty.is_singleton());
assert!(!zero.is_empty());
assert!(zero.is_singleton());
}
#[test]
fn constructors_test() {
assert_eq!(empty, Empty::empty());
assert_eq!(zero, Singleton::singleton(0));
}
#[test]
fn intersection_test() {
let sym_cases = vec![
(empty, empty, empty),
(empty, zero, empty),
(zero, zero, zero),
(zero, ten, empty),
(ten, ten, ten)
];
for (x,y,r) in sym_cases.into_iter() {
assert!(x.intersection(&y) == r, "{:?} intersection {:?} is not equal to {:?}", x, y, r);
assert!(y.intersection(&x) == r, "{:?} intersection {:?} is not equal to {:?}", y, x, r);
}
}
#[test]
fn difference_test() {
let cases = vec![
(empty, empty, empty, empty),
(empty, zero, empty, zero),
(zero, zero, empty, empty),
(zero, ten, zero, ten),
(ten, ten, empty, empty)
];
for (x,y,r1,r2) in cases.into_iter() {
assert!(x.difference(&y) == r1, "{:?} difference {:?} is not equal to {:?}", x, y, r1);
assert!(y.difference(&x) == r2, "{:?} difference {:?} is not equal to {:?}", y, x, r2);
}
}
#[test]
fn intersection_value_test() {
let sym_cases = vec![
(empty, 0, empty),
(empty, 1, empty),
(zero, 0, zero),
(zero, 1, empty),
(ten, 10, ten)
];
for (x,y,r) in sym_cases.into_iter() {
assert!(x.intersection(&y) == r, "{:?} intersection {:?} is not equal to {:?}", x, y, r);
assert!(y.intersection(&x) == r, "{:?} intersection {:?} is not equal to {:?}", y, x, r);
}
}
#[test]
fn difference_value_test() {
let cases = vec![
(empty, 0, empty, zero),
(zero, 0, empty, empty),
(zero, 10, zero, ten),
(ten, 10, empty, empty)
];
for (x,y,r1,r2) in cases.into_iter() {
assert!(x.difference(&y) == r1, "{:?} difference {:?} is not equal to {:?}", x, y, r1);
assert!(y.difference(&x) == r2, "{:?} difference {:?} is not equal to {:?}", y, x, r2);
}
}
#[test]
fn is_disjoint_and_overlap_test() {
let sym_cases = vec![
(empty, empty, true),
(empty, zero, true),
(zero, zero, false),
(zero, ten, true),
(ten, ten, false)
];
for (x,y,r) in sym_cases.into_iter() {
assert!(x.is_disjoint(&y) == r, "{:?} disjoint {:?} is not equal to {:?}", x, y, r);
assert!(y.is_disjoint(&x) == r, "{:?} disjoint {:?} is not equal to {:?}", y, x, r);
assert!(x.overlap(&y) == !r, "{:?} overlap {:?} is not equal to {:?}", x, y, !r);
assert!(y.overlap(&x) == !r, "{:?} overlap {:?} is not equal to {:?}", y, x, !r);
}
}
#[test]
fn contains_test() {
let cases = vec![
(empty, 0, false),
(empty, 1, false),
(zero, 0, true),
(zero, 1, false),
(ten, 9, false),
(ten, 10, true)
];
for (x,y,r) in cases.into_iter() {
assert!(x.contains(&y) == r, "{:?} contains {:?} is not equal to {:?}", x, y, r);
}
}
#[test]
fn subset_test() {
let cases = vec![
(empty, empty, true, true),
(empty, zero, true, false),
(zero, zero, true, true),
(zero, ten, false, false),
(ten, ten, true, true)
];
for (x,y,r1,r2) in cases.into_iter() {
assert!(x.is_subset(&y) == r1, "{:?} subset {:?} is not equal to {:?}", x, y, r1);
assert!(y.is_subset(&x) == r2, "{:?} subset {:?} is not equal to {:?}", y, x, r2);
}
}
#[test]
fn proper_subset_test() {
let cases = vec![
(empty, empty, false, false),
(empty, zero, true, false),
(zero, zero, false, false),
(zero, ten, false, false),
(ten, ten, false, false)
];
for (x,y,r1,r2) in cases.into_iter() {
assert!(x.is_proper_subset(&y) == r1, "{:?} proper_subset {:?} is not equal to {:?}", x, y, r1);
assert!(y.is_proper_subset(&x) == r2, "{:?} proper_subset {:?} is not equal to {:?}", y, x, r2);
}
}
#[test]
fn arithmetics_tests() {
let twenty = Optional::singleton(20);
let one_hundred = Optional::singleton(100);
let cases = vec![
(empty, empty, empty, empty, empty),
(empty, ten, empty, empty, empty),
(ten, empty, empty, empty, empty),
(ten, zero, ten, ten, zero),
(ten, ten, twenty,zero, one_hundred)
];
for (x,y,add,sub,mul) in cases.into_iter() {
assert!(x + y == add, "{:?} + {:?} is not equal to {:?}", x, y, add);
assert!(x - y == sub, "{:?} - {:?} is not equal to {:?}", x, y, sub);
assert!(x * y == mul, "{:?} * {:?} is not equal to {:?}", x, y, mul);
}
}
}