elefant-client 0.1.0

A pure rust implementation of a postgres client that is independent of the executor runtime
Documentation
use std::borrow::Cow;
use std::num::NonZeroUsize;

pub trait Decoder<'a, O: 'a> {
    type Error: From<std::io::Error>;

    fn decode(buffer: &mut ByteSliceReader<'a>) -> DecodeResult<O, Self::Error>;
}

pub type DecodeResult<T, E> = Result<T, DecodeError<E>>;

#[derive(Debug)]
pub enum DecodeError<E> {
    NeedsMoreData(Option<NonZeroUsize>),
    Error(E),
}

impl<E> From<ByteSliceError> for DecodeError<E> {
    fn from(value: ByteSliceError) -> Self {
        match value {
            ByteSliceError::NeedsMoreData(n) => DecodeError::NeedsMoreData(n),
        }
    }
}

pub trait DecodeErrorError {}

impl<E: DecodeErrorError> From<E> for DecodeError<E> {
    fn from(value: E) -> Self {
        DecodeError::Error(value)
    }
}

#[derive(Debug)]
pub enum ByteSliceError {
    NeedsMoreData(Option<NonZeroUsize>),
}

pub struct ByteSliceReader<'a> {
    bytes: &'a [u8],
    read_bytes: usize,
}

impl<'a> ByteSliceReader<'a> {
    pub fn new(bytes: &'a [u8]) -> Self {
        Self {
            bytes,
            read_bytes: 0,
        }
    }

    #[inline]
    pub fn get_read_bytes(&self) -> usize {
        self.read_bytes
    }

    pub fn read_null_terminated_string(&mut self) -> Result<Cow<'a, str>, ByteSliceError> {
        let mut position = 0;
        loop {
            if self.bytes.len() <= position {
                return Err(ByteSliceError::NeedsMoreData(None));
            }
            if self.bytes[position] == 0 {
                break;
            }
            position += 1;
        }
        let (byt, remaining) = self.bytes.split_at(position);
        self.bytes = &remaining[1..];
        let result = String::from_utf8_lossy(byt);
        self.read_bytes += position + 1;
        Ok(result)
    }

    pub fn read_i32(&mut self) -> Result<i32, ByteSliceError> {
        if self.bytes.len() < 4 {
            return Err(ByteSliceError::NeedsMoreData(NonZeroUsize::new(4)));
        }

        let result =
            i32::from_be_bytes([self.bytes[0], self.bytes[1], self.bytes[2], self.bytes[3]]);
        self.bytes = &self.bytes[4..];
        self.read_bytes += 4;
        Ok(result)
    }

    pub fn read_i16(&mut self) -> Result<i16, ByteSliceError> {
        if self.bytes.len() < 2 {
            return Err(ByteSliceError::NeedsMoreData(NonZeroUsize::new(2)));
        }

        let result = i16::from_be_bytes([self.bytes[0], self.bytes[1]]);
        self.bytes = &self.bytes[2..];
        self.read_bytes += 2;
        Ok(result)
    }

    pub fn read_i8(&mut self) -> Result<i8, ByteSliceError> {
        if self.bytes.is_empty() {
            return Err(ByteSliceError::NeedsMoreData(NonZeroUsize::new(1)));
        }

        let result = i8::from_be_bytes([self.bytes[0]]);
        self.bytes = &self.bytes[1..];
        self.read_bytes += 1;
        Ok(result)
    }

    pub fn read_u8(&mut self) -> Result<u8, ByteSliceError> {
        if self.bytes.is_empty() {
            return Err(ByteSliceError::NeedsMoreData(NonZeroUsize::new(1)));
        }

        let result = self.bytes[0];
        self.bytes = &self.bytes[1..];
        self.read_bytes += 1;
        Ok(result)
    }

    pub fn read_i64(&mut self) -> Result<i64, ByteSliceError> {
        if self.bytes.len() < 8 {
            return Err(ByteSliceError::NeedsMoreData(NonZeroUsize::new(8)));
        }

        let result = i64::from_be_bytes(self.bytes[..8].try_into().unwrap());
        self.bytes = &self.bytes[8..];
        self.read_bytes += 8;
        Ok(result)
    }

    pub fn read_u64(&mut self) -> Result<u64, ByteSliceError> {
        if self.bytes.len() < 8 {
            return Err(ByteSliceError::NeedsMoreData(NonZeroUsize::new(8)));
        }

        let result = u64::from_be_bytes(self.bytes[..8].try_into().unwrap());
        self.bytes = &self.bytes[8..];
        self.read_bytes += 8;
        Ok(result)
    }

    pub fn read_bytes(&mut self, n: usize) -> Result<&'a [u8], ByteSliceError> {
        if n == 0 {
            return Ok(&[]);
        }

        match self.bytes.split_at_checked(n) {
            Some((byt, remaining)) => {
                self.bytes = remaining;
                self.read_bytes += n;
                Ok(byt)
            }
            None => Err(ByteSliceError::NeedsMoreData(NonZeroUsize::new(n))),
        }
    }

    pub fn read_exact(&mut self, slice: &mut [u8]) -> Result<(), ByteSliceError> {
        if slice.is_empty() {
            return Ok(());
        }

        match self.bytes.split_at_checked(slice.len()) {
            Some((byt, remaining)) => {
                slice.copy_from_slice(byt);
                self.bytes = remaining;
                self.read_bytes += slice.len();
                Ok(())
            }
            None => Err(ByteSliceError::NeedsMoreData(NonZeroUsize::new(
                slice.len(),
            ))),
        }
    }

    pub fn require_bytes(&self, required: usize) -> Result<(), ByteSliceError> {
        if self.bytes.len() < required {
            Err(ByteSliceError::NeedsMoreData(NonZeroUsize::new(required)))
        } else {
            Ok(())
        }
    }
}