Repository: launchbadge/sqlx
File: sqlx-postgres/src/bind_iter.rs (Rust)

Code before:
    }
}

impl<T, I> Type<Postgres> for PgBindIter<I>
where
    T: Type<Postgres> + PgHasArrayType,
    I: Iterator<Item = T>,
{
    fn type_info() -> <Postgres as Database>::TypeInfo {
        T::array_type_info()
    }
    fn compatible(ty: &PgTypeInfo) -> bool {
        T::array_compatible(ty)
    }
}

impl<'q, T, I> PgBindIter<I>
where
    I: Iterator<Item = T>,
    T: Type<Postgres> + Encode<'q, Postgres>,
{
    fn encode_inner(
        // need ownership to iterate
        mut iter: I,
        buf: &mut PgArgumentBuffer,
    ) -> Result<IsNull, Box<dyn std::error::Error + Send + Sync + 'static>> {
        let first = iter.next();
        let type_info = first
            .as_ref()
            .and_then(Encode::produces)
            .unwrap_or_else(T::type_info);

        buf.extend(&1_i32.to_be_bytes()); // number of dimensions
        buf.extend(&0_i32.to_be_bytes()); // flags

        match type_info.0 {
            PgType::DeclareWithName(name) => buf.patch_type_by_name(&name),
            PgType::DeclareArrayOf(array) => buf.patch_array_type(array),

            ty => {
                buf.extend(&ty.oid().0.to_be_bytes());
            }
        }

        let len_start = buf.len();
        buf.extend(0_i32.to_be_bytes()); // len (unknown so far)
        buf.extend(1_i32.to_be_bytes()); // lower bound

        match first {
            Some(first) => buf.encode(first)?,
            None => return Ok(IsNull::No),

Review comment (suggestion):
```suggestion
    ) -> Result<IsNull, BoxDynError> {
```

Code after:
/// requires iterating 3 times to collect items into the array and then
/// iterating over them again to encode.
///
/// This now requires only iterating over the array once for each field
/// while using less memory giving both speed and memory usage improvements
/// along with allowing much more flexibility in the underlying collection.
///
/// ```rust,no_run
/// # async fn test_bind_iter() -> Result<(), sqlx::error::BoxDynError> {
/// # use sqlx::types::chrono::{DateTime, Utc};
/// # use sqlx::Connection;
/// # fn people() -> &'static [Person] {
/// #   &[]
/// # }
/// # let mut conn = <sqlx::Postgres as sqlx::Database>::Connection::connect("dummyurl").await?;
/// use sqlx::postgres::PgBindIterExt;
///
/// #[derive(sqlx::FromRow)]
/// struct Person {
///     id: i64,
///     name: String,
///     birthdate: DateTime<Utc>,
/// }
///
/// # let people: &[Person] = people();
/// sqlx::query("insert into person(id, name, birthdate) select * from unnest($1, $2, $3)")
///     .bind(people.iter().map(|p| p.id).bind_iter())
///     .bind(people.iter().map(|p| &p.name).bind_iter())
///     .bind(people.iter().map(|p| &p.birthdate).bind_iter())
///     .execute(&mut conn)
///     .await?;
///
/// # Ok(())
/// # }
/// ```
pub trait PgBindIterExt: Iterator + Sized {
    fn bind_iter(self) -> PgBindIter<Self>;
}

impl<I: Iterator + Sized> PgBindIterExt for I {
    fn bind_iter(self) -> PgBindIter<I> {
        PgBindIter(Cell::new(Some(self)))
    }
}

impl<I> Type<Postgres> for PgBindIter<I>
where
    I: Iterator,
    <I as Iterator>::Item: Type<Postgres> + PgHasArrayType,
{
    fn type_info() -> <Postgres as Database>::TypeInfo {