use byteorder::{LittleEndian, NetworkEndian as NE, WriteBytesExt};
use chrono::{DateTime, NaiveDate, NaiveDateTime, TimeZone, Utc};
use geo_types::Geometry;
use std::mem::{size_of, size_of_val};
use uuid::Uuid;
use wkb::geom_to_wkb;
use super::WriteExt;
use crate::common::*;
use crate::schema::Srid;
pub(crate) struct RawJson<'a>(pub(crate) &'a str);
pub(crate) struct RawJsonb<'a>(pub(crate) &'a str);
pub(crate) struct GeometryWithSrid<'a> {
pub(crate) geometry: &'a Geometry<f64>,
pub(crate) srid: Srid,
}
pub(crate) trait WriteBinary {
fn write_binary<W: Write>(&self, wtr: &mut W) -> Result<()>;
}
impl WriteBinary for bool {
fn write_binary<W: Write>(&self, wtr: &mut W) -> Result<()> {
wtr.write_len(size_of::<u8>())?;
wtr.write_u8(match self {
true => 1,
false => 0,
})?;
Ok(())
}
}
impl WriteBinary for NaiveDate {
fn write_binary<W: Write>(&self, wtr: &mut W) -> Result<()> {
let epoch = NaiveDate::from_ymd(2000, 1, 1);
let day_number = cast::i32((*self - epoch).num_days())?;
wtr.write_len(size_of_val(&day_number))?;
wtr.write_i32::<NE>(day_number)?;
Ok(())
}
}
impl WriteBinary for f32 {
fn write_binary<W: Write>(&self, wtr: &mut W) -> Result<()> {
wtr.write_len(size_of_val(self))?;
wtr.write_f32::<NE>(*self)?;
Ok(())
}
}
impl WriteBinary for f64 {
fn write_binary<W: Write>(&self, wtr: &mut W) -> Result<()> {
wtr.write_len(size_of_val(self))?;
wtr.write_f64::<NE>(*self)?;
Ok(())
}
}
impl<'a> WriteBinary for GeometryWithSrid<'a> {
fn write_binary<W: Write>(&self, wtr: &mut W) -> Result<()> {
let wkb = geom_to_wkb(&self.geometry);
wtr.write_len(wkb.len() + 4)?;
wtr.write_all(&wkb[0..4])?; wtr.write_u8(wkb[4] | 0x20)?; wtr.write_u32::<LittleEndian>(self.srid.to_u32())?; wtr.write_all(&wkb[5..])?; Ok(())
}
}
impl WriteBinary for i16 {
fn write_binary<W: Write>(&self, wtr: &mut W) -> Result<()> {
wtr.write_len(size_of_val(self))?;
wtr.write_i16::<NE>(*self)?;
Ok(())
}
}
impl WriteBinary for i32 {
fn write_binary<W: Write>(&self, wtr: &mut W) -> Result<()> {
wtr.write_len(size_of_val(self))?;
wtr.write_i32::<NE>(*self)?;
Ok(())
}
}
impl WriteBinary for i64 {
fn write_binary<W: Write>(&self, wtr: &mut W) -> Result<()> {
wtr.write_len(size_of_val(self))?;
wtr.write_i64::<NE>(*self)?;
Ok(())
}
}
impl<'a> WriteBinary for RawJson<'a> {
fn write_binary<W: Write>(&self, wtr: &mut W) -> Result<()> {
wtr.write_len(self.0.len())?;
wtr.write_all(self.0.as_bytes())?;
Ok(())
}
}
impl<'a> WriteBinary for RawJsonb<'a> {
fn write_binary<W: Write>(&self, wtr: &mut W) -> Result<()> {
wtr.write_len(1 + self.0.len())?;
wtr.write_u8(1)?; wtr.write_all(self.0.as_bytes())?;
Ok(())
}
}
impl<'a> WriteBinary for &'a str {
fn write_binary<W: Write>(&self, wtr: &mut W) -> Result<()> {
wtr.write_len(self.len())?;
wtr.write_all(self.as_bytes())?;
Ok(())
}
}
impl<'a> WriteBinary for &'a [u8] {
fn write_binary<W: Write>(&self, wtr: &mut W) -> Result<()> {
wtr.write_len(self.len())?;
wtr.write_all(self)?;
Ok(())
}
}
impl<'a> WriteBinary for NaiveDateTime {
fn write_binary<W: Write>(&self, wtr: &mut W) -> Result<()> {
let epoch = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
let duration = *self - epoch;
let microseconds = duration
.num_microseconds()
.ok_or_else(|| format_err!("date math overflow"))?;
wtr.write_len(size_of::<i64>())?;
wtr.write_i64::<NE>(microseconds)?;
Ok(())
}
}
impl<'a> WriteBinary for DateTime<Utc> {
fn write_binary<W: Write>(&self, wtr: &mut W) -> Result<()> {
let epoch = Utc.ymd(2000, 1, 1).and_hms(0, 0, 0);
let duration = *self - epoch;
let microseconds = duration
.num_microseconds()
.ok_or_else(|| format_err!("date math overflow"))?;
wtr.write_len(size_of::<i64>())?;
wtr.write_i64::<NE>(microseconds)?;
Ok(())
}
}
impl WriteBinary for Uuid {
fn write_binary<W: Write>(&self, wtr: &mut W) -> Result<()> {
wtr.write_len(self.as_bytes().len())?;
wtr.write_all(self.as_bytes())?;
Ok(())
}
}