use std::error::Error;
use std::ops::{Add, AddAssign, Sub, SubAssign};
use std::io::prelude::*;
use byteorder::{NetworkEndian, ReadBytesExt, WriteBytesExt};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct PgMoney(pub i64);
use pg::Pg;
use types::{self, FromSql, IsNull, Money, ToSql, ToSqlOutput};
primitive_impls!(Money -> (PgMoney, pg: (790, 791)));
impl FromSql<types::Money, Pg> for PgMoney {
fn from_sql(bytes: Option<&[u8]>) -> Result<Self, Box<Error + Send + Sync>> {
let mut bytes = not_none!(bytes);
bytes
.read_i64::<NetworkEndian>()
.map(PgMoney)
.map_err(|e| e.into())
}
}
impl ToSql<types::Money, Pg> for PgMoney {
fn to_sql<W: Write>(
&self,
out: &mut ToSqlOutput<W, Pg>,
) -> Result<IsNull, Box<Error + Send + Sync>> {
out.write_i64::<NetworkEndian>(self.0)
.map(|_| IsNull::No)
.map_err(|e| e.into())
}
}
impl Add for PgMoney {
type Output = Self;
fn add(self, rhs: PgMoney) -> Self::Output {
self.0
.checked_add(rhs.0)
.map(PgMoney)
.expect("overflow adding money amounts")
}
}
impl AddAssign for PgMoney {
fn add_assign(&mut self, rhs: PgMoney) {
self.0 = self.0
.checked_add(rhs.0)
.expect("overflow adding money amounts")
}
}
impl Sub for PgMoney {
type Output = Self;
fn sub(self, rhs: PgMoney) -> Self::Output {
self.0
.checked_sub(rhs.0)
.map(PgMoney)
.expect("underflow subtracting money amounts")
}
}
impl SubAssign for PgMoney {
fn sub_assign(&mut self, rhs: PgMoney) {
self.0 = self.0
.checked_sub(rhs.0)
.expect("underflow subtracting money amounts")
}
}
#[cfg(feature = "quickcheck")]
mod quickcheck_impls {
extern crate quickcheck;
use self::quickcheck::{Arbitrary, Gen};
use super::PgMoney;
impl Arbitrary for PgMoney {
fn arbitrary<G: Gen>(g: &mut G) -> Self {
PgMoney(i64::arbitrary(g))
}
}
}
#[test]
fn add_money() {
let c1 = PgMoney(123);
let c2 = PgMoney(456);
assert_eq!(PgMoney(579), c1 + c2);
}
#[test]
fn add_assign_money() {
let mut c1 = PgMoney(123);
c1 += PgMoney(456);
assert_eq!(PgMoney(579), c1);
}
#[test]
#[should_panic(expected = "overflow adding money amounts")]
fn add_money_overflow() {
let c1 = PgMoney(::std::i64::MAX);
let c2 = PgMoney(1);
let _overflow = c1 + c2;
}
#[test]
#[should_panic(expected = "overflow adding money amounts")]
fn add_assign_money_overflow() {
let mut c1 = PgMoney(::std::i64::MAX);
c1 += PgMoney(1);
}
#[test]
fn sub_money() {
let c1 = PgMoney(123);
let c2 = PgMoney(456);
assert_eq!(PgMoney(-333), c1 - c2);
}
#[test]
fn sub_assign_money() {
let mut c1 = PgMoney(123);
c1 -= PgMoney(456);
assert_eq!(PgMoney(-333), c1);
}
#[test]
#[should_panic(expected = "underflow subtracting money amounts")]
fn sub_money_underflow() {
let c1 = PgMoney(::std::i64::MIN);
let c2 = PgMoney(1);
let _underflow = c1 - c2;
}
#[test]
#[should_panic(expected = "underflow subtracting money amounts")]
fn sub_assign_money_underflow() {
let mut c1 = PgMoney(::std::i64::MIN);
c1 -= PgMoney(1);
}