mpvsock 0.2.0

mpv socket ipc client with MIT/Apache-2.0 license
Documentation
use std::io::{self, Read};

pub struct ResponseBuffer {
	buffer: Vec<u8>,
	position: usize
}
impl ResponseBuffer {
	const LINE_DELIM: u8 = b'\n';
	const RESERVE_SIZE: usize = 128;

	pub fn new() -> Self {
		ResponseBuffer {
			buffer: Vec::with_capacity(Self::RESERVE_SIZE),
			position: 0
		}
	}

	pub fn read_nonblocking(&mut self, mut stream: impl Read) -> Result<(), io::Error> {
		match stream.read_to_end(&mut self.buffer) {
			Ok(_) => (),
			Err(err) if err.kind() == io::ErrorKind::WouldBlock => (),
			Err(err) => return Err(err)
		}

		Ok(())
	}

	pub fn read_blocking(&mut self, stream: impl Read) -> Result<(), io::Error> {
		for byte in stream.bytes() {
			let byte = match byte {
				Ok(byte) => byte,
				Err(err) if err.kind() == io::ErrorKind::WouldBlock => break,
				Err(err) => return Err(err)
			};

			if byte == Self::LINE_DELIM {
				break
			}

			self.buffer.push(byte);
		}

		Ok(())
	}

	pub fn read_from(&mut self, mut stream: impl Read) -> Result<(), io::Error> {
		if self.buffer.len() + Self::RESERVE_SIZE >= self.buffer.capacity() {
			self.buffer
				.resize(self.buffer.len() + Self::RESERVE_SIZE, 0);
		}

		match stream.read(&mut self.buffer) {
			Ok(_) => (),
			Err(err) if err.kind() == io::ErrorKind::WouldBlock => (),
			Err(err) => return Err(err)
		}

		Ok(())
	}

	pub fn consume_line(&mut self) -> Option<&[u8]> {
		let next_newline = self.buffer[self.position ..]
			.iter()
			.position(|&b| b == Self::LINE_DELIM);

		match next_newline {
			None => None,
			Some(end) => {
				let line = &self.buffer[self.position ..][.. end];
				self.position += end + 1;

				if log::log_enabled!(log::Level::Debug) {
					match std::str::from_utf8(line) {
						Ok(line) => {
							log::trace!("Consumed line: {}", line);
						}
						Err(_err) => {
							log::trace!("Consumed line: {:?}", line)
						}
					}
				}

				Some(line)
			}
		}
	}

	pub fn shift(&mut self) {
		log::trace!("Shifting buffer by {} elements", self.position);

		self.buffer.drain(.. self.position);
		self.position = 0;
	}
}