cartel-pg 0.30.0

Async PostgreSQL driver for the dope runtime
use o3::alloc::array;
use std::{marker, mem};

use crate::protocol::{Length, Reason, Wire};

pub struct Array<'row, T> {
    bytes: Wire<'row>,
    len: usize,
    marker: marker::PhantomData<T>,
}

impl<T> Copy for Array<'_, T> {}

impl<T> Clone for Array<'_, T> {
    fn clone(&self) -> Self {
        *self
    }
}

impl<'row, T> Array<'row, T>
where
    T: Element<'row>,
{
    pub(crate) const fn new(bytes: Wire<'row>, len: usize) -> Self {
        Self {
            bytes,
            len,
            marker: marker::PhantomData,
        }
    }

    pub const fn len(self) -> usize {
        self.len
    }

    pub const fn is_empty(self) -> bool {
        self.len == 0
    }

    pub fn try_collect(self) -> Result<Vec<T::Owned>, crate::Error> {
        let Self { mut bytes, len, .. } = self;
        let values = array::Block::<mem::MaybeUninit<T::Owned>, usize>::try_new(len, ())
            .map_err(crate::Error::Allocation)?
            .try_init(|_| T::__read(&mut bytes)?.__own())?;
        finish(bytes)?;
        Ok(values.into_vec())
    }
}

pub struct Iter<'row, T> {
    state: State<'row>,
    marker: marker::PhantomData<T>,
}

enum State<'row> {
    Reading { bytes: Wire<'row>, remaining: usize },
    Done,
}

impl<'row, T> Iterator for Iter<'row, T>
where
    T: Element<'row>,
{
    type Item = Result<T, crate::Error>;

    fn next(&mut self) -> Option<Self::Item> {
        let State::Reading {
            bytes,
            remaining: left,
        } = &mut self.state
        else {
            return None;
        };
        if *left == 0 {
            let result = finish(*bytes).err().map(Err);
            self.state = State::Done;
            return result;
        }
        *left -= 1;
        match T::__read(bytes) {
            Ok(value) => Some(Ok(value)),
            Err(error) => {
                self.state = State::Done;
                Some(Err(error))
            }
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        match &self.state {
            State::Reading {
                remaining: left, ..
            } => (0, left.checked_add(1)),
            State::Done => (0, Some(0)),
        }
    }
}

const _: () = assert!(mem::size_of::<Iter<'static, i32>>() == 3 * mem::size_of::<usize>());

impl<'row, T> IntoIterator for Array<'row, T>
where
    T: Element<'row>,
{
    type Item = Result<T, crate::Error>;
    type IntoIter = Iter<'row, T>;

    fn into_iter(self) -> Self::IntoIter {
        Iter {
            state: State::Reading {
                bytes: self.bytes,
                remaining: self.len,
            },
            marker: marker::PhantomData,
        }
    }
}

#[doc(hidden)]
pub trait Element<'row>: Sized {
    type Owned;

    fn __read(bytes: &mut Wire<'row>) -> Result<Self, crate::Error>;

    fn __own(self) -> Result<Self::Owned, crate::Error>;
}

fn finish(bytes: Wire<'_>) -> Result<(), crate::Error> {
    if bytes.is_empty() {
        Ok(())
    } else {
        Err(crate::Error::Protocol(Reason::ArrayTrailing {
            actual: bytes.length(),
        }))
    }
}

fn element<'row>(bytes: &mut Wire<'row>) -> Result<Wire<'row>, crate::Error> {
    let Some((head, tail)) = bytes.split_array::<4>() else {
        return Err(crate::Error::Protocol(Reason::ArrayLength {
            actual: bytes.length(),
        }));
    };
    let len = i32::from_be_bytes(*head);
    *bytes = tail;
    if len == -1 {
        return Err(crate::Error::Protocol(Reason::ArrayNull));
    }
    let Ok(len) = u32::try_from(len) else {
        return Err(crate::Error::Protocol(Reason::NegativeArrayLength {
            actual: len,
        }));
    };
    let Some((head, tail)) = bytes.split_at(len as usize) else {
        return Err(crate::Error::Protocol(Reason::ArrayBytes {
            actual: bytes.length(),
            required: Length::from_u32(len),
        }));
    };
    *bytes = tail;
    Ok(head)
}

impl<'row> Element<'row> for i32 {
    type Owned = Self;

    fn __read(bytes: &mut Wire<'row>) -> Result<Self, crate::Error> {
        let bytes = element(bytes)?;
        let Ok(value) = bytes.as_slice().try_into() else {
            return Err(crate::Error::Protocol(Reason::ArrayI32Width {
                actual: bytes.length(),
            }));
        };
        Ok(Self::from_be_bytes(value))
    }

    fn __own(self) -> Result<Self::Owned, crate::Error> {
        Ok(self)
    }
}

impl<'row> Element<'row> for i64 {
    type Owned = Self;

    fn __read(bytes: &mut Wire<'row>) -> Result<Self, crate::Error> {
        let bytes = element(bytes)?;
        let Ok(value) = bytes.as_slice().try_into() else {
            return Err(crate::Error::Protocol(Reason::ArrayI64Width {
                actual: bytes.length(),
            }));
        };
        Ok(Self::from_be_bytes(value))
    }

    fn __own(self) -> Result<Self::Owned, crate::Error> {
        Ok(self)
    }
}

impl<'row> Element<'row> for &'row str {
    type Owned = String;

    fn __read(bytes: &mut Wire<'row>) -> Result<Self, crate::Error> {
        match element(bytes)?.try_text() {
            Ok(value) => Ok(value.as_str()),
            Err(error) => Err(crate::Error::Protocol(Reason::ArrayTextUtf8 {
                valid: error.valid,
                error: error.error,
            })),
        }
    }

    fn __own(self) -> Result<Self::Owned, crate::Error> {
        crate::Error::try_string(self)
    }
}