1use crate::collation::Collation;
2use crate::decode::Decode;
3use crate::encode::{Encode, IsNull};
4use crate::error::BoxDynError;
5use crate::protocol::text::{ColumnFlags, ColumnType};
6use crate::types::Type;
7use crate::{MySql, MySqlTypeInfo, MySqlValueFormat, MySqlValueRef};
8use byteorder::{ByteOrder, LittleEndian};
9
10fn uint_type_info(ty: ColumnType) -> MySqlTypeInfo {
11 MySqlTypeInfo {
12 r#type: ty,
13 flags: ColumnFlags::BINARY | ColumnFlags::UNSIGNED,
14 collation: Collation::BINARY,
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>) -> Result<IsNull, BoxDynError> {
74 buf.extend(&self.to_le_bytes());
75
76 Ok(IsNull::No)
77 }
78}
79
80impl Encode<'_, MySql> for u16 {
81 fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {
82 buf.extend(&self.to_le_bytes());
83
84 Ok(IsNull::No)
85 }
86}
87
88impl Encode<'_, MySql> for u32 {
89 fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {
90 buf.extend(&self.to_le_bytes());
91
92 Ok(IsNull::No)
93 }
94}
95
96impl Encode<'_, MySql> for u64 {
97 fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {
98 buf.extend(&self.to_le_bytes());
99
100 Ok(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
124 if buf.is_empty() {
126 return Err("empty buffer".into());
127 }
128
129 if buf.len() > 8 {
130 return Err(format!(
131 "expected no more than 8 bytes for unsigned integer value, got {}",
132 buf.len()
133 )
134 .into());
135 }
136
137 LittleEndian::read_uint(buf, buf.len())
138 }
139 })
140}
141
142impl Decode<'_, MySql> for u8 {
143 fn decode(value: MySqlValueRef<'_>) -> Result<Self, BoxDynError> {
144 uint_decode(value)?.try_into().map_err(Into::into)
145 }
146}
147
148impl Decode<'_, MySql> for u16 {
149 fn decode(value: MySqlValueRef<'_>) -> Result<Self, BoxDynError> {
150 uint_decode(value)?.try_into().map_err(Into::into)
151 }
152}
153
154impl Decode<'_, MySql> for u32 {
155 fn decode(value: MySqlValueRef<'_>) -> Result<Self, BoxDynError> {
156 uint_decode(value)?.try_into().map_err(Into::into)
157 }
158}
159
160impl Decode<'_, MySql> for u64 {
161 fn decode(value: MySqlValueRef<'_>) -> Result<Self, BoxDynError> {
162 uint_decode(value)
163 }
164}