typed-clickhouse 0.2.0

a typed client for ClickHouse
Documentation
use std::collections::VecDeque;

use bytes::Buf;

#[derive(Default)]
pub struct BufList<T> {
    bufs: VecDeque<T>,
    rem: usize,
    cursor: usize,
}

impl<T: Buf> BufList<T> {
    #[inline]
    pub fn push(&mut self, buf: T) {
        let rem = buf.remaining();

        if rem > 0 {
            self.bufs.push_back(buf);
            self.rem += rem;
        }
    }

    #[inline]
    pub fn bufs_cnt(&self) -> usize {
        self.bufs.len()
    }

    pub fn commit(&mut self) {
        while self.cursor > 0 {
            let front = &mut self.bufs[0];
            let rem = front.remaining();

            if rem > self.cursor {
                front.advance(self.cursor);
                self.cursor = 0;
            } else {
                front.advance(rem);
                self.cursor -= rem;
                self.bufs.pop_front();
            }
        }
    }

    pub fn rollback(&mut self) {
        self.rem += self.cursor;
        self.cursor = 0;
    }
}

impl<T: Buf> Buf for BufList<T> {
    #[inline]
    fn remaining(&self) -> usize {
        self.rem
    }

    #[inline]
    fn bytes(&self) -> &[u8] {
        let mut cnt = self.cursor;

        for buf in &self.bufs {
            let bytes = buf.bytes();
            if bytes.len() > cnt {
                return &bytes[cnt..];
            }
            cnt -= bytes.len();
        }

        b""
    }

    #[inline]
    fn advance(&mut self, cnt: usize) {
        self.rem -= cnt;
        self.cursor += cnt;
    }
}

#[test]
fn it_advances() {
    let mut list = BufList::<&[_]>::default();
    list.push(&[1, 2, 3]);
    list.push(&[]);
    list.push(&[4, 5, 6]);
    list.push(&[7, 8, 9]);
    list.push(&[]);

    assert_eq!(list.bufs_cnt(), 3);
    list.advance(1);
    list.commit();
    assert_eq!(list.bufs_cnt(), 3);
    list.advance(4);
    list.commit();
    assert_eq!(list.bufs_cnt(), 2);
    list.advance(4);
    list.commit();
    assert_eq!(list.bufs_cnt(), 0);
}

#[test]
fn it_copies_to_slice() {
    let mut list = BufList::<&[_]>::default();
    list.push(&[1, 2, 3]);
    list.push(&[]);
    list.push(&[4, 5, 6]);
    list.push(&[7, 8, 9]);
    list.push(&[]);
    assert_eq!(list.bufs_cnt(), 3);

    let mut result = vec![0; 9];

    list.copy_to_slice(&mut result[0..1]);
    list.commit();
    assert_eq!(result, [1, 0, 0, 0, 0, 0, 0, 0, 0]);
    assert_eq!(list.bufs_cnt(), 3);

    list.copy_to_slice(&mut result[1..5]);
    list.commit();
    assert_eq!(result, [1, 2, 3, 4, 5, 0, 0, 0, 0]);
    assert_eq!(list.bufs_cnt(), 2);

    list.copy_to_slice(&mut result[5..]);
    list.commit();
    assert_eq!(result, [1, 2, 3, 4, 5, 6, 7, 8, 9]);
    assert_eq!(list.bufs_cnt(), 0);
}

#[test]
fn it_does_rollback() {
    let mut list = BufList::<&[_]>::default();
    list.push(&[1, 2, 3]);
    list.push(&[4, 5]);

    let mut result = vec![0; 5];
    list.copy_to_slice(&mut result[0..2]);
    assert_eq!(result, [1, 2, 0, 0, 0]);
    list.commit();
    list.copy_to_slice(&mut result[2..4]);
    assert_eq!(result, [1, 2, 3, 4, 0]);
    list.copy_to_slice(&mut result[4..]);
    assert_eq!(result, [1, 2, 3, 4, 5]);

    list.rollback();

    let mut result = vec![0; 3];
    list.copy_to_slice(&mut result);
    assert_eq!(result, [3, 4, 5]);
}