use types::{Point, LineString, Points, AsEwkbPoint, AsEwkbLineString};
use std::io::prelude::*;
use std::mem;
use std::fmt;
use std::slice::Iter;
use byteorder::{self,ReadBytesExt, WriteBytesExt, BigEndian, LittleEndian};
use error::Error;
#[derive(PartialEq, Clone, Debug)]
pub struct EwkbPoint {
pub x: f64,
pub y: f64,
pub srid: Option<i32>,
}
#[derive(PartialEq, Clone, Debug)]
pub struct EwkbLineString {
pub points: Vec<EwkbPoint>,
pub srid: Option<i32>,
}
pub struct EwkbPointGeom<'a> {
pub geom: &'a Point,
pub srid: Option<i32>,
}
pub struct EwkbLineStringGeom<'a, T>
where T: 'a + Point
{
pub geom: &'a LineString<'a, ItemType=T, Iter=Iter<'a, T>>,
pub srid: Option<i32>,
}
pub trait EwkbGeometry: fmt::Debug {
type PointType: Point;
fn opt_srid(&self) -> Option<i32> {
None
}
fn set_srid(&mut self, _srid: Option<i32>) {
}
}
pub trait EwkbRead: EwkbGeometry + Sized {
fn read_ewkb<R: Read>(raw: &mut R) -> Result<Self, Error> {
let byte_order = try!(raw.read_i8());
let is_be = byte_order == 0i8;
let type_id = try!(read_u32(raw, is_be));
let mut srid: Option<i32> = None;
if type_id & 0x20000000 == 0x20000000 {
srid = Some(try!(read_i32(raw, is_be)));
}
let ewkb = Self::read_ewkb_body(raw, is_be);
ewkb.map(|mut val| { val.set_srid(srid); val } )
}
fn read_ewkb_body<R: Read>(raw: &mut R, is_be: bool) -> Result<Self, Error>;
}
pub trait EwkbWrite: EwkbGeometry {
fn type_id(&self) -> u32;
fn write_ewkb<W: Write+?Sized>(&self, w: &mut W) -> Result<(), Error> {
try!(w.write_u8(0x01));
let type_id = self.type_id();
try!(w.write_u32::<LittleEndian>(type_id));
self.opt_srid().map(|srid| w.write_i32::<LittleEndian>(srid));
try!(self.write_ewkb_body(w));
Ok(())
}
fn write_ewkb_body<W: Write+?Sized>(&self, w: &mut W) -> Result<(), Error>;
fn to_hex_ewkb(&self) -> String {
let mut buf: Vec<u8> = Vec::new();
let _ = self.write_ewkb(&mut buf).unwrap();
let hex: String = buf.iter().fold(String::new(), |s, &b| s + &format!("{:02X}", b));
hex
}
}
impl<'a> EwkbGeometry for EwkbPointGeom<'a> {
type PointType = EwkbPoint;
fn opt_srid(&self) -> Option<i32> {
self.srid
}
fn set_srid(&mut self, srid: Option<i32>) {
self.srid = srid;
}
}
impl<'a> fmt::Debug for EwkbPointGeom<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(write!(f, "EwkbPointGeom")); Ok(())
}
}
impl<'a> EwkbPointGeom<'a> {
fn has_z() -> bool { false }
fn has_m() -> bool { false }
fn wkb_type_id(has_srid: bool) -> u32 {
let mut type_ = 0x0000_0001_u32;
if has_srid {
type_ |= 0x20000000;
}
if Self::has_z() {
type_ |= 0x80000000;
}
if Self::has_m() {
type_ != 0x40000000;
}
type_
}
}
impl<'a> EwkbWrite for EwkbPointGeom<'a> {
fn type_id(&self) -> u32 {
Self::wkb_type_id(self.opt_srid().is_some())
}
fn write_ewkb_body<W: Write+?Sized>(&self, w: &mut W) -> Result<(), Error> {
try!(w.write_f64::<LittleEndian>(self.geom.x()));
try!(w.write_f64::<LittleEndian>(self.geom.y()));
self.geom.opt_z().map(|z| w.write_f64::<LittleEndian>(z));
self.geom.opt_m().map(|m| w.write_f64::<LittleEndian>(m));
Ok(())
}
}
impl<'a> AsEwkbPoint<'a> for EwkbPoint {
fn as_ewkb(&'a self) -> EwkbPointGeom<'a> {
EwkbPointGeom { geom: self, srid: self.srid }
}
}
impl From<byteorder::Error> for Error {
fn from(e: byteorder::Error) -> Error {
Error::Read(format!("error while reading: {:?}", e))
}
}
fn read_u32<R: Read>(raw: &mut R, is_be: bool) -> Result<u32, Error> {
Ok(try!(
if is_be { raw.read_u32::<BigEndian>() }
else { raw.read_u32::<LittleEndian>() }
))
}
fn read_i32<R: Read>(raw: &mut R, is_be: bool) -> Result<i32, Error> {
Ok(try!(
if is_be { raw.read_i32::<BigEndian>() }
else { raw.read_i32::<LittleEndian>() }
))
}
fn read_f64<R: Read>(raw: &mut R, is_be: bool) -> Result<f64, Error> {
Ok(try!(
if is_be { raw.read_f64::<BigEndian>() }
else { raw.read_f64::<LittleEndian>() }
))
}
impl EwkbPoint {
fn has_z() -> bool { false }
fn has_m() -> bool { false }
fn new_from_opt_vals(x: f64, y: f64, _z: Option<f64>, _m: Option<f64>) -> Self {
EwkbPoint { x: x, y: y, srid: None }
}
}
impl Point for EwkbPoint {
fn x(&self) -> f64 {
unsafe { *mem::transmute::<_, *const f64>(self) }
}
fn y(&self) -> f64 {
unsafe { *mem::transmute::<_, *const f64>(self).offset(1) }
}
}
impl EwkbGeometry for EwkbPoint {
type PointType = EwkbPoint;
fn opt_srid(&self) -> Option<i32> {
self.srid
}
fn set_srid(&mut self, srid: Option<i32>) {
self.srid = srid;
}
}
impl EwkbRead for EwkbPoint {
fn read_ewkb_body<R: Read>(raw: &mut R, is_be: bool) -> Result<Self, Error> {
let x = try!(read_f64(raw, is_be));
let y = try!(read_f64(raw, is_be));
let z = if Self::has_z() {
Some(try!(read_f64(raw, is_be)))
} else {
None
};
let m = if Self::has_m() {
Some(try!(read_f64(raw, is_be)))
} else {
None
};
Ok(Self::new_from_opt_vals(x, y, z, m))
}
}
impl EwkbGeometry for EwkbLineString {
type PointType = EwkbPoint;
fn opt_srid(&self) -> Option<i32> {
self.srid
}
fn set_srid(&mut self, srid: Option<i32>) {
self.srid = srid;
}
}
impl EwkbRead for EwkbLineString {
fn read_ewkb_body<R: Read>(raw: &mut R, is_be: bool) -> Result<Self, Error> {
let mut points: Vec<EwkbPoint> = vec![];
let size = try!(read_u32(raw, is_be)) as usize;
for _ in 0..size {
points.push(EwkbPoint::read_ewkb_body(raw, is_be).unwrap());
}
Ok(EwkbLineString {points: points, srid: None})
}
}
impl<'a> Points<'a> for EwkbLineString {
type ItemType = EwkbPoint;
type Iter = Iter<'a, Self::ItemType>;
fn points(&'a self) -> Self::Iter {
self.points.iter()
}
}
impl<'a> LineString<'a> for EwkbLineString {}
impl<'a, T> EwkbGeometry for EwkbLineStringGeom<'a, T>
where T: 'a + Point
{
type PointType = EwkbPoint;
fn opt_srid(&self) -> Option<i32> {
self.srid
}
fn set_srid(&mut self, srid: Option<i32>) {
self.srid = srid;
}
}
impl<'a, T> fmt::Debug for EwkbLineStringGeom<'a, T>
where T: 'a + Point
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(write!(f, "EwkbLineStringGeom")); Ok(())
}
}
impl<'a> EwkbLineStringGeom<'a, EwkbPoint> {
fn has_z() -> bool { false }
fn has_m() -> bool { false }
fn wkb_type_id(has_srid: bool) -> u32 {
let mut type_ = 0x0000_0001_u32;
if has_srid {
type_ |= 0x20000000;
}
if Self::has_z() {
type_ |= 0x80000000;
}
if Self::has_m() {
type_ != 0x40000000;
}
type_
}
}
impl<'a> EwkbWrite for EwkbLineStringGeom<'a, EwkbPoint> {
fn type_id(&self) -> u32 {
let type_id = EwkbPointGeom::wkb_type_id(self.opt_srid().is_some());
(type_id & 0xffff_ff00) | 0x02
}
fn write_ewkb_body<W: Write+?Sized>(&self, w: &mut W) -> Result<(), Error> {
try!(w.write_u32::<LittleEndian>(self.geom.points().len() as u32));
for point in self.geom.points() {
let wkb = EwkbPointGeom { geom: point, srid: self.srid };
try!(wkb.write_ewkb_body(w));
}
Ok(())
}
}
impl<'a> AsEwkbLineString<'a, EwkbPoint> for EwkbLineString {
fn as_ewkb(&'a self) -> EwkbLineStringGeom<'a, EwkbPoint> {
EwkbLineStringGeom { geom: self, srid: self.srid }
}
}
#[test]
fn test_geom_to_wkb() {
let point = EwkbPoint { x: 10.0, y: -20.0, srid: None };
assert_eq!(point.as_ewkb().to_hex_ewkb(), "0101000000000000000000244000000000000034C0");
let point = EwkbPoint { x: 10.0, y: -20.0, srid: Some(4326) };
assert_eq!(point.as_ewkb().to_hex_ewkb(), "0101000020E6100000000000000000244000000000000034C0");
let p = |x, y| EwkbPoint { x: x, y: y, srid: None };
let line = EwkbLineString {srid: None, points: vec![p(10.0, -20.0), p(0., -0.5)]};
assert_eq!(line.as_ewkb().to_hex_ewkb(), "010200000002000000000000000000244000000000000034C00000000000000000000000000000E0BF");
let line = EwkbLineString {srid: Some(4326), points: vec![p(10.0, -20.0), p(0., -0.5)]};
assert_eq!(line.as_ewkb().to_hex_ewkb(), "0102000020E610000002000000000000000000244000000000000034C00000000000000000000000000000E0BF");
}
#[test]
fn test_iterators() {
let p = |x, y| EwkbPoint { x: x, y: y, srid: None };
let line = EwkbLineString {srid: Some(4326), points: vec![p(10.0, -20.0), p(0., -0.5)]};
assert_eq!(line.points().last(), Some(&EwkbPoint { x: 0., y: -0.5, srid: None }));
}
#[test]
fn test_ewkb_adapters() {
let point = EwkbPoint { x: 10.0, y: -20.0, srid: None };
assert_eq!(point.as_ewkb().to_hex_ewkb(), "0101000000000000000000244000000000000034C0");
let p = |x, y| EwkbPoint { x: x, y: y, srid: None };
let line = EwkbLineString {srid: Some(4326), points: vec![p(10.0, -20.0), p(0., -0.5)]};
assert_eq!(line.as_ewkb().to_hex_ewkb(), "0102000020E610000002000000000000000000244000000000000034C00000000000000000000000000000E0BF");
}
#[test]
fn test_wkb_to_geom() {
let mut point_ewkb: &[u8] = &[1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 64, 0, 0, 0, 0, 0, 0, 52, 192];
let point = EwkbPoint::read_ewkb(&mut point_ewkb).unwrap();
assert_eq!(point.as_ewkb().to_hex_ewkb(), "0101000000000000000000244000000000000034C0");
let mut line_ewkb: &[u8] = &[1, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 64, 0, 0, 0, 0, 0, 0, 52, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 191];
let line = EwkbLineString::read_ewkb(&mut line_ewkb).unwrap();
assert_eq!(line.as_ewkb().to_hex_ewkb(), "010200000002000000000000000000244000000000000034C00000000000000000000000000000E0BF");
}