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