1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
use std::io::{Read, Result, ErrorKind};


pub struct Buffer {
    data: Box<[u8]>,
    start: usize,
    end: usize
}


impl Buffer {
    pub fn new(size: usize) -> Buffer {
        Buffer {
            data: vec![0u8; size].into_boxed_slice(),
            start: 0,
            end: 0
        }
    }

    pub fn len(&self) -> usize {
        self.end.checked_sub(self.start).unwrap()
    }

    pub fn n_free(&self) -> usize {
        self.data.len().checked_sub(self.end).unwrap()
    }

    pub fn pos(&self) -> usize {
        self.start
    }

    pub fn replace_buffer(&mut self, mut buffer: Box<[u8]>) -> Box<[u8]> {
        let n_in_buffer = self.len();
        let new_end = (n_in_buffer + 15) & !0x0f;  // make sure next read is aligned
        let new_start = new_end.checked_sub(n_in_buffer).unwrap();

        assert!(buffer.len() >= new_end);

        {
            let dest = &mut buffer[new_start..new_end];
            let src = &self.data[self.start..self.end];
            dest.copy_from_slice(src);
        }

        ::std::mem::swap(&mut self.data, &mut buffer);
        self.start = new_start;
        self.end = new_end;

        buffer
    }

    /// Move data to the start of the buffer, freeing space at the end.
    pub fn clean(&mut self) {
        if self.start == 0 {
            return
        }

        let n_in_buffer = self.len();
        let new_end = (n_in_buffer + 15) & !0x0f;  // make sure next read is aligned
        let new_start = new_end.checked_sub(n_in_buffer).unwrap();

        if new_start >= self.start {
            return
        }

        let dest = self.data[new_start..].as_mut_ptr();
        let src = self.data[self.start..].as_ptr();

        unsafe { ::std::ptr::copy(src, dest, n_in_buffer); }
        self.start = new_start;
        self.end = new_end;
    }

    pub fn read_into<R: Read>(&mut self, reader: &mut R) -> Result<usize> {
        let n_free = self.n_free();
        let num_read = if n_free < 4096 { n_free } else { n_free - n_free % 4096 };

        let dest = &mut self.data[self.end..self.end + num_read];

        let n_read;
        loop {
            match reader.read(dest) {
                Err(e) => {
                    if e.kind() != ErrorKind::Interrupted {
                        return Err(e)
                    }
                },
                Ok(val) => { n_read = val; break }
            }
        };
        self.end += n_read;
        Ok(n_read)
    }

    #[inline]
    pub fn data(&self) -> &[u8] {
        &self.data[self.start..self.end]
    }

    #[inline]
    pub fn consume(&mut self, count: usize) {
        self.start = self.start.checked_add(count).unwrap();
        debug_assert!(self.start <= self.end);
    }
}