tokio_postgres_extractor/
iter.rs

1//! Extension traits for working with iterators over [`Row`]s.
2//!
3//! Using these extension traits, iterators over [`Row`]s can be turned into iterators
4//! over [`Extract`]able types.
5//!
6//! # Examples
7//!
8//! ```
9//! # use tokio_postgres::Row;
10//! # use tokio_postgres_extractor::{Columns, Extract};
11//! # use tokio_postgres_extractor::iter::IterExtractRefExt;
12//! #[derive(Columns, Extract)]
13//! struct User<'a> {
14//!     id: i32,
15//!     name: &'a str,
16//! }
17//!
18//! fn extract_users<'a>(i: impl Iterator<Item = &'a Row>) -> Vec<User<'a>> {
19//!     i.extract_ref().collect()
20//! }
21//! ```
22
23use {
24    crate::{
25        iter::sealed::{Sealed1, Sealed2},
26        Extract, ExtractOwned,
27    },
28    tokio_postgres::Row,
29};
30
31#[cfg(test)]
32mod tests;
33
34/// An iterator over `T`s that are extracted from [`Row`]s.
35///
36/// Construct it using [`IterExtractExt::extract`].
37///
38/// # Panics
39///
40/// The iterator panics if [`Extract::extract`] panics.
41pub struct ExtractIter<T, I>
42where
43    T: ExtractOwned,
44    I: Iterator<Item = Row>,
45{
46    iter: I,
47    columns: Option<T::Columns>,
48}
49
50impl<T, I> Iterator for ExtractIter<T, I>
51where
52    T: ExtractOwned,
53    I: Iterator<Item = Row>,
54{
55    type Item = T;
56
57    fn next(&mut self) -> Option<Self::Item> {
58        Some(T::extract(&mut self.columns, &self.iter.next()?))
59    }
60}
61
62/// Extension trait for extracting from an iterator over [`Row`].
63pub trait IterExtractExt: Iterator<Item = Row> + Sized + Sealed2 {
64    /// Turns the iterator into an iterator over `T`.
65    ///
66    /// # Examples
67    ///
68    /// ```
69    /// # use tokio_postgres::Row;
70    /// # use tokio_postgres_extractor::iter::IterExtractExt;
71    /// # use tokio_postgres_extractor::{Columns, Extract};
72    /// #[derive(Columns, Extract)]
73    /// struct User {
74    ///     id: i32,
75    ///     name: String,
76    /// }
77    ///
78    /// fn extract_users(i: impl Iterator<Item = Row>) -> Vec<User> {
79    ///     i.extract().collect()
80    /// }
81    fn extract<T: ExtractOwned>(self) -> ExtractIter<T, Self>;
82}
83
84impl<I> Sealed2 for I where I: Iterator<Item = Row> {}
85
86impl<I> IterExtractExt for I
87where
88    I: Iterator<Item = Row>,
89{
90    fn extract<T: ExtractOwned>(self) -> ExtractIter<T, Self> {
91        ExtractIter {
92            iter: self,
93            columns: None,
94        }
95    }
96}
97
98/// An iterator over `T`s that are extracted from [`&Row`][Row]s.
99///
100/// Construct it using [`IterExtractRefExt::extract_ref`].
101///
102/// # Panics
103///
104/// The iterator panics if [`Extract::extract`] panics.
105pub struct ExtractIterRef<'a, T, I>
106where
107    T: Extract<'a>,
108    I: Iterator<Item = &'a Row>,
109{
110    iter: I,
111    columns: Option<T::Columns>,
112}
113
114impl<'a, T, I> Iterator for ExtractIterRef<'a, T, I>
115where
116    T: Extract<'a>,
117    I: Iterator<Item = &'a Row>,
118{
119    type Item = T;
120
121    fn next(&mut self) -> Option<Self::Item> {
122        Some(T::extract(&mut self.columns, self.iter.next()?))
123    }
124}
125
126/// Extension trait for extracting from an iterator over [`&Row`][Row].
127pub trait IterExtractRefExt<'a>: Iterator<Item = &'a Row> + Sized + Sealed1 {
128    /// Turns the iterator into an iterator over `T`.
129    ///
130    /// # Examples
131    ///
132    /// ```
133    /// # use tokio_postgres::Row;
134    /// # use tokio_postgres_extractor::iter::IterExtractRefExt;
135    /// # use tokio_postgres_extractor::{Columns, Extract};
136    /// #[derive(Columns, Extract)]
137    /// struct User<'a> {
138    ///     id: i32,
139    ///     name: &'a str,
140    /// }
141    ///
142    /// fn extract_users<'a>(i: impl Iterator<Item = &'a Row>) -> Vec<User<'a>> {
143    ///     i.extract_ref().collect()
144    /// }
145    /// ```
146    fn extract_ref<T: Extract<'a>>(self) -> ExtractIterRef<'a, T, Self>;
147}
148
149impl<'a, I> Sealed1 for I where I: Iterator<Item = &'a Row> {}
150
151impl<'a, I> IterExtractRefExt<'a> for I
152where
153    I: Iterator<Item = &'a Row>,
154{
155    fn extract_ref<T: Extract<'a>>(self) -> ExtractIterRef<'a, T, Self> {
156        ExtractIterRef {
157            iter: self,
158            columns: None,
159        }
160    }
161}
162
163mod sealed {
164    pub trait Sealed1 {}
165    pub trait Sealed2 {}
166}