1use crate::{protocol::Format, ProtocolError};
4use bytes::{BufMut, BytesMut};
5
6pub trait ToProtocolValue: std::fmt::Debug {
8 fn to_protocol(&self, buf: &mut BytesMut, format: Format) -> Result<(), ProtocolError>
10 where
11 Self: Sized,
12 {
13 match format {
14 Format::Text => self.to_text(buf),
15 Format::Binary => self.to_binary(buf),
16 }
17 }
18
19 fn to_text(&self, buf: &mut BytesMut) -> Result<(), ProtocolError>
21 where
22 Self: Sized;
23
24 fn to_binary(&self, buf: &mut BytesMut) -> Result<(), ProtocolError>
26 where
27 Self: Sized;
28}
29
30impl ToProtocolValue for String {
31 fn to_text(&self, buf: &mut BytesMut) -> Result<(), ProtocolError> {
32 buf.put_i32(self.len() as i32);
33 buf.extend_from_slice(self.as_bytes());
34
35 Ok(())
36 }
37
38 fn to_binary(&self, buf: &mut BytesMut) -> Result<(), ProtocolError> {
39 buf.put_i32(self.len() as i32);
40 buf.extend_from_slice(self.as_bytes());
41
42 Ok(())
43 }
44}
45
46impl ToProtocolValue for bool {
47 fn to_text(&self, buf: &mut BytesMut) -> Result<(), ProtocolError> {
48 if *self {
49 "t".to_string().to_text(buf)
50 } else {
51 "f".to_string().to_text(buf)
52 }
53 }
54
55 fn to_binary(&self, buf: &mut BytesMut) -> Result<(), ProtocolError> {
56 buf.put_i32(1_i32);
57 buf.extend_from_slice(if *self { &[1] } else { &[0] });
58
59 Ok(())
60 }
61}
62
63impl<T: ToProtocolValue> ToProtocolValue for Option<T> {
64 fn to_text(&self, buf: &mut BytesMut) -> Result<(), ProtocolError> {
65 match &self {
66 None => buf.extend_from_slice(&(-1_i32).to_be_bytes()),
67 Some(v) => v.to_text(buf)?,
68 };
69
70 Ok(())
71 }
72
73 fn to_binary(&self, buf: &mut BytesMut) -> Result<(), ProtocolError> {
74 match &self {
75 None => buf.extend_from_slice(&(-1_i32).to_be_bytes()),
76 Some(v) => v.to_binary(buf)?,
77 };
78
79 Ok(())
80 }
81}
82
83macro_rules! impl_primitive {
84 ($type: ident) => {
85 impl ToProtocolValue for $type {
86 fn to_text(&self, buf: &mut BytesMut) -> Result<(), ProtocolError> {
87 self.to_string().to_text(buf)
88 }
89
90 fn to_binary(&self, buf: &mut BytesMut) -> Result<(), ProtocolError> {
91 buf.extend_from_slice(&(std::mem::size_of::<$type>() as u32).to_be_bytes());
92 buf.extend_from_slice(&self.to_be_bytes());
93
94 Ok(())
95 }
96 }
97 };
98}
99
100impl_primitive!(i8);
101impl_primitive!(i16);
102impl_primitive!(i32);
103impl_primitive!(i64);
104impl_primitive!(f32);
105impl_primitive!(f64);
106
107#[cfg(test)]
108mod tests {
109 use crate::*;
110 use bytes::BytesMut;
111 #[cfg(feature = "with-chrono")]
112 use chrono::NaiveDate;
113
114 fn assert_text_encode<T: ToProtocolValue>(value: T, expected: &[u8]) {
115 let mut buf = BytesMut::new();
116 value.to_text(&mut buf).unwrap();
117
118 assert_eq!(buf.as_ref(), expected);
119 }
120
121 #[test]
122 fn test_text_encoders() -> Result<(), ProtocolError> {
123 assert_text_encode(true, &[0, 0, 0, 1, 116]);
124 assert_text_encode(false, &[0, 0, 0, 1, 102]);
125 assert_text_encode("str".to_string(), &[0, 0, 0, 3, 115, 116, 114]);
126 assert_text_encode(
127 IntervalValue::new(0, 0, 0, 0, 0, 0),
128 &[
129 0, 0, 0, 46, 48, 32, 121, 101, 97, 114, 115, 32, 48, 32, 109, 111, 110, 115, 32,
130 48, 32, 100, 97, 121, 115, 32, 48, 32, 104, 111, 117, 114, 115, 32, 48, 32, 109,
131 105, 110, 115, 32, 48, 46, 48, 48, 32, 115, 101, 99, 115,
132 ],
133 );
134 assert_text_encode(
135 IntervalValue::new(1, 2, 3, 4, 5, 6),
136 &[
137 0, 0, 0, 50, 48, 32, 121, 101, 97, 114, 115, 32, 49, 32, 109, 111, 110, 115, 32,
138 50, 32, 100, 97, 121, 115, 32, 51, 32, 104, 111, 117, 114, 115, 32, 52, 32, 109,
139 105, 110, 115, 32, 53, 46, 48, 48, 48, 48, 48, 54, 32, 115, 101, 99, 115,
140 ],
141 );
142
143 #[cfg(feature = "with-chrono")]
144 {
145 assert_text_encode(
147 TimestampValue::new(0, None),
148 &[
149 0, 0, 0, 26, 49, 57, 55, 48, 45, 48, 49, 45, 48, 49, 32, 48, 48, 58, 48, 48,
150 58, 48, 48, 46, 48, 48, 48, 48, 48, 48,
151 ],
152 );
153 assert_text_encode(
154 TimestampValue::new(1650890322000000000, None),
155 &[
156 0, 0, 0, 26, 50, 48, 50, 50, 45, 48, 52, 45, 50, 53, 32, 49, 50, 58, 51, 56,
157 58, 52, 50, 46, 48, 48, 48, 48, 48, 48,
158 ],
159 );
160
161 assert_text_encode(
163 NaiveDate::from_ymd_opt(2025, 8, 8).unwrap(),
164 &[
165 0, 0, 0, 10, 50, 48, 50, 53, 45, 48, 56, 45, 48, 56, ],
168 );
169 assert_text_encode(
170 NaiveDate::from_ymd_opt(2000, 1, 1).unwrap(),
171 &[
172 0, 0, 0, 10, 50, 48, 48, 48, 45, 48, 49, 45, 48, 49, ],
175 );
176 assert_text_encode(
177 NaiveDate::from_ymd_opt(1999, 12, 31).unwrap(),
178 &[
179 0, 0, 0, 10, 49, 57, 57, 57, 45, 49, 50, 45, 51, 49, ],
182 );
183 }
184
185 Ok(())
186 }
187
188 fn assert_bind_encode<T: ToProtocolValue>(value: T, expected: &[u8]) {
189 let mut buf = BytesMut::new();
190 value.to_binary(&mut buf).unwrap();
191
192 assert_eq!(buf.as_ref(), expected);
193 }
194
195 #[test]
196 fn test_binary_encoders() -> Result<(), ProtocolError> {
197 assert_bind_encode(true, &[0, 0, 0, 1, 1]);
198 assert_bind_encode(false, &[0, 0, 0, 1, 0]);
199 assert_bind_encode(
200 IntervalValue::new(0, 0, 0, 0, 0, 0),
201 &[0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
202 );
203 assert_bind_encode(
204 IntervalValue::new(1, 2, 3, 4, 5, 6),
205 &[
206 0, 0, 0, 16, 0, 0, 0, 2, 146, 85, 83, 70, 0, 0, 0, 2, 0, 0, 0, 1,
207 ],
208 );
209
210 #[cfg(feature = "with-chrono")]
211 {
212 assert_bind_encode(
214 TimestampValue::new(0, None),
215 &[0, 0, 0, 8, 255, 252, 162, 254, 196, 200, 32, 0],
216 );
217 assert_bind_encode(
218 TimestampValue::new(1650890322000000000, None),
219 &[0, 0, 0, 8, 0, 2, 128, 120, 159, 252, 216, 128],
220 );
221
222 assert_bind_encode(
225 NaiveDate::from_ymd_opt(2000, 1, 1).unwrap(),
226 &[
227 0, 0, 0, 4, 0, 0, 0, 0, ],
230 );
231 assert_bind_encode(
233 NaiveDate::from_ymd_opt(2025, 8, 8).unwrap(),
234 &[
235 0, 0, 0, 4, 0, 0, 36, 135, ],
238 );
239 assert_bind_encode(
241 NaiveDate::from_ymd_opt(1999, 12, 31).unwrap(),
242 &[
243 0, 0, 0, 4, 255, 255, 255, 255, ],
246 );
247 }
248
249 Ok(())
250 }
251}