Skip to content
8 changes: 6 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
[package]

name = "intervallum"
version = "1.4.2"
version = "1.4.3"
authors = [ "Pierre Talbot <pierre.talbot@uni.lu>" ]

description = "Generic interval and interval set library."
documentation = "https://docs.rs/intervallum/1.4.2/interval/"
documentation = "https://docs.rs/intervallum/1.4.3/interval/"
repository = "https://github.com/ptal/intervallum"
readme = "README.md"
keywords = ["interval", "math", "data-structure", "containers", "interval-set"]
Expand All @@ -24,3 +24,7 @@ num-traits = "0.2.14"
bit-set = "0.5.0"
gcollections = "1.5.0"
trilean = "1.1.0"
serde = "1.0.219"

[dev-dependencies]
serde_test = "1.0.177"
178 changes: 177 additions & 1 deletion src/libinterval/interval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,15 @@
use crate::ops::*;
use gcollections::ops::*;
use gcollections::*;
use serde::de::{self, SeqAccess, Visitor};
use serde::ser::SerializeTuple;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use trilean::SKleene;

use num_traits::{Num, Zero};
use std::cmp::{max, min};
use std::fmt::{Display, Error, Formatter};
use std::fmt::{self, Display, Error, Formatter};
use std::marker::PhantomData;
use std::ops::{Add, Mul, Sub};

/// Closed interval (endpoints included).
Expand All @@ -51,6 +55,84 @@ pub struct Interval<Bound> {
ub: Bound,
}

impl<Bound> Serialize for Interval<Bound>
where
Bound: Serialize + Width + Num,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
if self.is_empty() {
serializer.serialize_none()
} else {
let mut tuple = serializer.serialize_tuple(2)?;
tuple.serialize_element(&self.lb)?;
tuple.serialize_element(&self.ub)?;
tuple.end()
}
}
}

impl<'de, Bound> Deserialize<'de> for Interval<Bound>
where
Bound: Width + Num + Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct IntervalVisitor<Bound> {
marker: PhantomData<fn() -> Bound>,
}
impl<Bound> IntervalVisitor<Bound> {
fn new() -> Self {
IntervalVisitor {
marker: PhantomData,
}
}
}
impl<'de, Bound> Visitor<'de> for IntervalVisitor<Bound>
where
Bound: Width + Deserialize<'de> + Num,
{
type Value = Interval<Bound>;

fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("tuple of two numbers or none")
}

fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let lower = seq
.next_element::<Bound>()?
.ok_or_else(|| de::Error::invalid_length(0, &self))?;
let upper = seq
.next_element::<Bound>()?
.ok_or_else(|| de::Error::invalid_length(1, &self))?;
let mut extra_elements = 0;
while seq.next_element::<de::IgnoredAny>()?.is_some() {
extra_elements += 1;
}
if extra_elements > 0 {
return Err(de::Error::invalid_length(2 + extra_elements, &self));
}
Ok(Interval::new(lower, upper))
}

fn visit_none<E>(self) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Interval::<Bound>::empty())
}
}
deserializer.deserialize_any(IntervalVisitor::new())
}
}

impl<Bound> IntervalKind for Interval<Bound> {}

