1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
use std::io::prelude::*;
use std::ops::{Add, AddAssign, Sub, SubAssign};
use deserialize::{self, FromSql};
use pg::Pg;
use serialize::{self, Output, ToSql};
use sql_types::{BigInt, Money};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, FromSqlRow, AsExpression)]
#[sql_type = "Money"]
pub struct PgMoney(pub i64);
impl FromSql<Money, Pg> for PgMoney {
fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {
FromSql::<BigInt, Pg>::from_sql(bytes).map(PgMoney)
}
}
impl ToSql<Money, Pg> for PgMoney {
fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
ToSql::<BigInt, Pg>::to_sql(&self.0, out)
}
}
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);
}