diff --git a/.travis.yml b/.travis.yml index eb62afb..ea999b2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ language: rust rust: - nightly - beta -- 1.10.0 +- 1.20.0 addons: postgresql: 9.4 script: diff --git a/Cargo.toml b/Cargo.toml index a332b68..7c27408 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,20 +1,16 @@ [package] name = "postgres_range" -version = "0.8.2" +version = "0.9.0" authors = ["Steven Fackler "] license = "MIT" description = "Range support for rust-postgres" repository = "https://github.com/sfackler/rust-postgres-range" -documentation = "https://sfackler.github.io/rust-postgres-range/doc/v0.8.2/postgres_range" +documentation = "https://sfackler.github.io/rust-postgres-range/doc/v0.9.0/postgres_range" [dependencies] time = "0.1" -postgres = "0.11" -postgres-protocol = { git = "https://github.com/sfackler/rust-postgres-protocol" } +postgres = "0.15" +postgres-protocol = "0.3" [dev-dependencies] -postgres = { version = "0.11", features = ["with-time"] } - -[replace] -"postgres:0.11.11" = { git = "https://github.com/sfackler/rust-postgres" } -"fallible-iterator:0.1.2" = { git = "https://github.com/sfackler/rust-fallible-iterator" } +postgres = { version = "0.15", features = ["with-time"] } \ No newline at end of file diff --git a/src/impls.rs b/src/impls.rs index f070d96..d7c6a76 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -1,21 +1,24 @@ use std::error::Error; -use postgres::types::{Type, Kind, ToSql, FromSql, IsNull, SessionInfo}; -use postgres_protocol::types; +use postgres::types::{FromSql, IsNull, Kind, ToSql, Type}; +use postgres_protocol::{self as protocol, types}; -use {Range, RangeBound, BoundType, BoundSided, Normalizable}; +use {BoundSided, BoundType, Normalizable, Range, RangeBound}; -impl FromSql for Range where T: PartialOrd+Normalizable+FromSql { - fn from_sql(ty: &Type, raw: &[u8], info: &SessionInfo) -> Result, Box> { +impl FromSql for Range +where + T: PartialOrd + Normalizable + FromSql, +{ + fn from_sql(ty: &Type, raw: &[u8]) -> Result, Box> { let element_type = match ty.kind() { &Kind::Range(ref ty) => ty, - _ => panic!("unexpected type {:?}", ty) + _ => panic!("unexpected type {:?}", ty), }; - match try!(types::range_from_sql(raw)) { + match types::range_from_sql(raw)? { types::Range::Empty => Ok(Range::empty()), types::Range::Nonempty(lower, upper) => { - let lower = try!(bound_from_sql(lower, element_type, info)); - let upper = try!(bound_from_sql(upper, element_type, info)); + let lower = bound_from_sql(lower, element_type)?; + let upper = bound_from_sql(upper, element_type)?; Ok(Range::new(lower, upper)) } } @@ -29,42 +32,48 @@ impl FromSql for Range where T: PartialOrd+Normalizable+FromSql { } } -fn bound_from_sql(bound: types::RangeBound>, ty: &Type, info: &SessionInfo) -> Result>, Box> - where T: PartialOrd + Normalizable + FromSql, - S: BoundSided +fn bound_from_sql(bound: types::RangeBound>, ty: &Type) -> Result>, Box> +where + T: PartialOrd + Normalizable + FromSql, + S: BoundSided, { match bound { types::RangeBound::Exclusive(value) => { let value = match value { - Some(value) => try!(T::from_sql(ty, value, info)), - None => try!(T::from_sql_null(ty, info)), + Some(value) => T::from_sql(ty, value)?, + None => T::from_sql_null(ty)?, }; Ok(Some(RangeBound::new(value, BoundType::Exclusive))) - }, + } types::RangeBound::Inclusive(value) => { let value = match value { - Some(value) => try!(T::from_sql(ty, value, info)), - None => try!(T::from_sql_null(ty, info)), + Some(value) => T::from_sql(ty, value)?, + None => T::from_sql_null(ty)?, }; Ok(Some(RangeBound::new(value, BoundType::Inclusive))) - }, + } types::RangeBound::Unbounded => Ok(None), } } -impl ToSql for Range where T: PartialOrd+Normalizable+ToSql { - fn to_sql(&self, ty: &Type, mut buf: &mut Vec, info: &SessionInfo) -> Result> { +impl ToSql for Range +where + T: PartialOrd + Normalizable + ToSql, +{ + fn to_sql(&self, ty: &Type, buf: &mut Vec) -> Result> { let element_type = match ty.kind() { &Kind::Range(ref ty) => ty, - _ => panic!("unexpected type {:?}", ty) + _ => panic!("unexpected type {:?}", ty), }; if self.is_empty() { types::empty_range_to_sql(buf); } else { - try!(types::range_to_sql(|buf| bound_to_sql(self.lower(), element_type, info, buf), - |buf| bound_to_sql(self.upper(), element_type, info, buf), - buf)); + types::range_to_sql( + |buf| bound_to_sql(self.lower(), element_type, buf), + |buf| bound_to_sql(self.upper(), element_type, buf), + buf, + )?; } Ok(IsNull::No) @@ -80,15 +89,16 @@ impl ToSql for Range where T: PartialOrd+Normalizable+ToSql { to_sql_checked!(); } -fn bound_to_sql(bound: Option<&RangeBound>, ty: &Type, info: &SessionInfo, buf: &mut Vec) -> Result, Box> - where S: BoundSided, - T: ToSql +fn bound_to_sql(bound: Option<&RangeBound>, ty: &Type, buf: &mut Vec) -> Result, Box> +where + S: BoundSided, + T: ToSql, { match bound { Some(bound) => { - let null = match try!(bound.value.to_sql(ty, buf, info)) { - IsNull::Yes => types::IsNull::Yes, - IsNull::No => types::IsNull::No, + let null = match bound.value.to_sql(ty, buf)? { + IsNull::Yes => protocol::IsNull::Yes, + IsNull::No => protocol::IsNull::No, }; match bound.type_ { @@ -98,7 +108,6 @@ fn bound_to_sql(bound: Option<&RangeBound>, ty: &Type, info: &Sessio } None => Ok(types::RangeBound::Unbounded), } - } #[cfg(test)] @@ -130,10 +139,11 @@ mod test { }) } - fn test_type(sql_type: &str, checks: &[(T, S)]) { + fn test_type(sql_type: &str, checks: &[(T, S)]) { let conn = Connection::connect("postgres://postgres@localhost", TlsMode::None).unwrap(); for &(ref val, ref repr) in checks { - let stmt = conn.prepare(&*format!("SELECT {}::{}", *repr, sql_type)).unwrap(); + let stmt = conn.prepare(&*format!("SELECT {}::{}", *repr, sql_type)) + .unwrap(); let result = stmt.query(&[]).unwrap().iter().next().unwrap().get(0); assert!(val == &result); diff --git a/src/lib.rs b/src/lib.rs index 05733bf..55ffa69 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,5 @@ //! Types dealing with ranges of values -#![doc(html_root_url="https://sfackler.github.io/rust-postgres-range/doc/v0.8.2")] +#![doc(html_root_url = "https://sfackler.github.io/rust-postgres-range/doc/v0.8.2")] #[macro_use(to_sql_checked)] extern crate postgres; @@ -15,7 +15,7 @@ use std::marker::PhantomData; use time::Timespec; use BoundSide::{Lower, Upper}; -use BoundType::{Inclusive, Exclusive}; +use BoundType::{Exclusive, Inclusive}; use InnerRange::{Empty, Normal}; /// The `range!` macro can make it easier to create ranges. It roughly mirrors @@ -118,7 +118,9 @@ pub trait Normalizable: Sized { /// /// The logic here should match the logic performed by the equivalent /// Postgres type. - fn normalize(bound: RangeBound) -> RangeBound where S: BoundSided; + fn normalize(bound: RangeBound) -> RangeBound + where + S: BoundSided; } macro_rules! bounded_normalizable { @@ -145,7 +147,10 @@ bounded_normalizable!(i32); bounded_normalizable!(i64); impl Normalizable for Timespec { - fn normalize(bound: RangeBound) -> RangeBound where S: BoundSided { + fn normalize(bound: RangeBound) -> RangeBound + where + S: BoundSided, + { bound } } @@ -156,7 +161,7 @@ pub enum BoundSide { /// An upper bound. Upper, /// A lower bound. - Lower + Lower, } /// A trait implemented by phantom types indicating the type of the bound. @@ -189,7 +194,7 @@ pub enum BoundType { /// The bound includes its value. Inclusive, /// The bound excludes its value. - Exclusive + Exclusive, } /// Represents a one-sided bound. @@ -208,9 +213,18 @@ fn _is_send_sync() { is_send_sync::>(); } -impl Copy for RangeBound where S: BoundSided, T: Copy {} +impl Copy for RangeBound +where + S: BoundSided, + T: Copy, +{ +} -impl Clone for RangeBound where S: BoundSided, T: Clone { +impl Clone for RangeBound +where + S: BoundSided, + T: Clone, +{ fn clone(&self) -> RangeBound { RangeBound { value: self.value.clone(), @@ -220,7 +234,11 @@ impl Clone for RangeBound where S: BoundSided, T: Clone { } } -impl fmt::Debug for RangeBound where S: BoundSided, T: fmt::Debug { +impl fmt::Debug for RangeBound +where + S: BoundSided, + T: fmt::Debug, +{ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("RangeBound") .field("value", &self.value) @@ -229,7 +247,11 @@ impl fmt::Debug for RangeBound where S: BoundSided, T: fmt::Debug { } } -impl fmt::Display for RangeBound where S: BoundSided, T: fmt::Display { +impl fmt::Display for RangeBound +where + S: BoundSided, + T: fmt::Display, +{ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let (lower, upper) = match self.type_ { Inclusive => ('[', ']'), @@ -243,7 +265,11 @@ impl fmt::Display for RangeBound where S: BoundSided, T: fmt::Displa } } -impl PartialEq for RangeBound where S: BoundSided, T: PartialEq { +impl PartialEq for RangeBound +where + S: BoundSided, + T: PartialEq, +{ fn eq(&self, other: &RangeBound) -> bool { self.value == other.value && self.type_ == other.type_ } @@ -253,35 +279,56 @@ impl PartialEq for RangeBound where S: BoundSided, T: PartialEq { } } -impl Eq for RangeBound where S: BoundSided, T: Eq {} +impl Eq for RangeBound +where + S: BoundSided, + T: Eq, +{ +} -impl PartialOrd for RangeBound where S: BoundSided, T: PartialOrd { +impl PartialOrd for RangeBound +where + S: BoundSided, + T: PartialOrd, +{ fn partial_cmp(&self, other: &RangeBound) -> Option { - match (::side(), self.type_, other.type_, - self.value.partial_cmp(&other.value)) { - (Upper, Exclusive, Inclusive, Some(Ordering::Equal)) - | (Lower, Inclusive, Exclusive, Some(Ordering::Equal)) => Some(Ordering::Less), - (Upper, Inclusive, Exclusive, Some(Ordering::Equal)) - | (Lower, Exclusive, Inclusive, Some(Ordering::Equal)) => Some(Ordering::Greater), + match ( + ::side(), + self.type_, + other.type_, + self.value.partial_cmp(&other.value), + ) { + (Upper, Exclusive, Inclusive, Some(Ordering::Equal)) | (Lower, Inclusive, Exclusive, Some(Ordering::Equal)) => Some(Ordering::Less), + (Upper, Inclusive, Exclusive, Some(Ordering::Equal)) | (Lower, Exclusive, Inclusive, Some(Ordering::Equal)) => Some(Ordering::Greater), (_, _, _, cmp) => cmp, } } } -impl Ord for RangeBound where S: BoundSided, T: Ord { +impl Ord for RangeBound +where + S: BoundSided, + T: Ord, +{ fn cmp(&self, other: &RangeBound) -> Ordering { - match (::side(), self.type_, other.type_, - self.value.cmp(&other.value)) { - (Upper, Exclusive, Inclusive, Ordering::Equal) - | (Lower, Inclusive, Exclusive, Ordering::Equal) => Ordering::Less, - (Upper, Inclusive, Exclusive, Ordering::Equal) - | (Lower, Exclusive, Inclusive, Ordering::Equal) => Ordering::Greater, + match ( + ::side(), + self.type_, + other.type_, + self.value.cmp(&other.value), + ) { + (Upper, Exclusive, Inclusive, Ordering::Equal) | (Lower, Inclusive, Exclusive, Ordering::Equal) => Ordering::Less, + (Upper, Inclusive, Exclusive, Ordering::Equal) | (Lower, Exclusive, Inclusive, Ordering::Equal) => Ordering::Greater, (_, _, _, ord) => ord, } } } -impl RangeBound where S: BoundSided, T: PartialOrd { +impl RangeBound +where + S: BoundSided, + T: PartialOrd, +{ /// Constructs a new range bound pub fn new(value: T, type_: BoundType) -> RangeBound { RangeBound { @@ -302,9 +349,13 @@ impl RangeBound where S: BoundSided, T: PartialOrd { } } -struct OptBound<'a, S: 'a + BoundSided, T:'a>(Option<&'a RangeBound>); +struct OptBound<'a, S: 'a + BoundSided, T: 'a>(Option<&'a RangeBound>); -impl<'a, S, T> PartialEq for OptBound<'a, S, T> where S: BoundSided, T: PartialEq { +impl<'a, S, T> PartialEq for OptBound<'a, S, T> +where + S: BoundSided, + T: PartialEq, +{ fn eq(&self, &OptBound(ref other): &OptBound<'a, S, T>) -> bool { let &OptBound(ref self_) = self; self_ == other @@ -316,15 +367,17 @@ impl<'a, S, T> PartialEq for OptBound<'a, S, T> where S: BoundSided, T: PartialE } } -impl<'a, S, T> PartialOrd for OptBound<'a, S, T> where S: BoundSided, T: PartialOrd { +impl<'a, S, T> PartialOrd for OptBound<'a, S, T> +where + S: BoundSided, + T: PartialOrd, +{ fn partial_cmp(&self, other: &OptBound<'a, S, T>) -> Option { match (self, other, ::side()) { (&OptBound(None), &OptBound(None), _) => Some(Ordering::Equal), - (&OptBound(None), _, Lower) - | (_, &OptBound(None), Upper) => Some(Ordering::Less), - (&OptBound(None), _, Upper) - | (_, &OptBound(None), Lower) => Some(Ordering::Greater), - (&OptBound(Some(a)), &OptBound(Some(b)), _) => a.partial_cmp(b) + (&OptBound(None), _, Lower) | (_, &OptBound(None), Upper) => Some(Ordering::Less), + (&OptBound(None), _, Upper) | (_, &OptBound(None), Lower) => Some(Ordering::Greater), + (&OptBound(Some(a)), &OptBound(Some(b)), _) => a.partial_cmp(b), } } } @@ -338,20 +391,25 @@ pub struct Range { #[derive(Debug, PartialEq, Eq, Clone, Copy)] enum InnerRange { Empty, - Normal(Option>, - Option>) + Normal( + Option>, + Option>, + ), } -impl fmt::Display for Range where T: fmt::Display { +impl fmt::Display for Range +where + T: fmt::Display, +{ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match self.inner { Empty => write!(fmt, "empty"), Normal(ref lower, ref upper) => { match *lower { - Some(ref bound) => try!(write!(fmt, "{}", bound)), - None => try!(write!(fmt, "(")), + Some(ref bound) => write!(fmt, "{}", bound)?, + None => write!(fmt, "(")?, } - try!(write!(fmt, ",")); + write!(fmt, ",")?; match *upper { Some(ref bound) => write!(fmt, "{}", bound), None => write!(fmt, ")"), @@ -361,26 +419,30 @@ impl fmt::Display for Range where T: fmt::Display { } } -impl Range where T: PartialOrd + Normalizable { +impl Range +where + T: PartialOrd + Normalizable, +{ /// Creates a new range. /// /// If a bound is `None`, the range is unbounded in that direction. - pub fn new(lower: Option>, - upper: Option>) -> Range { + pub fn new(lower: Option>, upper: Option>) -> Range { let lower = lower.map(Normalizable::normalize); let upper = upper.map(Normalizable::normalize); if let (&Some(ref lower), &Some(ref upper)) = (&lower, &upper) { let empty = match (lower.type_, upper.type_) { (Inclusive, Inclusive) => lower.value > upper.value, - _ => lower.value >= upper.value + _ => lower.value >= upper.value, }; if empty { return Range { inner: Empty }; } } - Range { inner: Normal(lower, upper) } + Range { + inner: Normal(lower, upper), + } } /// Creates a new empty range. @@ -392,7 +454,7 @@ impl Range where T: PartialOrd + Normalizable { pub fn is_empty(&self) -> bool { match self.inner { Empty => true, - Normal(..) => false + Normal(..) => false, } } @@ -400,7 +462,7 @@ impl Range where T: PartialOrd + Normalizable { pub fn lower(&self) -> Option<&RangeBound> { match self.inner { Normal(Some(ref lower), _) => Some(lower), - _ => None + _ => None, } } @@ -408,7 +470,7 @@ impl Range where T: PartialOrd + Normalizable { pub fn upper(&self) -> Option<&RangeBound> { match self.inner { Normal(_, Some(ref upper)) => Some(upper), - _ => None + _ => None, } } @@ -417,8 +479,11 @@ impl Range where T: PartialOrd + Normalizable { match self.inner { Empty => false, Normal(ref lower, ref upper) => { - lower.as_ref().map_or(true, |b| b.in_bounds(value)) && - upper.as_ref().map_or(true, |b| b.in_bounds(value)) + lower.as_ref().map_or(true, |b| { + b.in_bounds(value) + }) && upper.as_ref().map_or(true, |b| { + b.in_bounds(value) + }) } } } @@ -433,12 +498,14 @@ impl Range where T: PartialOrd + Normalizable { return false; } - OptBound(self.lower()) <= OptBound(other.lower()) && - OptBound(self.upper()) >= OptBound(other.upper()) + OptBound(self.lower()) <= OptBound(other.lower()) && OptBound(self.upper()) >= OptBound(other.upper()) } } -fn order(a: T, b: T) -> (T, T) where T: PartialOrd { +fn order(a: T, b: T) -> (T, T) +where + T: PartialOrd, +{ if a < b { (a, b) } else { @@ -446,17 +513,18 @@ fn order(a: T, b: T) -> (T, T) where T: PartialOrd { } } -impl Range where T: PartialOrd+Normalizable+Clone { +impl Range +where + T: PartialOrd + Normalizable + Clone, +{ /// Returns the intersection of this range with another. pub fn intersect(&self, other: &Range) -> Range { if self.is_empty() || other.is_empty() { return Range::empty(); } - let (_, OptBound(lower)) = order(OptBound(self.lower()), - OptBound(other.lower())); - let (OptBound(upper), _) = order(OptBound(self.upper()), - OptBound(other.upper())); + let (_, OptBound(lower)) = order(OptBound(self.lower()), OptBound(other.lower())); + let (OptBound(upper), _) = order(OptBound(self.upper()), OptBound(other.upper())); Range::new(lower.map(|v| v.clone()), upper.map(|v| v.clone())) } @@ -471,23 +539,33 @@ impl Range where T: PartialOrd+Normalizable+Clone { return Some(self.clone()); } - let (OptBound(l_lower), OptBound(u_lower)) = - order(OptBound(self.lower()), OptBound(other.lower())); - let (OptBound(l_upper), OptBound(u_upper)) = - order(OptBound(self.upper()), OptBound(other.upper())); + let (OptBound(l_lower), OptBound(u_lower)) = order(OptBound(self.lower()), OptBound(other.lower())); + let (OptBound(l_upper), OptBound(u_upper)) = order(OptBound(self.upper()), OptBound(other.upper())); let discontiguous = match (u_lower, l_upper) { - (Some(&RangeBound { value: ref l, type_: Exclusive, .. }), - Some(&RangeBound { value: ref u, type_: Exclusive, .. })) => l >= u, - (Some(&RangeBound { value: ref l, .. }), - Some(&RangeBound { value: ref u, .. })) => l > u, - _ => false + ( + Some(&RangeBound { + value: ref l, + type_: Exclusive, + .. + }), + Some(&RangeBound { + value: ref u, + type_: Exclusive, + .. + }), + ) => l >= u, + (Some(&RangeBound { value: ref l, .. }), Some(&RangeBound { value: ref u, .. })) => l > u, + _ => false, }; if discontiguous { None } else { - Some(Range::new(l_lower.map(|v| v.clone()), u_upper.map(|v| v.clone()))) + Some(Range::new( + l_lower.map(|v| v.clone()), + u_upper.map(|v| v.clone()), + )) } } } @@ -496,13 +574,8 @@ impl Range where T: PartialOrd+Normalizable+Clone { mod test { use std::i32; - use super::{RangeBound, - Range, - UpperBound, - LowerBound, - Normalizable, - BoundType}; - use super::BoundType::{Inclusive, Exclusive}; + use super::{BoundType, LowerBound, Normalizable, Range, RangeBound, UpperBound}; + use super::BoundType::{Exclusive, Inclusive}; #[test] fn test_range_bound_lower_lt() { @@ -601,19 +674,31 @@ mod test { #[test] fn test_normalize_lower() { let r: RangeBound = RangeBound::new(10i32, Inclusive); - assert_eq!(RangeBound::new(10i32, Inclusive), Normalizable::normalize(r)); + assert_eq!( + RangeBound::new(10i32, Inclusive), + Normalizable::normalize(r) + ); let r: RangeBound = RangeBound::new(10i32, Exclusive); - assert_eq!(RangeBound::new(11i32, Inclusive), Normalizable::normalize(r)); + assert_eq!( + RangeBound::new(11i32, Inclusive), + Normalizable::normalize(r) + ); } #[test] fn test_normalize_upper() { let r: RangeBound = RangeBound::new(10i32, Inclusive); - assert_eq!(RangeBound::new(11i32, Exclusive), Normalizable::normalize(r)); + assert_eq!( + RangeBound::new(11i32, Exclusive), + Normalizable::normalize(r) + ); let r: RangeBound = RangeBound::new(10i32, Exclusive); - assert_eq!(RangeBound::new(10i32, Exclusive), Normalizable::normalize(r)); + assert_eq!( + RangeBound::new(10i32, Exclusive), + Normalizable::normalize(r) + ); } #[test] @@ -641,8 +726,7 @@ mod test { assert_eq!(r1, (range!('(',; ')')).intersect(&r1)); let r2 = range!('(' 10i32,; ')'); - let exp = Range::new(r2.lower().map(|v| v.clone()), - r1.upper().map(|v| v.clone())); + let exp = Range::new(r2.lower().map(|v| v.clone()), r1.upper().map(|v| v.clone())); assert_eq!(exp, r1.intersect(&r2)); assert_eq!(exp, r2.intersect(&r1));