cdbc_mysql/types/
uint.rs

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        // NOTE: Regardless of the value format, there is raw binary data here
107
108        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}