sqlx_mysql/types/
uint.rs

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        // NOTE: Regardless of the value format, there is raw binary data here
105
106        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            // Check conditions that could cause `read_uint()` to panic.
123            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}