1use cdbc::decode::Decode;
2use cdbc::encode::{Encode, IsNull};
3use cdbc::error::BoxDynError;
4use crate::protocol::text::{ColumnFlags, ColumnType};
5use crate::{MySql, MySqlTypeInfo, MySqlValueFormat, MySqlValueRef};
6use cdbc::types::Type;
7use byteorder::{ByteOrder, LittleEndian};
8use std::convert::TryInto;
9
10fn uint_type_info(ty: ColumnType) -> MySqlTypeInfo {
11 MySqlTypeInfo {
12 r#type: ty,
13 flags: ColumnFlags::BINARY | ColumnFlags::UNSIGNED,
14 char_set: 63,
15 max_size: None,
16 }
17}
18
19fn uint_compatible(ty: &MySqlTypeInfo) -> bool {
20 matches!(
21 ty.r#type,
22 ColumnType::Tiny
23 | ColumnType::Short
24 | ColumnType::Long
25 | ColumnType::Int24
26 | ColumnType::LongLong
27 | ColumnType::Year
28 | ColumnType::Bit
29 ) && ty.flags.contains(ColumnFlags::UNSIGNED)
30}
31
32impl Type<MySql> for u8 {
33 fn type_info() -> MySqlTypeInfo {
34 uint_type_info(ColumnType::Tiny)
35 }
36
37 fn compatible(ty: &MySqlTypeInfo) -> bool {
38 uint_compatible(ty)
39 }
40}
41
42impl Type<MySql> for u16 {
43 fn type_info() -> MySqlTypeInfo {
44 uint_type_info(ColumnType::Short)
45 }
46
47 fn compatible(ty: &MySqlTypeInfo) -> bool {
48 uint_compatible(ty)
49 }
50}
51
52impl Type<MySql> for u32 {
53 fn type_info() -> MySqlTypeInfo {
54 uint_type_info(ColumnType::Long)
55 }
56
57 fn compatible(ty: &MySqlTypeInfo) -> bool {
58 uint_compatible(ty)
59 }
60}
61
62impl Type<MySql> for u64 {
63 fn type_info() -> MySqlTypeInfo {
64 uint_type_info(ColumnType::LongLong)
65 }
66
67 fn compatible(ty: &MySqlTypeInfo) -> bool {
68 uint_compatible(ty)
69 }
70}
71
72impl Encode<'_, MySql> for u8 {
73 fn encode_by_ref(&self, buf: &mut Vec<u8>) -> IsNull {
74 buf.extend(&self.to_le_bytes());
75
76 IsNull::No
77 }
78}
79
80impl Encode<'_, MySql> for u16 {
81 fn encode_by_ref(&self, buf: &mut Vec<u8>) -> IsNull {
82 buf.extend(&self.to_le_bytes());
83
84 IsNull::No
85 }
86}
87
88impl Encode<'_, MySql> for u32 {
89 fn encode_by_ref(&self, buf: &mut Vec<u8>) -> IsNull {
90 buf.extend(&self.to_le_bytes());
91
92 IsNull::No
93 }
94}
95
96impl Encode<'_, MySql> for u64 {
97 fn encode_by_ref(&self, buf: &mut Vec<u8>) -> IsNull {
98 buf.extend(&self.to_le_bytes());
99
100 IsNull::No
101 }
102}
103
104fn uint_decode(value: MySqlValueRef<'_>) -> Result<u64, BoxDynError> {
105 if value.type_info.r#type == ColumnType::Bit {
106 let buf = value.as_bytes()?;
109 let mut value: u64 = 0;
110
111 for b in buf {
112 value = (*b as u64) | (value << 8);
113 }
114
115 return Ok(value);
116 }
117
118 Ok(match value.format() {
119 MySqlValueFormat::Text => value.as_str()?.parse()?,
120
121 MySqlValueFormat::Binary => {
122 let buf = value.as_bytes()?;
123 LittleEndian::read_uint(buf, buf.len())
124 }
125 })
126}
127
128impl Decode<'_, MySql> for u8 {
129 fn decode(value: MySqlValueRef<'_>) -> Result<Self, BoxDynError> {
130 uint_decode(value)?.try_into().map_err(Into::into)
131 }
132}
133
134impl Decode<'_, MySql> for u16 {
135 fn decode(value: MySqlValueRef<'_>) -> Result<Self, BoxDynError> {
136 uint_decode(value)?.try_into().map_err(Into::into)
137 }
138}
139
140impl Decode<'_, MySql> for u32 {
141 fn decode(value: MySqlValueRef<'_>) -> Result<Self, BoxDynError> {
142 uint_decode(value)?.try_into().map_err(Into::into)
143 }
144}
145
146impl Decode<'_, MySql> for u64 {
147 fn decode(value: MySqlValueRef<'_>) -> Result<Self, BoxDynError> {
148 uint_decode(value)
149 }
150}