use std::cmp::PartialEq;
use std::ops::{Index, IndexMut};
use std::path::PathBuf;
use std::fmt;
pub mod tag;
pub use self::tag::*;
mod trig;
pub use self::trig::*;
mod color;
pub use self::color::*;
use crate::error::*;
use ringhopper_proc::*;
pub type FourCC = u32;
pub type Data = Vec<u8>;
pub trait TagEnumFn {
fn into_u16(self) -> u16 where Self: Sized;
fn from_u16(input_value: u16) -> ErrorMessageResult<Self> where Self: Sized;
fn options() -> &'static [&'static str];
fn options_pretty() -> &'static [&'static str];
fn as_str(self) -> &'static str where Self: Sized {
Self::options()[self.into_u16() as usize]
}
fn as_str_pretty(self) -> &'static str where Self: Sized {
Self::options_pretty()[self.into_u16() as usize]
}
}
pub const HALO_DIRECTORY_SEPARATOR: char = '\\';
#[derive(Copy, Clone, Default, Debug, PartialEq)]
pub struct String32 {
pub(crate) bytes: [u8; 32],
pub(crate) length: usize
}
impl String32 {
pub fn to_str(&self) -> &str {
std::str::from_utf8(&self.bytes[0..self.length]).unwrap()
}
pub fn from_bytes(bytes: [u8; 32]) -> ErrorMessageResult<String32> {
let mut length: usize = 0;
for b in bytes {
if b == 0 {
break;
}
length += 1;
}
if length >= bytes.len() {
Err(ErrorMessage::StaticString(get_compiled_string!("engine.types.error_string_not_null_terminated")))
}
else if !std::str::from_utf8(&bytes[0..length]).is_ok() {
Err(ErrorMessage::StaticString(get_compiled_string!("engine.types.error_string_not_valid_utf8")))
}
else {
let mut bytes_copy = bytes;
for i in &mut bytes_copy[length..] {
*i = 0
}
Ok(String32 { bytes: bytes_copy, length })
}
}
pub fn from_bytes_slice(bytes: &[u8]) -> ErrorMessageResult<String32> {
let mut input_bytes = [0u8; 32];
let len = bytes.len();
let limit = input_bytes.len() - 1;
if len > limit {
return Err(ErrorMessage::AllocatedString(format!(get_compiled_string!("engine.types.error_string_exceeds_limit"), limit=limit, len=len)))
}
for b in 0..bytes.len() {
input_bytes[b] = bytes[b];
}
Self::from_bytes(input_bytes)
}
pub fn from_str(string: &str) -> ErrorMessageResult<String32> {
Self::from_bytes_slice(string.as_bytes())
}
}
impl fmt::Display for String32 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
f.write_str(self.to_str())
}
}
#[derive(Copy, Clone, Default, Debug, PartialEq)]
pub struct Point2DInt {
pub x: i16,
pub y: i16
}
#[derive(Copy, Clone, Default, Debug, PartialEq)]
pub struct Point2DUInt {
pub x: u16,
pub y: u16
}
#[derive(Copy, Clone, Default, Debug, PartialEq)]
pub struct Rectangle {
pub top: i16,
pub left: i16,
pub bottom: i16,
pub right: i16
}
#[derive(Copy, Clone, Default, PartialEq, Debug)]
pub struct Bounds<T> {
pub lower: T,
pub upper: T
}
impl<T: PartialOrd + Copy> Bounds<T> {
pub fn is_normal(&self) -> bool {
self.upper >= self.lower
}
pub fn normalize_lower(self) -> Bounds<T> {
if self.lower > self.upper {
Bounds { lower: self.upper, upper: self.upper }
}
else {
self
}
}
pub fn normalize_upper(self) -> Bounds<T> {
if self.upper < self.lower {
Bounds { lower: self.lower, upper: self.lower }
}
else {
self
}
}
}
fn match_pattern_bytes(string: &[u8], pattern: &[u8]) -> bool {
let string_len = string.len();
let pattern_len = pattern.len();
let mut string_index = 0usize;
let mut pattern_index = 0usize;
while string_index < string_len && pattern_index < pattern_len {
let p = pattern[pattern_index] as char;
let s = string[string_index] as char;
if (p == s && p != '*') || p == '?' || ((p == '/' || p == HALO_DIRECTORY_SEPARATOR || p == std::path::MAIN_SEPARATOR) && (s == '/' || s == HALO_DIRECTORY_SEPARATOR || s == std::path::MAIN_SEPARATOR)) {
pattern_index += 1;
string_index += 1;
}
else if p == '*' {
while pattern_index < pattern_len && pattern[pattern_index] as char == '*' {
pattern_index += 1;
}
for i in string_index..=string_len {
if match_pattern_bytes(&string[i..], &pattern[pattern_index..]) {
return true
}
}
return false;
}
else {
return false;
}
}
string_index == string_len && pattern_index == pattern_len
}
pub fn match_pattern(string: &str, pattern: &str) -> bool {
match_pattern_bytes(string.as_bytes(), pattern.as_bytes())
}
pub(crate) fn log2_u16(input: u16) -> u16 {
debug_assert!(input > 0, "cannot log2 zero");
let mut v = 0;
let mut i = input / 2;
while i > 0 {
i /= 2;
v += 1;
}
v
}