//! QuickDraw PICT format run length encoded data.

use crate::{bin::*, err::*};

/// Read run-length encoded data.
pub fn read<T>(b: &[u8], pitch: usize) -> ResultS<(Vec<T>, usize)>
	where T: ReadRleData
{
	let mut p = 0;
	let mut o = Vec::with_capacity(pitch);

	let sz = if pitch > 250 {
		(usize::from(u16b(b)) + 2, p += 2).0
	} else {
		(usize::from(b[0]) + 1, p += 1).0
	};

	while p < sz {
		let szf = b[p];
		let cmp = szf & 0x80 != 0;
		let len = usize::from(if cmp {!szf + 2} else {szf + 1});

		p += 1;
		o.reserve(len);

		T::read_rle_data(b, &mut p, cmp, len, &mut o);
	}

	if o.len() == pitch {
		Ok((o, p))
	} else {
		Err(err_msg("incorrect size for compressed scanline"))
	}
}

pub trait ReadRleData: Sized
{
	// Read a sequence of packed RLE data.
	fn read_rle_data(b: &[u8],
	                 p: &mut usize,
	                 cmp: bool,
	                 len: usize,
	                 out: &mut Vec<Self>);
}

impl ReadRleData for u16
{
	fn read_rle_data(b: &[u8],
	                 p: &mut usize,
	                 cmp: bool,
	                 len: usize,
	                 out: &mut Vec<Self>)
	{
		if cmp {
			let d = u16b(&b[*p..*p + 2]);
			*p += 2;
			for _ in 0..len {
				out.push(d);
			}
		} else {
			for _ in 0..len {
				let d = u16b(&b[*p..*p + 2]);
				*p += 2;
				out.push(d);
			}
		}
	}
}

impl ReadRleData for u8
{
	fn read_rle_data(b: &[u8],
	                 p: &mut usize,
	                 cmp: bool,
	                 len: usize,
	                 out: &mut Vec<Self>)
	{
		if cmp {
			let d = b[*p];
			*p += 1;
			for _ in 0..len {
				out.push(d);
			}
		} else {
			for _ in 0..len {
				let d = b[*p];
				*p += 1;
				out.push(d);
			}
		}
	}
}

// EOF
