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