diesel/pg/types/floats/
mod.rs1use byteorder::{NetworkEndian, ReadBytesExt, WriteBytesExt};
2use std::error::Error;
3use std::io::prelude::*;
4
5use deserialize::{self, FromSql};
6use pg::Pg;
7use serialize::{self, IsNull, Output, ToSql};
8use sql_types;
9
10#[cfg(feature = "quickcheck")]
11mod quickcheck_impls;
12
13#[derive(Debug, Clone, PartialEq, Eq, FromSqlRow, AsExpression)]
14#[sql_type = "sql_types::Numeric"]
15pub enum PgNumeric {
18 Positive {
20 weight: i16,
22 scale: u16,
24 digits: Vec<i16>,
26 },
27 Negative {
29 weight: i16,
31 scale: u16,
33 digits: Vec<i16>,
35 },
36 NaN,
38}
39
40#[derive(Debug, Clone, Copy)]
41struct InvalidNumericSign(u16);
42
43impl ::std::fmt::Display for InvalidNumericSign {
44 fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
45 write!(f, "InvalidNumericSign({0:x})", self.0)
46 }
47}
48
49impl Error for InvalidNumericSign {
50 fn description(&self) -> &str {
51 "sign for numeric field was not one of 0, 0x4000, 0xC000"
52 }
53}
54
55impl FromSql<sql_types::Numeric, Pg> for PgNumeric {
56 fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {
57 let mut bytes = not_none!(bytes);
58 let digit_count = bytes.read_u16::<NetworkEndian>()?;
59 let mut digits = Vec::with_capacity(digit_count as usize);
60 let weight = bytes.read_i16::<NetworkEndian>()?;
61 let sign = bytes.read_u16::<NetworkEndian>()?;
62 let scale = bytes.read_u16::<NetworkEndian>()?;
63 for _ in 0..digit_count {
64 digits.push(bytes.read_i16::<NetworkEndian>()?);
65 }
66
67 match sign {
68 0 => Ok(PgNumeric::Positive {
69 weight: weight,
70 scale: scale,
71 digits: digits,
72 }),
73 0x4000 => Ok(PgNumeric::Negative {
74 weight: weight,
75 scale: scale,
76 digits: digits,
77 }),
78 0xC000 => Ok(PgNumeric::NaN),
79 invalid => Err(Box::new(InvalidNumericSign(invalid))),
80 }
81 }
82}
83
84impl ToSql<sql_types::Numeric, Pg> for PgNumeric {
85 fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
86 let sign = match *self {
87 PgNumeric::Positive { .. } => 0,
88 PgNumeric::Negative { .. } => 0x4000,
89 PgNumeric::NaN => 0xC000,
90 };
91 let empty_vec = Vec::new();
92 let digits = match *self {
93 PgNumeric::Positive { ref digits, .. } | PgNumeric::Negative { ref digits, .. } => {
94 digits
95 }
96 PgNumeric::NaN => &empty_vec,
97 };
98 let weight = match *self {
99 PgNumeric::Positive { weight, .. } | PgNumeric::Negative { weight, .. } => weight,
100 PgNumeric::NaN => 0,
101 };
102 let scale = match *self {
103 PgNumeric::Positive { scale, .. } | PgNumeric::Negative { scale, .. } => scale,
104 PgNumeric::NaN => 0,
105 };
106 out.write_u16::<NetworkEndian>(digits.len() as u16)?;
107 out.write_i16::<NetworkEndian>(weight)?;
108 out.write_u16::<NetworkEndian>(sign)?;
109 out.write_u16::<NetworkEndian>(scale)?;
110 for digit in digits.iter() {
111 out.write_i16::<NetworkEndian>(*digit)?;
112 }
113
114 Ok(IsNull::No)
115 }
116}