impl<Bound> Collection for Interval<Bound> {
Expand Down Expand Up @@ -1371,6 +1453,8 @@ where
#[allow(non_upper_case_globals)]
#[cfg(test)]
mod tests {
use serde_test::{assert_de_tokens, assert_de_tokens_error, assert_tokens, Token};

use super::*;

const empty: Interval<i32> = Interval { lb: 1, ub: 0 };
Expand Down Expand Up @@ -2334,4 +2418,96 @@ mod tests {
);
tester.test_all();
}

#[test]
fn test_ser_de_interval() {
let interval = Interval::new(10, 20);
assert_tokens(
&interval,
&[
Token::Tuple { len: 2 },
Token::I32(10),
Token::I32(20),
Token::TupleEnd,
],
);
}

#[test]
fn test_de_interval_mixed_types() {
let interval = Interval::new(-5, 15);
assert_de_tokens::<Interval<i32>>(
&interval,
&[
Token::Tuple { len: 2 },
Token::I32(-5),
Token::I64(15),
Token::TupleEnd,
],
);
}

#[test]
fn test_de_interval_extra_token() {
assert_de_tokens_error::<Interval<i32>>(
&[
Token::Tuple { len: 3 },
Token::I32(10),
Token::I32(20),
Token::I32(30),
Token::TupleEnd,
],
"invalid length 3, expected tuple of two numbers or none",
);
}

#[test]
fn test_de_interval_extra_tokens() {
assert_de_tokens_error::<Interval<i32>>(
&[
Token::Tuple { len: 5 },
Token::I32(10),
Token::I32(20),
Token::I32(30),
Token::I32(40),
Token::I32(50),
Token::TupleEnd,
],
"invalid length 5, expected tuple of two numbers or none",
);
}

#[test]
fn test_ser_de_interval_u8() {
let interval = Interval::<u8>::new(10, 20);
assert_tokens(
&interval,
&[
Token::Tuple { len: 2 },
Token::U8(10),
Token::U8(20),
Token::TupleEnd,
],
);
}

#[test]
fn test_ser_de_interval_i64() {
let interval = Interval::<i64>::whole();
assert_tokens(
&interval,
&[
Token::Tuple { len: 2 },
Token::I64(<i64 as Width>::min_value()),
Token::I64(<i64 as Width>::max_value()),
Token::TupleEnd,
],
);
}

#[test]
fn test_ser_de_empty_interval() {
let interval = Interval::<i32>::empty();
assert_tokens(&interval, &[Token::None]);
}
}
123 changes: 123 additions & 0 deletions src/libinterval/interval_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,14 @@ use crate::interval::ToInterval;
use crate::ops::*;
use gcollections::ops::*;
use gcollections::*;
use serde::de::SeqAccess;
use serde::de::Visitor;
use serde::Deserialize;
use serde::Serialize;
use std::fmt;
use std::fmt::{Display, Error, Formatter};
use std::iter::{IntoIterator, Peekable};
use std::marker::PhantomData;
use std::ops::{Add, Mul, Sub};
use trilean::SKleene;

Expand All @@ -46,6 +52,78 @@ pub struct IntervalSet<Bound: Width> {
size: Bound::Output,
}

impl<Bound> Serialize for IntervalSet<Bound>
where
Bound: Width + Num + Serialize,
Interval<Bound>: Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
if self.is_empty() {
serializer.serialize_none()
} else {
serializer.collect_seq(&self.intervals)
}
}
}

impl<'de, Bound> Deserialize<'de> for IntervalSet<Bound>
where
Bound: Width + Num + Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
struct IntervalSetVisitor<Bound> {
marker: PhantomData<fn() -> Interval<Bound>>,
}
impl<Bound> IntervalSetVisitor<Bound> {
fn new() -> Self {
IntervalSetVisitor {
marker: PhantomData,
}
}
}
impl<'de, Bound> Visitor<'de> for IntervalSetVisitor<Bound>
where
Bound: Width + Deserialize<'de> + Num,
{
type Value = IntervalSet<Bound>;

fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("sequence of intervals")
}

fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let mut intervals = Vec::new();
if let Some(size) = seq.size_hint() {
intervals.reserve(size);
}
while let Some(interval) = seq.next_element::<Interval<Bound>>()? {
intervals.push(interval);
}
let mut interval_set = IntervalSet::empty();
interval_set.extend(intervals);
Ok(interval_set)
}

fn visit_none<E>(self) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(IntervalSet::empty())
}
}
deserializer.deserialize_any(IntervalSetVisitor::new())
}
}

impl<Bound: Width> IntervalKind for IntervalSet<Bound> {}

impl<Bound: Width> Collection for IntervalSet<Bound> {
Expand Down Expand Up @@ -1357,6 +1435,8 @@ where
#[allow(non_upper_case_globals)]
#[cfg(test)]
mod tests {
use serde_test::{assert_tokens, Token};

use super::*;

const extend_example: [(i32, i32); 2] = [(11, 33), (-55, -44)];
Expand Down Expand Up @@ -2749,4 +2829,47 @@ mod tests {
);
}
}

#[test]
fn test_ser_de_single_interval_set() {
assert_tokens(
&IntervalSet::from_interval(Interval::new(8, 12)),
&[
Token::Seq { len: Some(1) },
Token::Tuple { len: 2 },
Token::I32(8),
Token::I32(12),
Token::TupleEnd,
Token::SeqEnd,
],
);
}

#[test]
fn test_ser_de_multiple_interval_set() {
assert_tokens(
&[(20, 21), (3, 5), (-10, -5)].to_interval_set(),
&[
Token::Seq { len: Some(3) },
Token::Tuple { len: 2 },
Token::I32(-10),
Token::I32(-5),
Token::TupleEnd,
Token::Tuple { len: 2 },
Token::I32(3),
Token::I32(5),
Token::TupleEnd,
Token::Tuple { len: 2 },
Token::I32(20),
Token::I32(21),
Token::TupleEnd,
Token::SeqEnd,
],
);
}

#[test]
fn test_ser_de_empty_interval_set() {
assert_tokens(&IntervalSet::<i32>::empty(), &[Token::None]);
}
}