clue_core 3.0.0

C/Rust like programming language that compiles into Lua code
Documentation
use std::{
	collections::{
		vec_deque::{IntoIter, Iter},
		VecDeque,
	},
	ffi::OsString,
	hash::Hash,
};

use utf8_decode::decode;

pub type CodeChar = (u8, usize);

#[derive(Debug, Clone, Default)]
pub struct Code {
	list: VecDeque<CodeChar>,
}

pub struct CodeBytes {
	code: Code,
	line: usize,
	read: usize,
}

pub struct CodeChars {
	code: CodeBytes,
}

impl Iterator for CodeBytes {
	type Item = u8;

	fn next(&mut self) -> Option<Self::Item> {
		self.code.pop_start().map(|(c, line)| {
			self.read += 1;
			self.line = line;
			c
		})
	}
}

impl Iterator for CodeChars {
	type Item = char;

	fn next(&mut self) -> Option<Self::Item> {
		match decode(&mut self.code) {
			None => None,
			Some(Err(_)) => Some('\u{FFFD}'),
			Some(Ok(c)) => Some(c),
		}
	}
}

impl CodeChars {
	pub fn next_unwrapped(&mut self) -> char {
		self.next().unwrap_or('\0')
	}

	pub const fn line(&self) -> usize {
		self.code.line
	}

	pub fn bytes_read(&mut self) -> usize {
		let read = self.code.read;
		self.code.read = 0;
		read
	}
}

impl<'a> IntoIterator for &'a Code {
	type Item = &'a CodeChar;
	type IntoIter = Iter<'a, CodeChar>;

	fn into_iter(self) -> Iter<'a, CodeChar> {
		self.list.iter()
	}
}

impl IntoIterator for Code {
	type Item = CodeChar;
	type IntoIter = IntoIter<CodeChar>;

	fn into_iter(self) -> IntoIter<CodeChar> {
		self.list.into_iter()
	}
}

impl ToString for Code {
	fn to_string(&self) -> String {
		let mut result = String::with_capacity(self.len());
		for c in self.clone().chars() {
			result.push(c);
		}
		result
	}
}

impl<'a> From<(&'a [u8], usize)> for Code {
	fn from(value: (&'a [u8], usize)) -> Self {
		let (iter, line) = value;
		let mut result = Code::with_capacity(iter.len());
		for c in iter {
			result.push((*c, line))
		}
		result
	}
}

impl<'a, const N: usize> From<(&'a [u8; N], usize)> for Code {
	fn from(value: (&'a [u8; N], usize)) -> Self {
		Code::from((value.0 as &[u8], value.1))
	}
}

impl<'a> From<(&'a str, usize)> for Code {
	fn from(value: (&'a str, usize)) -> Self {
		Code::from((value.0.as_bytes(), value.1))
	}
}

impl From<(String, usize)> for Code {
	fn from(value: (String, usize)) -> Self {
		Code::from((value.0.as_bytes(), value.1))
	}
}

impl PartialEq for Code {
	fn eq(&self, other: &Self) -> bool {
		self.len() == other.len() && {
			let mut other = other.into_iter();
			for (c, _) in self {
				if *c != other.next().unwrap().0 {
					return false;
				}
			}
			true
		}
	}
}

impl PartialEq<&str> for Code {
	fn eq(&self, other: &&str) -> bool {
		self.len() == other.len() && {
			let mut other = other.bytes();
			for (c, _) in self {
				if *c != other.next().unwrap() {
					return false;
				}
			}
			true
		}
	}
}

impl PartialEq<OsString> for Code {
	fn eq(&self, other: &OsString) -> bool {
		self.len() == other.len() && {
			let other = other.clone().into_string().unwrap();
			let mut other = other.bytes();
			for (c, _) in self {
				if *c != other.next().unwrap() {
					return false;
				}
			}
			true
		}
	}
}

impl Eq for Code {}

impl Hash for Code {
	fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
		for (c, _) in &self.list {
			c.hash(state)
		}
	}
}

impl Code {
	pub fn new() -> Self {
		Self {
			list: VecDeque::new(),
		}
	}

	pub fn with_capacity(capacity: usize) -> Self {
		Self {
			list: VecDeque::with_capacity(capacity),
		}
	}

	pub fn append(&mut self, mut other: Self) {
		self.list.append(&mut other.list)
	}

	pub fn is_empty(&self) -> bool {
		self.list.is_empty()
	}

	pub fn len(&self) -> usize {
		self.list.len()
	}

	pub fn last(&self) -> Option<&CodeChar> {
		self.list.back()
	}

	pub fn push(&mut self, c: CodeChar) {
		self.list.push_back(c);
	}

	pub fn pop(&mut self) -> Option<CodeChar> {
		self.list.pop_back()
	}

	pub fn push_start(&mut self, c: CodeChar) {
		self.list.push_front(c)
	}
	pub fn pop_start(&mut self) -> Option<CodeChar> {
		self.list.pop_front()
	}

	pub fn iter(&self) -> Iter<CodeChar> {
		self.list.iter()
	}

	pub const fn bytes(self) -> CodeBytes {
		CodeBytes {
			code: self,
			line: 0,
			read: 0,
		}
	}

	pub const fn chars(self) -> CodeChars {
		CodeChars { code: self.bytes() }
	}

	pub fn trim(mut self) -> Self {
		while let Some((c, _)) = self.list.front() {
			if c.is_ascii_whitespace() {
				self.list.pop_front();
			} else {
				break;
			}
		}
		while let Some((c, _)) = self.list.back() {
			if c.is_ascii_whitespace() {
				self.list.pop_back();
			} else {
				break;
			}
		}
		self
	}
}