1use std::io::prelude::*;
4use std::ops::{Add, AddAssign, Sub, SubAssign};
5
6use deserialize::{self, FromSql};
7use pg::Pg;
8use serialize::{self, Output, ToSql};
9use sql_types::{BigInt, Money};
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, FromSqlRow, AsExpression)]
23#[sql_type = "Money"]
24pub struct PgMoney(pub i64);
25
26impl FromSql<Money, Pg> for PgMoney {
27 fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {
28 FromSql::<BigInt, Pg>::from_sql(bytes).map(PgMoney)
29 }
30}
31
32impl ToSql<Money, Pg> for PgMoney {
33 fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
34 ToSql::<BigInt, Pg>::to_sql(&self.0, out)
35 }
36}
37
38impl Add for PgMoney {
39 type Output = Self;
40 fn add(self, rhs: PgMoney) -> Self::Output {
44 self.0
45 .checked_add(rhs.0)
46 .map(PgMoney)
47 .expect("overflow adding money amounts")
48 }
49}
50
51impl AddAssign for PgMoney {
52 fn add_assign(&mut self, rhs: PgMoney) {
56 self.0 = self
57 .0
58 .checked_add(rhs.0)
59 .expect("overflow adding money amounts")
60 }
61}
62
63impl Sub for PgMoney {
64 type Output = Self;
65 fn sub(self, rhs: PgMoney) -> Self::Output {
69 self.0
70 .checked_sub(rhs.0)
71 .map(PgMoney)
72 .expect("underflow subtracting money amounts")
73 }
74}
75
76impl SubAssign for PgMoney {
77 fn sub_assign(&mut self, rhs: PgMoney) {
81 self.0 = self
82 .0
83 .checked_sub(rhs.0)
84 .expect("underflow subtracting money amounts")
85 }
86}
87
88#[cfg(feature = "quickcheck")]
89mod quickcheck_impls {
90 extern crate quickcheck;
91
92 use self::quickcheck::{Arbitrary, Gen};
93 use super::PgMoney;
94
95 impl Arbitrary for PgMoney {
96 fn arbitrary<G: Gen>(g: &mut G) -> Self {
97 PgMoney(i64::arbitrary(g))
98 }
99 }
100}
101
102#[test]
103fn add_money() {
104 let c1 = PgMoney(123);
105 let c2 = PgMoney(456);
106 assert_eq!(PgMoney(579), c1 + c2);
107}
108
109#[test]
110fn add_assign_money() {
111 let mut c1 = PgMoney(123);
112 c1 += PgMoney(456);
113 assert_eq!(PgMoney(579), c1);
114}
115
116#[test]
117#[should_panic(expected = "overflow adding money amounts")]
118fn add_money_overflow() {
119 let c1 = PgMoney(::std::i64::MAX);
120 let c2 = PgMoney(1);
121 let _overflow = c1 + c2;
122}
123
124#[test]
125#[should_panic(expected = "overflow adding money amounts")]
126fn add_assign_money_overflow() {
127 let mut c1 = PgMoney(::std::i64::MAX);
128 c1 += PgMoney(1);
129}
130
131#[test]
132fn sub_money() {
133 let c1 = PgMoney(123);
134 let c2 = PgMoney(456);
135 assert_eq!(PgMoney(-333), c1 - c2);
136}
137
138#[test]
139fn sub_assign_money() {
140 let mut c1 = PgMoney(123);
141 c1 -= PgMoney(456);
142 assert_eq!(PgMoney(-333), c1);
143}
144
145#[test]
146#[should_panic(expected = "underflow subtracting money amounts")]
147fn sub_money_underflow() {
148 let c1 = PgMoney(::std::i64::MIN);
149 let c2 = PgMoney(1);
150 let _underflow = c1 - c2;
151}
152
153#[test]
154#[should_panic(expected = "underflow subtracting money amounts")]
155fn sub_assign_money_underflow() {
156 let mut c1 = PgMoney(::std::i64::MIN);
157 c1 -= PgMoney(1);
158}