1use crate::constant::{ColumnFlags, ColumnType};
7use crate::error::{Error, Result, eyre};
8use crate::protocol::BinaryRowPayload;
9use crate::protocol::command::{ColumnDefinition, ColumnDefinitionTail};
10use crate::protocol::primitive::*;
11use crate::value::{Time8, Time12, Timestamp4, Timestamp7, Timestamp11, Value};
12use simdutf8::basic::from_utf8;
13use zerocopy::FromBytes;
14
15const BINARY_CHARSET: u16 = 63;
17
18pub trait FromRawValue<'buf>: Sized {
23 fn from_null() -> Result<Self> {
24 Err(Error::BadUsageError(format!(
25 "Cannot decode MySQL type NULL to {}",
26 std::any::type_name::<Self>()
27 )))
28 }
29
30 fn from_i8(_v: i8) -> Result<Self> {
31 Err(Error::BadUsageError(format!(
32 "Cannot decode MySQL type TINYINT (i8) to {}",
33 std::any::type_name::<Self>()
34 )))
35 }
36
37 fn from_i16(_v: i16) -> Result<Self> {
38 Err(Error::BadUsageError(format!(
39 "Cannot decode MySQL type SMALLINT (i16) to {}",
40 std::any::type_name::<Self>()
41 )))
42 }
43
44 fn from_i32(_v: i32) -> Result<Self> {
45 Err(Error::BadUsageError(format!(
46 "Cannot decode MySQL type INT (i32) to {}",
47 std::any::type_name::<Self>()
48 )))
49 }
50
51 fn from_i64(_v: i64) -> Result<Self> {
52 Err(Error::BadUsageError(format!(
53 "Cannot decode MySQL type BIGINT (i64) to {}",
54 std::any::type_name::<Self>()
55 )))
56 }
57
58 fn from_u8(_v: u8) -> Result<Self> {
59 Err(Error::BadUsageError(format!(
60 "Cannot decode MySQL type TINYINT UNSIGNED (u8) to {}",
61 std::any::type_name::<Self>()
62 )))
63 }
64
65 fn from_u16(_v: u16) -> Result<Self> {
66 Err(Error::BadUsageError(format!(
67 "Cannot decode MySQL type SMALLINT UNSIGNED (u16) to {}",
68 std::any::type_name::<Self>()
69 )))
70 }
71
72 fn from_u32(_v: u32) -> Result<Self> {
73 Err(Error::BadUsageError(format!(
74 "Cannot decode MySQL type INT UNSIGNED (u32) to {}",
75 std::any::type_name::<Self>()
76 )))
77 }
78
79 fn from_u64(_v: u64) -> Result<Self> {
80 Err(Error::BadUsageError(format!(
81 "Cannot decode MySQL type BIGINT UNSIGNED (u64) to {}",
82 std::any::type_name::<Self>()
83 )))
84 }
85
86 fn from_float(_v: f32) -> Result<Self> {
87 Err(Error::BadUsageError(format!(
88 "Cannot decode MySQL type FLOAT (f32) to {}",
89 std::any::type_name::<Self>()
90 )))
91 }
92
93 fn from_double(_v: f64) -> Result<Self> {
94 Err(Error::BadUsageError(format!(
95 "Cannot decode MySQL type DOUBLE (f64) to {}",
96 std::any::type_name::<Self>()
97 )))
98 }
99
100 fn from_bytes(_v: &'buf [u8]) -> Result<Self> {
101 Err(Error::BadUsageError(format!(
102 "Cannot decode MySQL type BYTES to {}",
103 std::any::type_name::<Self>()
104 )))
105 }
106
107 fn from_str(_v: &'buf [u8]) -> Result<Self> {
108 Err(Error::BadUsageError(format!(
109 "Cannot decode MySQL type STRING to {}",
110 std::any::type_name::<Self>()
111 )))
112 }
113
114 fn from_decimal(_v: &'buf [u8]) -> Result<Self> {
115 Err(Error::BadUsageError(format!(
116 "Cannot decode MySQL type DECIMAL to {}",
117 std::any::type_name::<Self>()
118 )))
119 }
120
121 fn from_date0() -> Result<Self> {
122 Err(Error::BadUsageError(format!(
123 "Cannot decode MySQL type DATE to {}",
124 std::any::type_name::<Self>()
125 )))
126 }
127
128 fn from_date4(_v: &'buf Timestamp4) -> Result<Self> {
129 Err(Error::BadUsageError(format!(
130 "Cannot decode MySQL type DATE to {}",
131 std::any::type_name::<Self>()
132 )))
133 }
134
135 fn from_datetime0() -> Result<Self> {
136 Err(Error::BadUsageError(format!(
137 "Cannot decode MySQL type DATETIME to {}",
138 std::any::type_name::<Self>()
139 )))
140 }
141
142 fn from_datetime4(_v: &'buf Timestamp4) -> Result<Self> {
143 Err(Error::BadUsageError(format!(
144 "Cannot decode MySQL type DATETIME to {}",
145 std::any::type_name::<Self>()
146 )))
147 }
148
149 fn from_datetime7(_v: &'buf Timestamp7) -> Result<Self> {
150 Err(Error::BadUsageError(format!(
151 "Cannot decode MySQL type DATETIME to {}",
152 std::any::type_name::<Self>()
153 )))
154 }
155
156 fn from_datetime11(_v: &'buf Timestamp11) -> Result<Self> {
157 Err(Error::BadUsageError(format!(
158 "Cannot decode MySQL type DATETIME to {}",
159 std::any::type_name::<Self>()
160 )))
161 }
162
163 fn from_time0() -> Result<Self> {
164 Err(Error::BadUsageError(format!(
165 "Cannot decode MySQL type TIME to {}",
166 std::any::type_name::<Self>()
167 )))
168 }
169
170 fn from_time8(_v: &'buf Time8) -> Result<Self> {
171 Err(Error::BadUsageError(format!(
172 "Cannot decode MySQL type TIME to {}",
173 std::any::type_name::<Self>()
174 )))
175 }
176
177 fn from_time12(_v: &'buf Time12) -> Result<Self> {
178 Err(Error::BadUsageError(format!(
179 "Cannot decode MySQL type TIME to {}",
180 std::any::type_name::<Self>()
181 )))
182 }
183}
184
185pub fn parse_value<'buf, T: FromRawValue<'buf>>(
189 col: &ColumnDefinitionTail,
190 is_null: bool,
191 data: &'buf [u8],
192) -> Result<(T, &'buf [u8])> {
193 if is_null {
194 return Ok((T::from_null()?, data));
195 }
196 let is_unsigned = col.flags()?.contains(ColumnFlags::UNSIGNED_FLAG);
197 let is_binary_charset = col.charset() == BINARY_CHARSET;
198
199 match col.column_type()? {
200 ColumnType::MYSQL_TYPE_NULL => Ok((T::from_null()?, data)),
201
202 ColumnType::MYSQL_TYPE_TINY => {
204 let (val, rest) = read_int_1(data)?;
205 let out = if is_unsigned {
206 T::from_u8(val)?
207 } else {
208 T::from_i8(val as i8)?
209 };
210 Ok((out, rest))
211 }
212
213 ColumnType::MYSQL_TYPE_SHORT | ColumnType::MYSQL_TYPE_YEAR => {
214 let (val, rest) = read_int_2(data)?;
215 let out = if is_unsigned {
216 T::from_u16(val)?
217 } else {
218 T::from_i16(val as i16)?
219 };
220 Ok((out, rest))
221 }
222
223 ColumnType::MYSQL_TYPE_INT24 | ColumnType::MYSQL_TYPE_LONG => {
224 let (val, rest) = read_int_4(data)?;
225 let out = if is_unsigned {
226 T::from_u32(val)?
227 } else {
228 T::from_i32(val as i32)?
229 };
230 Ok((out, rest))
231 }
232
233 ColumnType::MYSQL_TYPE_LONGLONG => {
234 let (val, rest) = read_int_8(data)?;
235 let out = if is_unsigned {
236 T::from_u64(val)?
237 } else {
238 T::from_i64(val as i64)?
239 };
240 Ok((out, rest))
241 }
242
243 ColumnType::MYSQL_TYPE_FLOAT => {
245 let (val, rest) = read_int_4(data)?;
246 Ok((T::from_float(f32::from_bits(val))?, rest))
247 }
248
249 ColumnType::MYSQL_TYPE_DOUBLE => {
250 let (val, rest) = read_int_8(data)?;
251 Ok((T::from_double(f64::from_bits(val))?, rest))
252 }
253
254 ColumnType::MYSQL_TYPE_DATE | ColumnType::MYSQL_TYPE_NEWDATE => {
256 let (len, mut rest) = read_int_1(data)?;
257 match len {
258 0 => Ok((T::from_date0()?, rest)),
259 4 => {
260 let ts = Timestamp4::ref_from_bytes(&rest[..4])?;
261 rest = &rest[4..];
262 Ok((T::from_date4(ts)?, rest))
263 }
264 _ => Err(Error::LibraryBug(eyre!("invalid date length: {}", len))),
265 }
266 }
267
268 ColumnType::MYSQL_TYPE_DATETIME
270 | ColumnType::MYSQL_TYPE_TIMESTAMP
271 | ColumnType::MYSQL_TYPE_TIMESTAMP2
272 | ColumnType::MYSQL_TYPE_DATETIME2 => {
273 let (len, mut rest) = read_int_1(data)?;
274 match len {
275 0 => Ok((T::from_datetime0()?, rest)),
276 4 => {
277 let ts = Timestamp4::ref_from_bytes(&rest[..4])?;
278 rest = &rest[4..];
279 Ok((T::from_datetime4(ts)?, rest))
280 }
281 7 => {
282 let ts = Timestamp7::ref_from_bytes(&rest[..7])?;
283 rest = &rest[7..];
284 Ok((T::from_datetime7(ts)?, rest))
285 }
286 11 => {
287 let ts = Timestamp11::ref_from_bytes(&rest[..11])?;
288 rest = &rest[11..];
289 Ok((T::from_datetime11(ts)?, rest))
290 }
291 _ => Err(Error::LibraryBug(eyre!("invalid datetime length: {}", len))),
292 }
293 }
294
295 ColumnType::MYSQL_TYPE_TIME | ColumnType::MYSQL_TYPE_TIME2 => {
297 let (len, mut rest) = read_int_1(data)?;
298 match len {
299 0 => Ok((T::from_time0()?, rest)),
300 8 => {
301 let time = Time8::ref_from_bytes(&rest[..8])?;
302 rest = &rest[8..];
303 Ok((T::from_time8(time)?, rest))
304 }
305 12 => {
306 let time = Time12::ref_from_bytes(&rest[..12])?;
307 rest = &rest[12..];
308 Ok((T::from_time12(time)?, rest))
309 }
310 _ => Err(Error::LibraryBug(eyre!("invalid time length: {}", len))),
311 }
312 }
313
314 ColumnType::MYSQL_TYPE_DECIMAL | ColumnType::MYSQL_TYPE_NEWDECIMAL => {
316 let (bytes, rest) = read_string_lenenc(data)?;
317 Ok((T::from_decimal(bytes)?, rest))
318 }
319
320 ColumnType::MYSQL_TYPE_VARCHAR
322 | ColumnType::MYSQL_TYPE_VAR_STRING
323 | ColumnType::MYSQL_TYPE_STRING
324 | ColumnType::MYSQL_TYPE_BLOB
325 | ColumnType::MYSQL_TYPE_TINY_BLOB
326 | ColumnType::MYSQL_TYPE_MEDIUM_BLOB
327 | ColumnType::MYSQL_TYPE_LONG_BLOB
328 | ColumnType::MYSQL_TYPE_GEOMETRY
329 | ColumnType::MYSQL_TYPE_JSON
330 | ColumnType::MYSQL_TYPE_ENUM
331 | ColumnType::MYSQL_TYPE_SET
332 | ColumnType::MYSQL_TYPE_BIT
333 | ColumnType::MYSQL_TYPE_TYPED_ARRAY => {
334 let (bytes, rest) = read_string_lenenc(data)?;
335 let out = if is_binary_charset {
336 T::from_bytes(bytes)?
337 } else {
338 T::from_str(bytes)?
339 };
340 Ok((out, rest))
341 }
342 }
343}
344
345pub fn skip_value<'buf>(
349 col: &ColumnDefinitionTail,
350 is_null: bool,
351 data: &'buf [u8],
352) -> Result<((), &'buf [u8])> {
353 if is_null {
354 return Ok(((), data));
355 }
356
357 match col.column_type()? {
358 ColumnType::MYSQL_TYPE_NULL => Ok(((), data)),
359
360 ColumnType::MYSQL_TYPE_TINY => Ok(((), &data[1..])),
362 ColumnType::MYSQL_TYPE_SHORT | ColumnType::MYSQL_TYPE_YEAR => Ok(((), &data[2..])),
363 ColumnType::MYSQL_TYPE_INT24
364 | ColumnType::MYSQL_TYPE_LONG
365 | ColumnType::MYSQL_TYPE_FLOAT => Ok(((), &data[4..])),
366 ColumnType::MYSQL_TYPE_LONGLONG | ColumnType::MYSQL_TYPE_DOUBLE => Ok(((), &data[8..])),
367
368 ColumnType::MYSQL_TYPE_DATE
370 | ColumnType::MYSQL_TYPE_NEWDATE
371 | ColumnType::MYSQL_TYPE_DATETIME
372 | ColumnType::MYSQL_TYPE_TIMESTAMP
373 | ColumnType::MYSQL_TYPE_TIMESTAMP2
374 | ColumnType::MYSQL_TYPE_DATETIME2
375 | ColumnType::MYSQL_TYPE_TIME
376 | ColumnType::MYSQL_TYPE_TIME2 => {
377 let (len, rest) = read_int_1(data)?;
378 Ok(((), &rest[len as usize..]))
379 }
380
381 ColumnType::MYSQL_TYPE_DECIMAL
383 | ColumnType::MYSQL_TYPE_NEWDECIMAL
384 | ColumnType::MYSQL_TYPE_VARCHAR
385 | ColumnType::MYSQL_TYPE_VAR_STRING
386 | ColumnType::MYSQL_TYPE_STRING
387 | ColumnType::MYSQL_TYPE_BLOB
388 | ColumnType::MYSQL_TYPE_TINY_BLOB
389 | ColumnType::MYSQL_TYPE_MEDIUM_BLOB
390 | ColumnType::MYSQL_TYPE_LONG_BLOB
391 | ColumnType::MYSQL_TYPE_GEOMETRY
392 | ColumnType::MYSQL_TYPE_JSON
393 | ColumnType::MYSQL_TYPE_ENUM
394 | ColumnType::MYSQL_TYPE_SET
395 | ColumnType::MYSQL_TYPE_BIT
396 | ColumnType::MYSQL_TYPE_TYPED_ARRAY => {
397 let (_, rest) = read_string_lenenc(data)?;
398 Ok(((), rest))
399 }
400 }
401}
402
403pub trait FromRawRow<'buf>: Sized {
405 fn from_raw_row(cols: &[ColumnDefinition<'_>], row: BinaryRowPayload<'buf>) -> Result<Self>;
406}
407
408impl<'buf, 'value> FromRawValue<'buf> for Value<'value>
413where
414 'buf: 'value,
415{
416 fn from_null() -> Result<Self> {
417 Ok(Value::Null)
418 }
419
420 fn from_i8(v: i8) -> Result<Self> {
421 Ok(Value::SignedInt(v as i64))
422 }
423
424 fn from_i16(v: i16) -> Result<Self> {
425 Ok(Value::SignedInt(v as i64))
426 }
427
428 fn from_i32(v: i32) -> Result<Self> {
429 Ok(Value::SignedInt(v as i64))
430 }
431
432 fn from_i64(v: i64) -> Result<Self> {
433 Ok(Value::SignedInt(v))
434 }
435
436 fn from_u8(v: u8) -> Result<Self> {
437 Ok(Value::UnsignedInt(v as u64))
438 }
439
440 fn from_u16(v: u16) -> Result<Self> {
441 Ok(Value::UnsignedInt(v as u64))
442 }
443
444 fn from_u32(v: u32) -> Result<Self> {
445 Ok(Value::UnsignedInt(v as u64))
446 }
447
448 fn from_u64(v: u64) -> Result<Self> {
449 Ok(Value::UnsignedInt(v))
450 }
451
452 fn from_float(v: f32) -> Result<Self> {
453 Ok(Value::Float(v))
454 }
455
456 fn from_double(v: f64) -> Result<Self> {
457 Ok(Value::Double(v))
458 }
459
460 fn from_bytes(v: &'buf [u8]) -> Result<Self> {
461 Ok(Value::Byte(v))
462 }
463
464 fn from_str(v: &'buf [u8]) -> Result<Self> {
465 Ok(Value::Byte(v))
466 }
467
468 fn from_decimal(v: &'buf [u8]) -> Result<Self> {
469 Ok(Value::Byte(v))
470 }
471
472 fn from_date0() -> Result<Self> {
473 Ok(Value::Date0)
474 }
475
476 fn from_date4(v: &'buf Timestamp4) -> Result<Self> {
477 Ok(Value::Date4(v))
478 }
479
480 fn from_datetime0() -> Result<Self> {
481 Ok(Value::Datetime0)
482 }
483
484 fn from_datetime4(v: &'buf Timestamp4) -> Result<Self> {
485 Ok(Value::Datetime4(v))
486 }
487
488 fn from_datetime7(v: &'buf Timestamp7) -> Result<Self> {
489 Ok(Value::Datetime7(v))
490 }
491
492 fn from_datetime11(v: &'buf Timestamp11) -> Result<Self> {
493 Ok(Value::Datetime11(v))
494 }
495
496 fn from_time0() -> Result<Self> {
497 Ok(Value::Time0)
498 }
499
500 fn from_time8(v: &'buf Time8) -> Result<Self> {
501 Ok(Value::Time8(v))
502 }
503
504 fn from_time12(v: &'buf Time12) -> Result<Self> {
505 Ok(Value::Time12(v))
506 }
507}
508
509impl FromRawValue<'_> for i8 {
514 fn from_i8(v: i8) -> Result<Self> {
515 Ok(v)
516 }
517}
518
519impl FromRawValue<'_> for i16 {
520 fn from_i8(v: i8) -> Result<Self> {
521 Ok(v as i16)
522 }
523
524 fn from_i16(v: i16) -> Result<Self> {
525 Ok(v)
526 }
527}
528
529impl FromRawValue<'_> for i32 {
530 fn from_i8(v: i8) -> Result<Self> {
531 Ok(v as i32)
532 }
533
534 fn from_i16(v: i16) -> Result<Self> {
535 Ok(v as i32)
536 }
537
538 fn from_i32(v: i32) -> Result<Self> {
539 Ok(v)
540 }
541}
542
543impl FromRawValue<'_> for i64 {
544 fn from_i8(v: i8) -> Result<Self> {
545 Ok(v as i64)
546 }
547
548 fn from_i16(v: i16) -> Result<Self> {
549 Ok(v as i64)
550 }
551
552 fn from_i32(v: i32) -> Result<Self> {
553 Ok(v as i64)
554 }
555
556 fn from_i64(v: i64) -> Result<Self> {
557 Ok(v)
558 }
559}
560
561impl FromRawValue<'_> for bool {
562 fn from_i8(v: i8) -> Result<Self> {
563 Ok(v != 0)
564 }
565
566 fn from_u8(v: u8) -> Result<Self> {
567 Ok(v != 0)
568 }
569}
570
571impl FromRawValue<'_> for u8 {
572 fn from_u8(v: u8) -> Result<Self> {
573 Ok(v)
574 }
575}
576
577impl FromRawValue<'_> for u16 {
578 fn from_u8(v: u8) -> Result<Self> {
579 Ok(v as u16)
580 }
581
582 fn from_u16(v: u16) -> Result<Self> {
583 Ok(v)
584 }
585}
586
587impl FromRawValue<'_> for u32 {
588 fn from_u8(v: u8) -> Result<Self> {
589 Ok(v as u32)
590 }
591
592 fn from_u16(v: u16) -> Result<Self> {
593 Ok(v as u32)
594 }
595
596 fn from_u32(v: u32) -> Result<Self> {
597 Ok(v)
598 }
599}
600
601impl FromRawValue<'_> for u64 {
602 fn from_u8(v: u8) -> Result<Self> {
603 Ok(v as u64)
604 }
605
606 fn from_u16(v: u16) -> Result<Self> {
607 Ok(v as u64)
608 }
609
610 fn from_u32(v: u32) -> Result<Self> {
611 Ok(v as u64)
612 }
613
614 fn from_u64(v: u64) -> Result<Self> {
615 Ok(v)
616 }
617}
618
619impl FromRawValue<'_> for f32 {
620 fn from_float(v: f32) -> Result<Self> {
621 Ok(v)
622 }
623}
624
625impl FromRawValue<'_> for f64 {
626 fn from_double(v: f64) -> Result<Self> {
627 Ok(v)
628 }
629
630 fn from_float(v: f32) -> Result<Self> {
631 Ok(v as f64)
632 }
633}
634
635impl<'a> FromRawValue<'a> for &'a [u8] {
636 fn from_bytes(v: &'a [u8]) -> Result<Self> {
637 Ok(v)
638 }
639}
640
641impl FromRawValue<'_> for Vec<u8> {
642 fn from_bytes(v: &[u8]) -> Result<Self> {
643 Ok(v.to_vec())
644 }
645}
646
647impl<'a> FromRawValue<'a> for &'a str {
648 fn from_str(v: &'a [u8]) -> Result<Self> {
649 from_utf8(v).map_err(|e| {
650 Error::BadUsageError(format!("Cannot decode MySQL type STRING to &str: {}", e))
651 })
652 }
653}
654
655impl FromRawValue<'_> for String {
656 fn from_str(v: &[u8]) -> Result<Self> {
657 from_utf8(v).map(|s| s.to_owned()).map_err(|e| {
658 Error::BadUsageError(format!("Cannot decode MySQL type STRING to String: {}", e))
659 })
660 }
661}
662
663impl<'a, T: FromRawValue<'a>> FromRawValue<'a> for Option<T> {
664 fn from_null() -> Result<Self> {
665 Ok(None)
666 }
667
668 fn from_i8(v: i8) -> Result<Self> {
669 T::from_i8(v).map(Some)
670 }
671
672 fn from_i16(v: i16) -> Result<Self> {
673 T::from_i16(v).map(Some)
674 }
675
676 fn from_i32(v: i32) -> Result<Self> {
677 T::from_i32(v).map(Some)
678 }
679
680 fn from_i64(v: i64) -> Result<Self> {
681 T::from_i64(v).map(Some)
682 }
683
684 fn from_u8(v: u8) -> Result<Self> {
685 T::from_u8(v).map(Some)
686 }
687
688 fn from_u16(v: u16) -> Result<Self> {
689 T::from_u16(v).map(Some)
690 }
691
692 fn from_u32(v: u32) -> Result<Self> {
693 T::from_u32(v).map(Some)
694 }
695
696 fn from_u64(v: u64) -> Result<Self> {
697 T::from_u64(v).map(Some)
698 }
699
700 fn from_float(v: f32) -> Result<Self> {
701 T::from_float(v).map(Some)
702 }
703
704 fn from_double(v: f64) -> Result<Self> {
705 T::from_double(v).map(Some)
706 }
707
708 fn from_bytes(v: &'a [u8]) -> Result<Self> {
709 T::from_bytes(v).map(Some)
710 }
711
712 fn from_str(v: &'a [u8]) -> Result<Self> {
713 T::from_str(v).map(Some)
714 }
715
716 fn from_decimal(v: &'a [u8]) -> Result<Self> {
717 T::from_decimal(v).map(Some)
718 }
719
720 fn from_date0() -> Result<Self> {
721 T::from_date0().map(Some)
722 }
723
724 fn from_date4(v: &'a Timestamp4) -> Result<Self> {
725 T::from_date4(v).map(Some)
726 }
727
728 fn from_datetime0() -> Result<Self> {
729 T::from_datetime0().map(Some)
730 }
731
732 fn from_datetime4(v: &'a Timestamp4) -> Result<Self> {
733 T::from_datetime4(v).map(Some)
734 }
735
736 fn from_datetime7(v: &'a Timestamp7) -> Result<Self> {
737 T::from_datetime7(v).map(Some)
738 }
739
740 fn from_datetime11(v: &'a Timestamp11) -> Result<Self> {
741 T::from_datetime11(v).map(Some)
742 }
743
744 fn from_time0() -> Result<Self> {
745 T::from_time0().map(Some)
746 }
747
748 fn from_time8(v: &'a Time8) -> Result<Self> {
749 T::from_time8(v).map(Some)
750 }
751
752 fn from_time12(v: &'a Time12) -> Result<Self> {
753 T::from_time12(v).map(Some)
754 }
755}
756
757macro_rules! impl_from_raw_row_tuple {
762 ($($idx:tt: $T:ident),+) => {
763 impl<'buf, 'value, $($T: FromRawValue<'buf>),+> FromRawRow<'buf> for ($($T,)+) {
764 #[expect(non_snake_case)]
765 fn from_raw_row(cols: &[ColumnDefinition<'_>], row: BinaryRowPayload<'buf>) -> Result<Self> {
766 let mut data = row.values();
767 let null_bitmap = row.null_bitmap();
768 $(
769 let ($T, rest) = parse_value::<$T>(&cols[$idx].tail, null_bitmap.is_null($idx), data)?;
770 data = rest;
771 )+
772 let _ = data; Ok(($($T,)+))
774 }
775 }
776 };
777}
778
779impl_from_raw_row_tuple!(0: A);
780impl_from_raw_row_tuple!(0: A, 1: B);
781impl_from_raw_row_tuple!(0: A, 1: B, 2: C);
782impl_from_raw_row_tuple!(0: A, 1: B, 2: C, 3: D);
783impl_from_raw_row_tuple!(0: A, 1: B, 2: C, 3: D, 4: E);
784impl_from_raw_row_tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F);
785impl_from_raw_row_tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G);
786impl_from_raw_row_tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H);
787impl_from_raw_row_tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I);
788impl_from_raw_row_tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J);
789impl_from_raw_row_tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J, 10: K);
790impl_from_raw_row_tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J, 10: K, 11: L);
791
792#[cfg(feature = "with-uuid")]
797impl FromRawValue<'_> for uuid::Uuid {
798 fn from_str(v: &[u8]) -> Result<Self> {
799 let s = from_utf8(v).map_err(|e| {
800 Error::BadUsageError(format!("Cannot decode MySQL STRING to UUID: {}", e))
801 })?;
802 uuid::Uuid::parse_str(s)
803 .map_err(|e| Error::BadUsageError(format!("Cannot parse UUID from '{}': {}", s, e)))
804 }
805
806 fn from_bytes(v: &[u8]) -> Result<Self> {
807 uuid::Uuid::from_slice(v)
808 .map_err(|e| Error::BadUsageError(format!("Cannot decode MySQL BINARY to UUID: {}", e)))
809 }
810}
811
812#[cfg(feature = "with-chrono")]
817impl FromRawValue<'_> for chrono::NaiveDate {
818 fn from_date0() -> Result<Self> {
819 Err(Error::BadUsageError(
820 "Cannot decode zero DATE to chrono::NaiveDate".to_string(),
821 ))
822 }
823
824 fn from_date4(v: &Timestamp4) -> Result<Self> {
825 chrono::NaiveDate::from_ymd_opt(v.year() as i32, v.month as u32, v.day as u32).ok_or_else(
826 || Error::BadUsageError(format!("Invalid date: {}-{}-{}", v.year(), v.month, v.day)),
827 )
828 }
829}
830
831#[cfg(feature = "with-chrono")]
832impl FromRawValue<'_> for chrono::NaiveTime {
833 fn from_time0() -> Result<Self> {
834 Ok(chrono::NaiveTime::from_hms_opt(0, 0, 0).expect("00:00:00 is valid"))
835 }
836
837 fn from_time8(v: &Time8) -> Result<Self> {
838 if v.is_negative() || v.days() > 0 {
839 return Err(Error::BadUsageError(
840 "Cannot decode TIME with days or negative to chrono::NaiveTime".to_string(),
841 ));
842 }
843 chrono::NaiveTime::from_hms_opt(v.hour as u32, v.minute as u32, v.second as u32).ok_or_else(
844 || {
845 Error::BadUsageError(format!(
846 "Invalid time: {}:{}:{}",
847 v.hour, v.minute, v.second
848 ))
849 },
850 )
851 }
852
853 fn from_time12(v: &Time12) -> Result<Self> {
854 if v.is_negative() || v.days() > 0 {
855 return Err(Error::BadUsageError(
856 "Cannot decode TIME with days or negative to chrono::NaiveTime".to_string(),
857 ));
858 }
859 chrono::NaiveTime::from_hms_micro_opt(
860 v.hour as u32,
861 v.minute as u32,
862 v.second as u32,
863 v.microsecond(),
864 )
865 .ok_or_else(|| {
866 Error::BadUsageError(format!(
867 "Invalid time: {}:{}:{}.{}",
868 v.hour,
869 v.minute,
870 v.second,
871 v.microsecond()
872 ))
873 })
874 }
875}
876
877#[cfg(feature = "with-chrono")]
878impl FromRawValue<'_> for chrono::NaiveDateTime {
879 fn from_datetime0() -> Result<Self> {
880 Err(Error::BadUsageError(
881 "Cannot decode zero DATETIME to chrono::NaiveDateTime".to_string(),
882 ))
883 }
884
885 fn from_datetime4(v: &Timestamp4) -> Result<Self> {
886 let date = chrono::NaiveDate::from_ymd_opt(v.year() as i32, v.month as u32, v.day as u32)
887 .ok_or_else(|| {
888 Error::BadUsageError(format!("Invalid date: {}-{}-{}", v.year(), v.month, v.day))
889 })?;
890 Ok(date.and_hms_opt(0, 0, 0).expect("00:00:00 is valid"))
891 }
892
893 fn from_datetime7(v: &Timestamp7) -> Result<Self> {
894 let date = chrono::NaiveDate::from_ymd_opt(v.year() as i32, v.month as u32, v.day as u32)
895 .ok_or_else(|| {
896 Error::BadUsageError(format!("Invalid date: {}-{}-{}", v.year(), v.month, v.day))
897 })?;
898 date.and_hms_opt(v.hour as u32, v.minute as u32, v.second as u32)
899 .ok_or_else(|| {
900 Error::BadUsageError(format!(
901 "Invalid time: {}:{}:{}",
902 v.hour, v.minute, v.second
903 ))
904 })
905 }
906
907 fn from_datetime11(v: &Timestamp11) -> Result<Self> {
908 let date = chrono::NaiveDate::from_ymd_opt(v.year() as i32, v.month as u32, v.day as u32)
909 .ok_or_else(|| {
910 Error::BadUsageError(format!("Invalid date: {}-{}-{}", v.year(), v.month, v.day))
911 })?;
912 date.and_hms_micro_opt(
913 v.hour as u32,
914 v.minute as u32,
915 v.second as u32,
916 v.microsecond(),
917 )
918 .ok_or_else(|| {
919 Error::BadUsageError(format!(
920 "Invalid datetime: {}-{}-{} {}:{}:{}.{}",
921 v.year(),
922 v.month,
923 v.day,
924 v.hour,
925 v.minute,
926 v.second,
927 v.microsecond()
928 ))
929 })
930 }
931}
932
933#[cfg(feature = "with-time")]
938impl FromRawValue<'_> for time::Date {
939 fn from_date0() -> Result<Self> {
940 Err(Error::BadUsageError(
941 "Cannot decode zero DATE to time::Date".to_string(),
942 ))
943 }
944
945 fn from_date4(v: &Timestamp4) -> Result<Self> {
946 let month = time::Month::try_from(v.month)
947 .map_err(|e| Error::BadUsageError(format!("Invalid month {}: {}", v.month, e)))?;
948 time::Date::from_calendar_date(v.year() as i32, month, v.day).map_err(|e| {
949 Error::BadUsageError(format!(
950 "Invalid date {}-{}-{}: {}",
951 v.year(),
952 v.month,
953 v.day,
954 e
955 ))
956 })
957 }
958}
959
960#[cfg(feature = "with-time")]
961impl FromRawValue<'_> for time::Time {
962 fn from_time0() -> Result<Self> {
963 Ok(time::Time::MIDNIGHT)
964 }
965
966 fn from_time8(v: &Time8) -> Result<Self> {
967 if v.is_negative() || v.days() > 0 {
968 return Err(Error::BadUsageError(
969 "Cannot decode TIME with days or negative to time::Time".to_string(),
970 ));
971 }
972 time::Time::from_hms(v.hour, v.minute, v.second).map_err(|e| {
973 Error::BadUsageError(format!(
974 "Invalid time {}:{}:{}: {}",
975 v.hour, v.minute, v.second, e
976 ))
977 })
978 }
979
980 fn from_time12(v: &Time12) -> Result<Self> {
981 if v.is_negative() || v.days() > 0 {
982 return Err(Error::BadUsageError(
983 "Cannot decode TIME with days or negative to time::Time".to_string(),
984 ));
985 }
986 time::Time::from_hms_micro(v.hour, v.minute, v.second, v.microsecond()).map_err(|e| {
987 Error::BadUsageError(format!(
988 "Invalid time {}:{}:{}.{}: {}",
989 v.hour,
990 v.minute,
991 v.second,
992 v.microsecond(),
993 e
994 ))
995 })
996 }
997}
998
999#[cfg(feature = "with-time")]
1000impl FromRawValue<'_> for time::PrimitiveDateTime {
1001 fn from_datetime0() -> Result<Self> {
1002 Err(Error::BadUsageError(
1003 "Cannot decode zero DATETIME to time::PrimitiveDateTime".to_string(),
1004 ))
1005 }
1006
1007 fn from_datetime4(v: &Timestamp4) -> Result<Self> {
1008 let month = time::Month::try_from(v.month)
1009 .map_err(|e| Error::BadUsageError(format!("Invalid month {}: {}", v.month, e)))?;
1010 let date = time::Date::from_calendar_date(v.year() as i32, month, v.day).map_err(|e| {
1011 Error::BadUsageError(format!(
1012 "Invalid date {}-{}-{}: {}",
1013 v.year(),
1014 v.month,
1015 v.day,
1016 e
1017 ))
1018 })?;
1019 Ok(time::PrimitiveDateTime::new(date, time::Time::MIDNIGHT))
1020 }
1021
1022 fn from_datetime7(v: &Timestamp7) -> Result<Self> {
1023 let month = time::Month::try_from(v.month)
1024 .map_err(|e| Error::BadUsageError(format!("Invalid month {}: {}", v.month, e)))?;
1025 let date = time::Date::from_calendar_date(v.year() as i32, month, v.day).map_err(|e| {
1026 Error::BadUsageError(format!(
1027 "Invalid date {}-{}-{}: {}",
1028 v.year(),
1029 v.month,
1030 v.day,
1031 e
1032 ))
1033 })?;
1034 let time = time::Time::from_hms(v.hour, v.minute, v.second).map_err(|e| {
1035 Error::BadUsageError(format!(
1036 "Invalid time {}:{}:{}: {}",
1037 v.hour, v.minute, v.second, e
1038 ))
1039 })?;
1040 Ok(time::PrimitiveDateTime::new(date, time))
1041 }
1042
1043 fn from_datetime11(v: &Timestamp11) -> Result<Self> {
1044 let month = time::Month::try_from(v.month)
1045 .map_err(|e| Error::BadUsageError(format!("Invalid month {}: {}", v.month, e)))?;
1046 let date = time::Date::from_calendar_date(v.year() as i32, month, v.day).map_err(|e| {
1047 Error::BadUsageError(format!(
1048 "Invalid date {}-{}-{}: {}",
1049 v.year(),
1050 v.month,
1051 v.day,
1052 e
1053 ))
1054 })?;
1055 let time = time::Time::from_hms_micro(v.hour, v.minute, v.second, v.microsecond())
1056 .map_err(|e| {
1057 Error::BadUsageError(format!(
1058 "Invalid time {}:{}:{}.{}: {}",
1059 v.hour,
1060 v.minute,
1061 v.second,
1062 v.microsecond(),
1063 e
1064 ))
1065 })?;
1066 Ok(time::PrimitiveDateTime::new(date, time))
1067 }
1068}
1069
1070#[cfg(feature = "with-rust-decimal")]
1075impl FromRawValue<'_> for rust_decimal::Decimal {
1076 fn from_decimal(v: &[u8]) -> Result<Self> {
1077 let s = from_utf8(v).map_err(|e| {
1078 Error::BadUsageError(format!("Cannot decode MySQL DECIMAL to string: {}", e))
1079 })?;
1080 s.parse()
1081 .map_err(|e| Error::BadUsageError(format!("Cannot parse Decimal from '{}': {}", s, e)))
1082 }
1083
1084 fn from_str(v: &[u8]) -> Result<Self> {
1085 Self::from_decimal(v)
1086 }
1087}