From c5a41e5b7e5ef2d36a3332eca3b4c2c272f4f67f Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 28 Oct 2013 22:35:52 -0700 Subject: [PATCH] Fixes for master + Range sketch --- lib.rs | 2 +- message.rs | 82 ++++++++------- types.rs => types/mod.rs | 33 ++++--- types/range.rs | 209 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 267 insertions(+), 59 deletions(-) rename types.rs => types/mod.rs (92%) create mode 100644 types/range.rs diff --git a/lib.rs b/lib.rs index c5313eec..19ce610e 100644 --- a/lib.rs +++ b/lib.rs @@ -65,7 +65,7 @@ fn main() { #[warn(missing_doc)]; -#[feature(macro_rules, struct_variant)]; +#[feature(macro_rules, struct_variant, globs)]; extern mod extra; diff --git a/message.rs b/message.rs index 6b4c859d..99baa602 100644 --- a/message.rs +++ b/message.rs @@ -3,8 +3,6 @@ use std::str; use std::rt::io::{Decorator, Reader, Writer}; -use std::rt::io::extensions::{ReaderUtil, ReaderByteConversions, - WriterByteConversions}; use std::rt::io::mem::{MemWriter, MemReader}; use std::mem; use std::vec; @@ -129,7 +127,7 @@ trait WriteString { impl WriteString for W { fn write_string(&mut self, s: &str) { self.write(s.as_bytes()); - self.write_u8_(0); + self.write_u8(0); } } @@ -149,56 +147,56 @@ impl WriteMessage for W { buf.write_string(portal); buf.write_string(statement); - buf.write_be_i16_(formats.len() as i16); + buf.write_be_i16(formats.len() as i16); for format in formats.iter() { - buf.write_be_i16_(*format); + buf.write_be_i16(*format); } - buf.write_be_i16_(values.len() as i16); + buf.write_be_i16(values.len() as i16); for value in values.iter() { match *value { None => { - buf.write_be_i32_(-1); + buf.write_be_i32(-1); } Some(ref value) => { - buf.write_be_i32_(value.len() as i32); + buf.write_be_i32(value.len() as i32); buf.write(*value); } } } - buf.write_be_i16_(result_formats.len() as i16); + buf.write_be_i16(result_formats.len() as i16); for format in result_formats.iter() { - buf.write_be_i16_(*format); + buf.write_be_i16(*format); } } CancelRequest { code, process_id, secret_key } => { - buf.write_be_i32_(code); - buf.write_be_i32_(process_id); - buf.write_be_i32_(secret_key); + buf.write_be_i32(code); + buf.write_be_i32(process_id); + buf.write_be_i32(secret_key); } Close { variant, name } => { ident = Some('C'); - buf.write_u8_(variant); + buf.write_u8(variant); buf.write_string(name); } Describe { variant, name } => { ident = Some('D'); - buf.write_u8_(variant); + buf.write_u8(variant); buf.write_string(name); } Execute { portal, max_rows } => { ident = Some('E'); buf.write_string(portal); - buf.write_be_i32_(max_rows); + buf.write_be_i32(max_rows); } Parse { name, query, param_types } => { ident = Some('P'); buf.write_string(name); buf.write_string(query); - buf.write_be_i16_(param_types.len() as i16); + buf.write_be_i16(param_types.len() as i16); for ty in param_types.iter() { - buf.write_be_i32_(*ty); + buf.write_be_i32(*ty); } } PasswordMessage { password } => { @@ -210,12 +208,12 @@ impl WriteMessage for W { buf.write_string(query); } StartupMessage { version, parameters } => { - buf.write_be_i32_(version); + buf.write_be_i32(version); for &(ref k, ref v) in parameters.iter() { buf.write_string(k.as_slice()); buf.write_string(v.as_slice()); } - buf.write_u8_(0); + buf.write_u8(0); } Sync => { ident = Some('S'); @@ -226,12 +224,12 @@ impl WriteMessage for W { } match ident { - Some(ident) => self.write_u8_(ident as u8), + Some(ident) => self.write_u8(ident as u8), None => () } // add size of length value - self.write_be_i32_((buf.inner_ref().len() + mem::size_of::()) + self.write_be_i32((buf.inner_ref().len() + mem::size_of::()) as i32); self.write(buf.inner()); } @@ -245,7 +243,7 @@ impl ReadString for R { fn read_string(&mut self) -> ~str { let mut buf = ~[]; loop { - let byte = self.read_u8_(); + let byte = self.read_u8(); if byte == 0 { break; } @@ -265,9 +263,9 @@ impl ReadMessage for R { fn read_message(&mut self) -> BackendMessage { debug!("Reading message"); - let ident = self.read_u8_(); + let ident = self.read_u8(); // subtract size of length value - let len = self.read_be_i32_() as uint - mem::size_of::(); + let len = self.read_be_i32() as uint - mem::size_of::(); let mut buf = MemReader::new(self.read_bytes(len)); let ret = match ident as char { @@ -275,7 +273,7 @@ impl ReadMessage for R { '2' => BindComplete, '3' => CloseComplete, 'A' => NotificationResponse { - pid: buf.read_be_i32_(), + pid: buf.read_be_i32(), channel: buf.read_string(), payload: buf.read_string() }, @@ -284,8 +282,8 @@ impl ReadMessage for R { 'E' => ErrorResponse { fields: read_fields(&mut buf) }, 'I' => EmptyQueryResponse, 'K' => BackendKeyData { - process_id: buf.read_be_i32_(), - secret_key: buf.read_be_i32_() + process_id: buf.read_be_i32(), + secret_key: buf.read_be_i32() }, 'n' => NoData, 'N' => NoticeResponse { fields: read_fields(&mut buf) }, @@ -297,7 +295,7 @@ impl ReadMessage for R { }, 't' => read_parameter_description(&mut buf), 'T' => read_row_description(&mut buf), - 'Z' => ReadyForQuery { state: buf.read_u8_() }, + 'Z' => ReadyForQuery { state: buf.read_u8() }, ident => fail!("Unknown message identifier `{}`", ident) }; assert!(buf.eof()); @@ -309,7 +307,7 @@ impl ReadMessage for R { fn read_fields(buf: &mut MemReader) -> ~[(u8, ~str)] { let mut fields = ~[]; loop { - let ty = buf.read_u8_(); + let ty = buf.read_u8(); if ty == 0 { break; } @@ -321,11 +319,11 @@ fn read_fields(buf: &mut MemReader) -> ~[(u8, ~str)] { } fn read_data_row(buf: &mut MemReader) -> BackendMessage { - let len = buf.read_be_i16_() as uint; + let len = buf.read_be_i16() as uint; let mut values = vec::with_capacity(len); do len.times() { - let val = match buf.read_be_i32_() { + let val = match buf.read_be_i32() { -1 => None, len => Some(buf.read_bytes(len as uint)) }; @@ -336,7 +334,7 @@ fn read_data_row(buf: &mut MemReader) -> BackendMessage { } fn read_auth_message(buf: &mut MemReader) -> BackendMessage { - match buf.read_be_i32_() { + match buf.read_be_i32() { 0 => AuthenticationOk, 2 => AuthenticationKerberosV5, 3 => AuthenticationCleartextPassword, @@ -349,29 +347,29 @@ fn read_auth_message(buf: &mut MemReader) -> BackendMessage { } fn read_parameter_description(buf: &mut MemReader) -> BackendMessage { - let len = buf.read_be_i16_() as uint; + let len = buf.read_be_i16() as uint; let mut types = vec::with_capacity(len); do len.times() { - types.push(buf.read_be_i32_()); + types.push(buf.read_be_i32()); } ParameterDescription { types: types } } fn read_row_description(buf: &mut MemReader) -> BackendMessage { - let len = buf.read_be_i16_() as uint; + let len = buf.read_be_i16() as uint; let mut types = vec::with_capacity(len); do len.times() { types.push(RowDescriptionEntry { name: buf.read_string(), - table_oid: buf.read_be_i32_(), - column_id: buf.read_be_i16_(), - type_oid: buf.read_be_i32_(), - type_size: buf.read_be_i16_(), - type_modifier: buf.read_be_i32_(), - format: buf.read_be_i16_() + table_oid: buf.read_be_i32(), + column_id: buf.read_be_i16(), + type_oid: buf.read_be_i32(), + type_size: buf.read_be_i16(), + type_modifier: buf.read_be_i32(), + format: buf.read_be_i16() }); } diff --git a/types.rs b/types/mod.rs similarity index 92% rename from types.rs rename to types/mod.rs index 8153c8ab..1adbe9aa 100644 --- a/types.rs +++ b/types/mod.rs @@ -6,11 +6,12 @@ use extra::time::Timespec; use extra::json; use extra::json::Json; use extra::uuid::Uuid; -use std::rt::io::Decorator; -use std::rt::io::extensions::{WriterByteConversions, ReaderByteConversions}; +use std::rt::io::{Reader, Writer, Decorator}; use std::rt::io::mem::{MemWriter, BufReader}; use std::str; +pub mod range; + /// A Postgres OID pub type Oid = i32; @@ -170,17 +171,17 @@ macro_rules! from_option_impl( from_map_impl!(PgBool, bool, |buf| { buf[0] != 0 }) from_option_impl!(bool) -from_conversions_impl!(PgChar, i8, read_i8_) +from_conversions_impl!(PgChar, i8, read_i8) from_option_impl!(i8) -from_conversions_impl!(PgInt2, i16, read_be_i16_) +from_conversions_impl!(PgInt2, i16, read_be_i16) from_option_impl!(i16) -from_conversions_impl!(PgInt4, i32, read_be_i32_) +from_conversions_impl!(PgInt4, i32, read_be_i32) from_option_impl!(i32) -from_conversions_impl!(PgInt8, i64, read_be_i64_) +from_conversions_impl!(PgInt8, i64, read_be_i64) from_option_impl!(i64) -from_conversions_impl!(PgFloat4, f32, read_be_f32_) +from_conversions_impl!(PgFloat4, f32, read_be_f32) from_option_impl!(f32) -from_conversions_impl!(PgFloat8, f64, read_be_f64_) +from_conversions_impl!(PgFloat8, f64, read_be_f64) from_option_impl!(f64) from_map_impl!(PgVarchar | PgText | PgCharN, ~str, |buf| { @@ -208,7 +209,7 @@ from_option_impl!(Uuid) from_map_impl!(PgTimestamp | PgTimestampZ, Timespec, |buf| { let mut rdr = BufReader::new(buf.as_slice()); - let t = rdr.read_be_i64_(); + let t = rdr.read_be_i64(); let mut sec = t / USEC_PER_SEC + TIME_SEC_CONVERSION; let mut usec = t % USEC_PER_SEC; @@ -282,17 +283,17 @@ impl ToSql for bool { } to_option_impl!(PgBool, bool) -to_conversions_impl!(PgChar, i8, write_i8_) +to_conversions_impl!(PgChar, i8, write_i8) to_option_impl!(PgChar, i8) -to_conversions_impl!(PgInt2, i16, write_be_i16_) +to_conversions_impl!(PgInt2, i16, write_be_i16) to_option_impl!(PgInt2, i16) -to_conversions_impl!(PgInt4, i32, write_be_i32_) +to_conversions_impl!(PgInt4, i32, write_be_i32) to_option_impl!(PgInt4, i32) -to_conversions_impl!(PgInt8, i64, write_be_i64_) +to_conversions_impl!(PgInt8, i64, write_be_i64) to_option_impl!(PgInt8, i64) -to_conversions_impl!(PgFloat4, f32, write_be_f32_) +to_conversions_impl!(PgFloat4, f32, write_be_f32) to_option_impl!(PgFloat4, f32) -to_conversions_impl!(PgFloat8, f64, write_be_f64_) +to_conversions_impl!(PgFloat8, f64, write_be_f64) to_option_impl!(PgFloat8, f64) impl ToSql for ~str { @@ -353,7 +354,7 @@ impl ToSql for Timespec { let t = (self.sec - TIME_SEC_CONVERSION) * USEC_PER_SEC + self.nsec as i64 / NSEC_PER_USEC; let mut buf = MemWriter::new(); - buf.write_be_i64_(t); + buf.write_be_i64(t); (Binary, Some(buf.inner())) } } diff --git a/types/range.rs b/types/range.rs new file mode 100644 index 00000000..d092a4e5 --- /dev/null +++ b/types/range.rs @@ -0,0 +1,209 @@ +#[allow(missing_doc)]; + +enum BoundSide { + Upper, + Lower +} + +trait BoundSided { + // param is a hack to get around lack of hints for self type + fn side(_: Option) -> BoundSide; +} + +pub struct UpperBound; +pub struct LowerBound; + +impl BoundSided for UpperBound { + fn side(_: Option) -> BoundSide { + Upper + } +} + +impl BoundSided for LowerBound { + fn side(_: Option) -> BoundSide { + Lower + } +} + +pub enum BoundType { + Inclusive, + Exclusive +} + +pub struct RangeBound { + value: T, + type_: BoundType +} + +impl Ord for RangeBound { + fn lt(&self, other: &RangeBound) -> bool { + match (BoundSided::side(None::), self.type_, other.type_) { + (Upper, Exclusive, Inclusive) + | (Lower, Inclusive, Exclusive) => self.value <= other.value, + _ => self.value < other.value + } + } +} + +impl RangeBound { + pub fn new(value: T, type_: BoundType) -> RangeBound { + RangeBound { value: value, type_: type_ } + } + + pub fn in_bounds(&self, value: &T) -> bool { + match (self.type_, BoundSided::side(None::)) { + (Inclusive, Upper) if value <= &self.value => true, + (Exclusive, Upper) if value < &self.value => true, + (Inclusive, Lower) if value >= &self.value => true, + (Exclusive, Lower) if value > &self.value => true, + _ => false + } + } +} + +#[deriving(Eq)] +pub enum RangeComparison { + Above, + Within, + Below +} + +pub struct Range { + lower: Option>, + upper: Option>, +} + +impl Range { + pub fn new(lower: Option>, + upper: Option>) -> Range { + match (&lower, &upper) { + (&Some(ref lower), &Some(ref upper)) => + assert!(lower.value <= upper.value), + _ => {} + } + + Range { lower: lower, upper: upper } + } + + pub fn cmp(&self, value: &T) -> RangeComparison { + let lower = do self.lower.as_ref().map_default(true) |b| { + b.in_bounds(value) + }; + let upper = do self.upper.as_ref().map_default(true) |b| { + b.in_bounds(value) + }; + + match (lower, upper) { + (true, false) => Above, + (true, true) => Within, + (false, true) => Below, + _ => unreachable!() + } + } + + pub fn contains(&self, value: &T) -> bool { + self.cmp(value) == Within + } +} + +#[cfg(test)] +mod test { + use super::*; + use std::int; + + #[test] + fn test_range_bound_lower_lt() { + fn check(val1: int, inc1: BoundType, val2: int, inc2: BoundType, expected: bool) { + let a: RangeBound = RangeBound::new(val1, inc1); + let b: RangeBound = RangeBound::new(val2, inc2); + assert_eq!(expected, a < b); + } + + check(1, Inclusive, 2, Exclusive, true); + check(1, Exclusive, 2, Inclusive, true); + check(1, Inclusive, 1, Exclusive, true); + check(2, Inclusive, 1, Inclusive, false); + check(2, Exclusive, 1, Exclusive, false); + check(1, Exclusive, 1, Inclusive, false); + check(1, Exclusive, 1, Exclusive, false); + check(1, Inclusive, 1, Inclusive, false); + } + + #[test] + fn test_range_bound_upper_lt() { + fn check(val1: int, inc1: BoundType, val2: int, inc2: BoundType, expected: bool) { + let a: RangeBound = RangeBound::new(val1, inc1); + let b: RangeBound = RangeBound::new(val2, inc2); + assert_eq!(expected, a < b); + } + + check(1, Inclusive, 2, Exclusive, true); + check(1, Exclusive, 2, Exclusive, true); + check(1, Exclusive, 1, Inclusive, true); + check(2, Inclusive, 1, Inclusive, false); + check(2, Exclusive, 1, Exclusive, false); + check(1, Inclusive, 1, Exclusive, false); + check(1, Inclusive, 1, Inclusive, false); + check(1, Exclusive, 1, Exclusive, false); + } + + #[test] + fn test_range_bound_lower_in_bounds() { + fn check(bound: int, inc: BoundType, val: int, expected: bool) { + let b: RangeBound = RangeBound::new(bound, inc); + assert_eq!(expected, b.in_bounds(&val)); + } + + check(1, Inclusive, 1, true); + check(1, Exclusive, 1, false); + check(1, Inclusive, 2, true); + check(1, Inclusive, 0, false); + } + + #[test] + fn test_range_bound_upper_in_bounds() { + fn check(bound: int, inc: BoundType, val: int, expected: bool) { + let b: RangeBound = RangeBound::new(bound, inc); + assert_eq!(expected, b.in_bounds(&val)); + } + + check(1, Inclusive, 1, true); + check(1, Exclusive, 1, false); + check(1, Inclusive, 2, false); + check(1, Inclusive, 0, true); + } + + #[test] + fn test_range_cmp() { + let r = Range::new(Some(RangeBound::new(1, Inclusive)), + Some(RangeBound::new(3, Inclusive))); + assert_eq!(Above, r.cmp(&4)); + assert_eq!(Within, r.cmp(&3)); + assert_eq!(Within, r.cmp(&2)); + assert_eq!(Within, r.cmp(&1)); + assert_eq!(Below, r.cmp(&0)); + + let r = Range::new(Some(RangeBound::new(1, Exclusive)), + Some(RangeBound::new(3, Exclusive))); + assert_eq!(Above, r.cmp(&4)); + assert_eq!(Above, r.cmp(&3)); + assert_eq!(Within, r.cmp(&2)); + assert_eq!(Below, r.cmp(&1)); + assert_eq!(Below, r.cmp(&0)); + + let r = Range::new(None, Some(RangeBound::new(3, Inclusive))); + assert_eq!(Above, r.cmp(&4)); + assert_eq!(Within, r.cmp(&2)); + assert_eq!(Within, r.cmp(&int::min_value)); + + let r = Range::new(Some(RangeBound::new(1, Inclusive)), None); + assert_eq!(Within, r.cmp(&int::max_value)); + assert_eq!(Within, r.cmp(&4)); + assert_eq!(Below, r.cmp(&0)); + + let r = Range::new(None, None); + assert_eq!(Within, r.cmp(&int::max_value)); + assert_eq!(Within, r.cmp(&0)); + assert_eq!(Within, r.cmp(&int::min_value)); + } +}