mysql_common/row/convert/
mod.rs

1// Copyright (c) 2017 Anatoly Ikorsky
2//
3// Licensed under the Apache License, Version 2.0
4// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
5// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. All files in the project carrying such notice may not be copied,
7// modified, or distributed except according to those terms.
8
9use crate::{
10    row::Row,
11    value::{
12        convert::{FromValue, FromValueError},
13        Value,
14    },
15};
16
17use std::{any::type_name, error::Error, fmt};
18
19pub mod frunk;
20
21/// `FromRow` conversion error.
22#[derive(Debug, Clone, PartialEq)]
23pub struct FromRowError(pub Row);
24
25impl fmt::Display for FromRowError {
26    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27        write!(
28            f,
29            "Couldn't convert the row `{:?}` to a desired type",
30            self.0
31        )
32    }
33}
34
35impl Error for FromRowError {
36    fn description(&self) -> &str {
37        "Couldn't convert the row to a desired type"
38    }
39}
40
41/// Will *panic* if could not convert `row` to `T`.
42pub fn from_row<T: FromRow>(row: Row) -> T {
43    FromRow::from_row(row)
44}
45
46/// Will return `Err(row)` if could not convert `row` to `T`
47pub fn from_row_opt<T: FromRow>(row: Row) -> Result<T, FromRowError> {
48    FromRow::from_row_opt(row)
49}
50
51/// Trait to convert `Row` into a tuple of `FromValue` implementors up to arity 12.
52///
53/// This trait is convenient way to convert mysql row to a tuple or rust types and relies on
54/// `FromValue` trait, i.e. calling `from_row::<(T, U)>(row)` is similar to calling
55/// `(T::from_value(column_1), U::from_value(column_2))`.
56///
57/// Note that conversion will always fail if any of columns was taken using `Row::take` method.
58///
59/// Conversion of individual columns of a row may fail. In this case `from_row` will panic, and
60/// `from_row_opt` will roll back conversion and return original row.
61///
62/// Concrete types of columns in a row is usually known to a programmer so `from_value` should never
63/// panic if types specified correctly. This means that column which holds `NULL` should correspond
64/// to a type wrapped in `Option`, `String` is used only with column which hold correct utf8, size
65/// and signedness of a numeric type should match to a value stored in a column and so on.
66///
67/// ```ignore
68/// // Consider columns in the row is: Bytes(<some binary data>), NULL and Int(1024)
69/// from_row::<(String, u8, u8)>(row) // this will panic because of invalid utf8 in first column.
70/// from_row::<(Vec<u8>, u8, u8)>(row) // this will panic because of a NULL in second column.
71/// from_row::<(Vec<u8>, Option<u8>, u8)>(row) // this will panic because 1024 does not fit in u8.
72/// from_row::<(Vec<u8>)>(row) // this will panic because number of columns != arity of a tuple.
73/// from_row::<(Vec<u8>, Option<u8>, u16, Option<u8>)>(row) // same reason of panic as previous.
74///
75/// from_row::<(Vec<u8>, Option<u8>, u16)>(row) // this'll work and return (vec![..], None, 1024u16)
76/// ```
77pub trait FromRow {
78    fn from_row(row: Row) -> Self
79    where
80        Self: Sized,
81    {
82        match Self::from_row_opt(row) {
83            Ok(x) => x,
84            Err(FromRowError(row)) => panic!(
85                "Couldn't convert {:?} to type {}. (see FromRow documentation)",
86                row,
87                type_name::<Self>(),
88            ),
89        }
90    }
91
92    fn from_row_opt(row: Row) -> Result<Self, FromRowError>
93    where
94        Self: Sized;
95}
96
97macro_rules! take_or_place {
98    ($row:expr, $index:expr, $t:ident) => (
99        match $row.take($index) {
100            Some(value) => {
101                match $t::get_intermediate(value) {
102                    Ok(ir) => ir,
103                    Err(FromValueError(value)) => {
104                        $row.place($index, value);
105                        return Err(FromRowError($row));
106                    },
107                }
108            },
109            None => return Err(FromRowError($row)),
110        }
111    );
112    ($row:expr, $index:expr, $t:ident, $( [$idx:expr, $ir:expr] ),*) => (
113        match $row.take($index) {
114            Some(value) => {
115                match $t::get_intermediate(value) {
116                    Ok(ir) => ir,
117                    Err(FromValueError(value)) => {
118                        $($row.place($idx, Into::<Value>::into($ir));)*
119                        $row.place($index, value);
120                        return Err(FromRowError($row));
121                    },
122                }
123            },
124            None => return Err(FromRowError($row)),
125        }
126    );
127}
128
129impl FromRow for Row {
130    fn from_row(row: Row) -> Self {
131        row
132    }
133
134    fn from_row_opt(row: Row) -> Result<Self, FromRowError>
135    where
136        Self: Sized,
137    {
138        Ok(row)
139    }
140}
141
142impl<T> FromRow for T
143where
144    T: FromValue,
145{
146    fn from_row_opt(mut row: Row) -> Result<T, FromRowError> {
147        if row.len() == 1 {
148            Ok(take_or_place!(row, 0, T).into())
149        } else {
150            Err(FromRowError(row))
151        }
152    }
153}
154
155impl<T1> FromRow for (T1,)
156where
157    T1: FromValue,
158{
159    fn from_row_opt(mut row: Row) -> Result<(T1,), FromRowError> {
160        if row.len() == 1 {
161            Ok((take_or_place!(row, 0, T1).into(),))
162        } else {
163            Err(FromRowError(row))
164        }
165    }
166}
167
168impl<T1, T2> FromRow for (T1, T2)
169where
170    T1: FromValue,
171    T2: FromValue,
172    T1::Intermediate: Into<Value>,
173{
174    fn from_row_opt(mut row: Row) -> Result<(T1, T2), FromRowError> {
175        if row.len() != 2 {
176            return Err(FromRowError(row));
177        }
178        let ir1 = take_or_place!(row, 0, T1);
179        let ir2 = take_or_place!(row, 1, T2, [0, ir1]);
180        Ok((Into::<T1>::into(ir1), Into::<T2>::into(ir2)))
181    }
182}
183
184impl<T1, T2, T3> FromRow for (T1, T2, T3)
185where
186    T1: FromValue,
187    T2: FromValue,
188    T3: FromValue,
189    T1::Intermediate: Into<Value>,
190    T2::Intermediate: Into<Value>,
191{
192    fn from_row_opt(mut row: Row) -> Result<(T1, T2, T3), FromRowError> {
193        if row.len() != 3 {
194            return Err(FromRowError(row));
195        }
196        let ir1 = take_or_place!(row, 0, T1);
197        let ir2 = take_or_place!(row, 1, T2, [0, ir1]);
198        let ir3 = take_or_place!(row, 2, T3, [0, ir1], [1, ir2]);
199        Ok((Into::<T1>::into(ir1), Into::<T2>::into(ir2), ir3.into()))
200    }
201}
202
203impl<T1, T2, T3, T4> FromRow for (T1, T2, T3, T4)
204where
205    T1: FromValue,
206    T2: FromValue,
207    T3: FromValue,
208    T4: FromValue,
209    T1::Intermediate: Into<Value>,
210    T2::Intermediate: Into<Value>,
211    T3::Intermediate: Into<Value>,
212{
213    fn from_row_opt(mut row: Row) -> Result<(T1, T2, T3, T4), FromRowError> {
214        if row.len() != 4 {
215            return Err(FromRowError(row));
216        }
217        let ir1 = take_or_place!(row, 0, T1);
218        let ir2 = take_or_place!(row, 1, T2, [0, ir1]);
219        let ir3 = take_or_place!(row, 2, T3, [0, ir1], [1, ir2]);
220        let ir4 = take_or_place!(row, 3, T4, [0, ir1], [1, ir2], [2, ir3]);
221        Ok((
222            Into::<T1>::into(ir1),
223            Into::<T2>::into(ir2),
224            Into::<T3>::into(ir3),
225            ir4.into(),
226        ))
227    }
228}
229
230impl<T1, T2, T3, T4, T5> FromRow for (T1, T2, T3, T4, T5)
231where
232    T1: FromValue,
233    T2: FromValue,
234    T3: FromValue,
235    T4: FromValue,
236    T5: FromValue,
237    T1::Intermediate: Into<Value>,
238    T2::Intermediate: Into<Value>,
239    T3::Intermediate: Into<Value>,
240    T4::Intermediate: Into<Value>,
241{
242    fn from_row_opt(mut row: Row) -> Result<(T1, T2, T3, T4, T5), FromRowError> {
243        if row.len() != 5 {
244            return Err(FromRowError(row));
245        }
246        let ir1 = take_or_place!(row, 0, T1);
247        let ir2 = take_or_place!(row, 1, T2, [0, ir1]);
248        let ir3 = take_or_place!(row, 2, T3, [0, ir1], [1, ir2]);
249        let ir4 = take_or_place!(row, 3, T4, [0, ir1], [1, ir2], [2, ir3]);
250        let ir5 = take_or_place!(row, 4, T5, [0, ir1], [1, ir2], [2, ir3], [3, ir4]);
251        Ok((
252            Into::<T1>::into(ir1),
253            Into::<T2>::into(ir2),
254            Into::<T3>::into(ir3),
255            Into::<T4>::into(ir4),
256            ir5.into(),
257        ))
258    }
259}
260
261impl<T1, T2, T3, T4, T5, T6> FromRow for (T1, T2, T3, T4, T5, T6)
262where
263    T1: FromValue,
264    T2: FromValue,
265    T3: FromValue,
266    T4: FromValue,
267    T5: FromValue,
268    T6: FromValue,
269    T1::Intermediate: Into<Value>,
270    T2::Intermediate: Into<Value>,
271    T3::Intermediate: Into<Value>,
272    T4::Intermediate: Into<Value>,
273    T5::Intermediate: Into<Value>,
274{
275    fn from_row_opt(mut row: Row) -> Result<(T1, T2, T3, T4, T5, T6), FromRowError> {
276        if row.len() != 6 {
277            return Err(FromRowError(row));
278        }
279        let ir1 = take_or_place!(row, 0, T1);
280        let ir2 = take_or_place!(row, 1, T2, [0, ir1]);
281        let ir3 = take_or_place!(row, 2, T3, [0, ir1], [1, ir2]);
282        let ir4 = take_or_place!(row, 3, T4, [0, ir1], [1, ir2], [2, ir3]);
283        let ir5 = take_or_place!(row, 4, T5, [0, ir1], [1, ir2], [2, ir3], [3, ir4]);
284        let ir6 = take_or_place!(row, 5, T6, [0, ir1], [1, ir2], [2, ir3], [3, ir4], [4, ir5]);
285        Ok((
286            Into::<T1>::into(ir1),
287            Into::<T2>::into(ir2),
288            Into::<T3>::into(ir3),
289            Into::<T4>::into(ir4),
290            Into::<T5>::into(ir5),
291            ir6.into(),
292        ))
293    }
294}
295
296impl<T1, T2, T3, T4, T5, T6, T7> FromRow for (T1, T2, T3, T4, T5, T6, T7)
297where
298    T1: FromValue,
299    T2: FromValue,
300    T3: FromValue,
301    T4: FromValue,
302    T5: FromValue,
303    T6: FromValue,
304    T7: FromValue,
305    T1::Intermediate: Into<Value>,
306    T2::Intermediate: Into<Value>,
307    T3::Intermediate: Into<Value>,
308    T4::Intermediate: Into<Value>,
309    T5::Intermediate: Into<Value>,
310    T6::Intermediate: Into<Value>,
311{
312    fn from_row_opt(mut row: Row) -> Result<(T1, T2, T3, T4, T5, T6, T7), FromRowError> {
313        if row.len() != 7 {
314            return Err(FromRowError(row));
315        }
316        let ir1 = take_or_place!(row, 0, T1);
317        let ir2 = take_or_place!(row, 1, T2, [0, ir1]);
318        let ir3 = take_or_place!(row, 2, T3, [0, ir1], [1, ir2]);
319        let ir4 = take_or_place!(row, 3, T4, [0, ir1], [1, ir2], [2, ir3]);
320        let ir5 = take_or_place!(row, 4, T5, [0, ir1], [1, ir2], [2, ir3], [3, ir4]);
321        let ir6 = take_or_place!(row, 5, T6, [0, ir1], [1, ir2], [2, ir3], [3, ir4], [4, ir5]);
322        let ir7 = take_or_place!(
323            row,
324            6,
325            T7,
326            [0, ir1],
327            [1, ir2],
328            [2, ir3],
329            [3, ir4],
330            [4, ir5],
331            [5, ir6]
332        );
333        Ok((
334            Into::<T1>::into(ir1),
335            Into::<T2>::into(ir2),
336            Into::<T3>::into(ir3),
337            Into::<T4>::into(ir4),
338            Into::<T5>::into(ir5),
339            Into::<T6>::into(ir6),
340            ir7.into(),
341        ))
342    }
343}
344
345impl<T1, T2, T3, T4, T5, T6, T7, T8> FromRow for (T1, T2, T3, T4, T5, T6, T7, T8)
346where
347    T1: FromValue,
348    T2: FromValue,
349    T3: FromValue,
350    T4: FromValue,
351    T5: FromValue,
352    T6: FromValue,
353    T7: FromValue,
354    T8: FromValue,
355    T1::Intermediate: Into<Value>,
356    T2::Intermediate: Into<Value>,
357    T3::Intermediate: Into<Value>,
358    T4::Intermediate: Into<Value>,
359    T5::Intermediate: Into<Value>,
360    T6::Intermediate: Into<Value>,
361    T7::Intermediate: Into<Value>,
362{
363    fn from_row_opt(mut row: Row) -> Result<(T1, T2, T3, T4, T5, T6, T7, T8), FromRowError> {
364        if row.len() != 8 {
365            return Err(FromRowError(row));
366        }
367        let ir1 = take_or_place!(row, 0, T1);
368        let ir2 = take_or_place!(row, 1, T2, [0, ir1]);
369        let ir3 = take_or_place!(row, 2, T3, [0, ir1], [1, ir2]);
370        let ir4 = take_or_place!(row, 3, T4, [0, ir1], [1, ir2], [2, ir3]);
371        let ir5 = take_or_place!(row, 4, T5, [0, ir1], [1, ir2], [2, ir3], [3, ir4]);
372        let ir6 = take_or_place!(row, 5, T6, [0, ir1], [1, ir2], [2, ir3], [3, ir4], [4, ir5]);
373        let ir7 = take_or_place!(
374            row,
375            6,
376            T7,
377            [0, ir1],
378            [1, ir2],
379            [2, ir3],
380            [3, ir4],
381            [4, ir5],
382            [5, ir6]
383        );
384        let ir8 = take_or_place!(
385            row,
386            7,
387            T8,
388            [0, ir1],
389            [1, ir2],
390            [2, ir3],
391            [3, ir4],
392            [4, ir5],
393            [5, ir6],
394            [6, ir7]
395        );
396        Ok((
397            Into::<T1>::into(ir1),
398            Into::<T2>::into(ir2),
399            Into::<T3>::into(ir3),
400            Into::<T4>::into(ir4),
401            Into::<T5>::into(ir5),
402            Into::<T6>::into(ir6),
403            Into::<T7>::into(ir7),
404            ir8.into(),
405        ))
406    }
407}
408
409impl<T1, T2, T3, T4, T5, T6, T7, T8, T9> FromRow for (T1, T2, T3, T4, T5, T6, T7, T8, T9)
410where
411    T1: FromValue,
412    T2: FromValue,
413    T3: FromValue,
414    T4: FromValue,
415    T5: FromValue,
416    T6: FromValue,
417    T7: FromValue,
418    T8: FromValue,
419    T9: FromValue,
420    T1::Intermediate: Into<Value>,
421    T2::Intermediate: Into<Value>,
422    T3::Intermediate: Into<Value>,
423    T4::Intermediate: Into<Value>,
424    T5::Intermediate: Into<Value>,
425    T6::Intermediate: Into<Value>,
426    T7::Intermediate: Into<Value>,
427    T8::Intermediate: Into<Value>,
428{
429    fn from_row_opt(mut row: Row) -> Result<(T1, T2, T3, T4, T5, T6, T7, T8, T9), FromRowError> {
430        if row.len() != 9 {
431            return Err(FromRowError(row));
432        }
433        let ir1 = take_or_place!(row, 0, T1);
434        let ir2 = take_or_place!(row, 1, T2, [0, ir1]);
435        let ir3 = take_or_place!(row, 2, T3, [0, ir1], [1, ir2]);
436        let ir4 = take_or_place!(row, 3, T4, [0, ir1], [1, ir2], [2, ir3]);
437        let ir5 = take_or_place!(row, 4, T5, [0, ir1], [1, ir2], [2, ir3], [3, ir4]);
438        let ir6 = take_or_place!(row, 5, T6, [0, ir1], [1, ir2], [2, ir3], [3, ir4], [4, ir5]);
439        let ir7 = take_or_place!(
440            row,
441            6,
442            T7,
443            [0, ir1],
444            [1, ir2],
445            [2, ir3],
446            [3, ir4],
447            [4, ir5],
448            [5, ir6]
449        );
450        let ir8 = take_or_place!(
451            row,
452            7,
453            T8,
454            [0, ir1],
455            [1, ir2],
456            [2, ir3],
457            [3, ir4],
458            [4, ir5],
459            [5, ir6],
460            [6, ir7]
461        );
462        let ir9 = take_or_place!(
463            row,
464            8,
465            T9,
466            [0, ir1],
467            [1, ir2],
468            [2, ir3],
469            [3, ir4],
470            [4, ir5],
471            [5, ir6],
472            [6, ir7],
473            [7, ir8]
474        );
475        Ok((
476            Into::<T1>::into(ir1),
477            Into::<T2>::into(ir2),
478            Into::<T3>::into(ir3),
479            Into::<T4>::into(ir4),
480            Into::<T5>::into(ir5),
481            Into::<T6>::into(ir6),
482            Into::<T7>::into(ir7),
483            Into::<T8>::into(ir8),
484            ir9.into(),
485        ))
486    }
487}
488
489impl<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> FromRow for (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10)
490where
491    T1: FromValue,
492    T2: FromValue,
493    T3: FromValue,
494    T4: FromValue,
495    T5: FromValue,
496    T6: FromValue,
497    T7: FromValue,
498    T8: FromValue,
499    T9: FromValue,
500    T10: FromValue,
501    T1::Intermediate: Into<Value>,
502    T2::Intermediate: Into<Value>,
503    T3::Intermediate: Into<Value>,
504    T4::Intermediate: Into<Value>,
505    T5::Intermediate: Into<Value>,
506    T6::Intermediate: Into<Value>,
507    T7::Intermediate: Into<Value>,
508    T8::Intermediate: Into<Value>,
509    T9::Intermediate: Into<Value>,
510{
511    fn from_row_opt(
512        mut row: Row,
513    ) -> Result<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10), FromRowError> {
514        if row.len() != 10 {
515            return Err(FromRowError(row));
516        }
517        let ir1 = take_or_place!(row, 0, T1);
518        let ir2 = take_or_place!(row, 1, T2, [0, ir1]);
519        let ir3 = take_or_place!(row, 2, T3, [0, ir1], [1, ir2]);
520        let ir4 = take_or_place!(row, 3, T4, [0, ir1], [1, ir2], [2, ir3]);
521        let ir5 = take_or_place!(row, 4, T5, [0, ir1], [1, ir2], [2, ir3], [3, ir4]);
522        let ir6 = take_or_place!(row, 5, T6, [0, ir1], [1, ir2], [2, ir3], [3, ir4], [4, ir5]);
523        let ir7 = take_or_place!(
524            row,
525            6,
526            T7,
527            [0, ir1],
528            [1, ir2],
529            [2, ir3],
530            [3, ir4],
531            [4, ir5],
532            [5, ir6]
533        );
534        let ir8 = take_or_place!(
535            row,
536            7,
537            T8,
538            [0, ir1],
539            [1, ir2],
540            [2, ir3],
541            [3, ir4],
542            [4, ir5],
543            [5, ir6],
544            [6, ir7]
545        );
546        let ir9 = take_or_place!(
547            row,
548            8,
549            T9,
550            [0, ir1],
551            [1, ir2],
552            [2, ir3],
553            [3, ir4],
554            [4, ir5],
555            [5, ir6],
556            [6, ir7],
557            [7, ir8]
558        );
559        let ir10 = take_or_place!(
560            row,
561            9,
562            T10,
563            [0, ir1],
564            [1, ir2],
565            [2, ir3],
566            [3, ir4],
567            [4, ir5],
568            [5, ir6],
569            [6, ir7],
570            [7, ir8],
571            [8, ir9]
572        );
573        Ok((
574            Into::<T1>::into(ir1),
575            Into::<T2>::into(ir2),
576            Into::<T3>::into(ir3),
577            Into::<T4>::into(ir4),
578            Into::<T5>::into(ir5),
579            Into::<T6>::into(ir6),
580            Into::<T7>::into(ir7),
581            Into::<T8>::into(ir8),
582            Into::<T9>::into(ir9),
583            ir10.into(),
584        ))
585    }
586}
587
588impl<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> FromRow
589    for (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11)
590where
591    T1: FromValue,
592    T2: FromValue,
593    T3: FromValue,
594    T4: FromValue,
595    T5: FromValue,
596    T6: FromValue,
597    T7: FromValue,
598    T8: FromValue,
599    T9: FromValue,
600    T10: FromValue,
601    T11: FromValue,
602    T1::Intermediate: Into<Value>,
603    T2::Intermediate: Into<Value>,
604    T3::Intermediate: Into<Value>,
605    T4::Intermediate: Into<Value>,
606    T5::Intermediate: Into<Value>,
607    T6::Intermediate: Into<Value>,
608    T7::Intermediate: Into<Value>,
609    T8::Intermediate: Into<Value>,
610    T9::Intermediate: Into<Value>,
611    T10::Intermediate: Into<Value>,
612{
613    fn from_row_opt(
614        mut row: Row,
615    ) -> Result<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11), FromRowError> {
616        if row.len() != 11 {
617            return Err(FromRowError(row));
618        }
619        let ir1 = take_or_place!(row, 0, T1);
620        let ir2 = take_or_place!(row, 1, T2, [0, ir1]);
621        let ir3 = take_or_place!(row, 2, T3, [0, ir1], [1, ir2]);
622        let ir4 = take_or_place!(row, 3, T4, [0, ir1], [1, ir2], [2, ir3]);
623        let ir5 = take_or_place!(row, 4, T5, [0, ir1], [1, ir2], [2, ir3], [3, ir4]);
624        let ir6 = take_or_place!(row, 5, T6, [0, ir1], [1, ir2], [2, ir3], [3, ir4], [4, ir5]);
625        let ir7 = take_or_place!(
626            row,
627            6,
628            T7,
629            [0, ir1],
630            [1, ir2],
631            [2, ir3],
632            [3, ir4],
633            [4, ir5],
634            [5, ir6]
635        );
636        let ir8 = take_or_place!(
637            row,
638            7,
639            T8,
640            [0, ir1],
641            [1, ir2],
642            [2, ir3],
643            [3, ir4],
644            [4, ir5],
645            [5, ir6],
646            [6, ir7]
647        );
648        let ir9 = take_or_place!(
649            row,
650            8,
651            T9,
652            [0, ir1],
653            [1, ir2],
654            [2, ir3],
655            [3, ir4],
656            [4, ir5],
657            [5, ir6],
658            [6, ir7],
659            [7, ir8]
660        );
661        let ir10 = take_or_place!(
662            row,
663            9,
664            T10,
665            [0, ir1],
666            [1, ir2],
667            [2, ir3],
668            [3, ir4],
669            [4, ir5],
670            [5, ir6],
671            [6, ir7],
672            [7, ir8],
673            [8, ir9]
674        );
675        let ir11 = take_or_place!(
676            row,
677            10,
678            T11,
679            [0, ir1],
680            [1, ir2],
681            [2, ir3],
682            [3, ir4],
683            [4, ir5],
684            [5, ir6],
685            [6, ir7],
686            [7, ir8],
687            [8, ir9],
688            [9, ir10]
689        );
690        Ok((
691            Into::<T1>::into(ir1),
692            Into::<T2>::into(ir2),
693            Into::<T3>::into(ir3),
694            Into::<T4>::into(ir4),
695            Into::<T5>::into(ir5),
696            Into::<T6>::into(ir6),
697            Into::<T7>::into(ir7),
698            Into::<T8>::into(ir8),
699            Into::<T9>::into(ir9),
700            Into::<T10>::into(ir10),
701            ir11.into(),
702        ))
703    }
704}
705
706impl<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> FromRow
707    for (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12)
708where
709    T1: FromValue,
710    T2: FromValue,
711    T3: FromValue,
712    T4: FromValue,
713    T5: FromValue,
714    T6: FromValue,
715    T7: FromValue,
716    T8: FromValue,
717    T9: FromValue,
718    T10: FromValue,
719    T11: FromValue,
720    T12: FromValue,
721    T1::Intermediate: Into<Value>,
722    T2::Intermediate: Into<Value>,
723    T3::Intermediate: Into<Value>,
724    T4::Intermediate: Into<Value>,
725    T5::Intermediate: Into<Value>,
726    T6::Intermediate: Into<Value>,
727    T7::Intermediate: Into<Value>,
728    T8::Intermediate: Into<Value>,
729    T9::Intermediate: Into<Value>,
730    T10::Intermediate: Into<Value>,
731    T11::Intermediate: Into<Value>,
732{
733    fn from_row_opt(
734        mut row: Row,
735    ) -> Result<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12), FromRowError> {
736        if row.len() != 12 {
737            return Err(FromRowError(row));
738        }
739        let ir1 = take_or_place!(row, 0, T1);
740        let ir2 = take_or_place!(row, 1, T2, [0, ir1]);
741        let ir3 = take_or_place!(row, 2, T3, [0, ir1], [1, ir2]);
742        let ir4 = take_or_place!(row, 3, T4, [0, ir1], [1, ir2], [2, ir3]);
743        let ir5 = take_or_place!(row, 4, T5, [0, ir1], [1, ir2], [2, ir3], [3, ir4]);
744        let ir6 = take_or_place!(row, 5, T6, [0, ir1], [1, ir2], [2, ir3], [3, ir4], [4, ir5]);
745        let ir7 = take_or_place!(
746            row,
747            6,
748            T7,
749            [0, ir1],
750            [1, ir2],
751            [2, ir3],
752            [3, ir4],
753            [4, ir5],
754            [5, ir6]
755        );
756        let ir8 = take_or_place!(
757            row,
758            7,
759            T8,
760            [0, ir1],
761            [1, ir2],
762            [2, ir3],
763            [3, ir4],
764            [4, ir5],
765            [5, ir6],
766            [6, ir7]
767        );
768        let ir9 = take_or_place!(
769            row,
770            8,
771            T9,
772            [0, ir1],
773            [1, ir2],
774            [2, ir3],
775            [3, ir4],
776            [4, ir5],
777            [5, ir6],
778            [6, ir7],
779            [7, ir8]
780        );
781        let ir10 = take_or_place!(
782            row,
783            9,
784            T10,
785            [0, ir1],
786            [1, ir2],
787            [2, ir3],
788            [3, ir4],
789            [4, ir5],
790            [5, ir6],
791            [6, ir7],
792            [7, ir8],
793            [8, ir9]
794        );
795        let ir11 = take_or_place!(
796            row,
797            10,
798            T11,
799            [0, ir1],
800            [1, ir2],
801            [2, ir3],
802            [3, ir4],
803            [4, ir5],
804            [5, ir6],
805            [6, ir7],
806            [7, ir8],
807            [8, ir9],
808            [9, ir10]
809        );
810        let ir12 = take_or_place!(
811            row,
812            11,
813            T12,
814            [0, ir1],
815            [1, ir2],
816            [2, ir3],
817            [3, ir4],
818            [4, ir5],
819            [5, ir6],
820            [6, ir7],
821            [7, ir8],
822            [8, ir9],
823            [9, ir10],
824            [10, ir11]
825        );
826        Ok((
827            Into::<T1>::into(ir1),
828            Into::<T2>::into(ir2),
829            Into::<T3>::into(ir3),
830            Into::<T4>::into(ir4),
831            Into::<T5>::into(ir5),
832            Into::<T6>::into(ir6),
833            Into::<T7>::into(ir7),
834            Into::<T8>::into(ir8),
835            Into::<T9>::into(ir9),
836            Into::<T10>::into(ir10),
837            Into::<T11>::into(ir11),
838            ir12.into(),
839        ))
840    }
841}
842
843#[cfg(feature = "nightly")]
844#[bench]
845fn bench_from_row(bencher: &mut test::Bencher) {
846    use std::sync::Arc;
847
848    use crate::{constants::ColumnType, io::WriteMysqlExt, packets::Column, value::Value};
849
850    fn col(name: &str, ty: ColumnType) -> Column {
851        let mut payload = b"\x00def".to_vec();
852        for _ in 0..5 {
853            payload.write_lenenc_str(name.as_bytes()).unwrap();
854        }
855        payload.extend_from_slice(&b"_\x2d\x00\xff\xff\xff\xff"[..]);
856        payload.push(ty as u8);
857        payload.extend_from_slice(&b"\x00\x00\x00"[..]);
858        Column::read(&payload[..]).unwrap()
859    }
860
861    let row = Row {
862        values: vec![
863            Some(Value::Bytes(b"12.3456789".to_vec())),
864            Some(Value::Int(0xF0)),
865            Some(Value::Int(0xF000)),
866            Some(Value::Int(0xF0000000)),
867        ],
868        columns: Arc::from(
869            vec![
870                col("foo", ColumnType::MYSQL_TYPE_STRING),
871                col("foo", ColumnType::MYSQL_TYPE_TINY),
872                col("foo", ColumnType::MYSQL_TYPE_SHORT),
873                col("foo", ColumnType::MYSQL_TYPE_LONG),
874            ]
875            .into_boxed_slice(),
876        ),
877    };
878
879    bencher.iter(|| from_row::<(String, u8, u16, u32)>(row.clone()));
880}