use std::{
ops::RangeInclusive,
path::{Path, PathBuf}
};
pub const TEXTURE_HEIGHT_RANGE: RangeInclusive<i8> = 0..=20;
#[allow(clippy::doc_markdown)]
pub const FILE_EXTENSION: &str = "hv";
pub trait NextValue<T>
where
Self: Iterator<Item = T>
{
#[inline]
#[must_use]
fn next_value(&mut self) -> T { self.next().unwrap() }
}
impl<T, U: Iterator<Item = T>> NextValue<T> for U {}
#[macro_export]
macro_rules! iterate_slice_in_triplets {
($i:ident, $j:ident, $k:ident, $max: expr, $f:block) => (
let (mut $i, mut $j, mut $k) = ($max - 2, $max - 1, 0);
while $k < $max
{
$f
$i = $j;
$j = $k;
$k += 1;
}
);
}
#[macro_export]
macro_rules! return_if_none {
($value:expr) => {
match $value
{
Some(value) => value,
None => return
}
};
($value:expr, $return_value:expr) => {
match $value
{
Some(value) => value,
None => return $return_value
}
};
}
#[macro_export]
macro_rules! return_if_no_match {
($value:expr, $pattern:pat, $f:expr) => {
match $value
{
$pattern => $f,
_ => return
}
};
($value:expr, $pattern:pat, $f:expr, $return_value:expr) => {
match $value
{
$pattern => $f,
_ => return $return_value
}
};
}
#[macro_export]
macro_rules! return_if_err {
($value:expr) => {
match $value
{
Ok(value) => value,
Err(_) => return
}
};
($value:expr, $return_value:expr) => {
match $value
{
Ok(value) => value,
Err(_) => return $return_value
}
};
}
#[macro_export]
macro_rules! continue_if_none {
($value:expr) => (
match $value
{
Some(value) => value,
None => continue
}
);
($value:expr, $label:tt) => (
match $value
{
Some(value) => value,
None => continue $label
}
);
}
#[macro_export]
macro_rules! continue_if_err {
($value:expr) => {
match $value
{
Ok(value) => value,
Err(_) => continue
}
};
}
#[macro_export]
macro_rules! continue_if_no_match {
($value:expr, $pattern:pat, $f:expr) => {
match $value
{
$pattern => $f,
_ => continue
}
};
}
#[macro_export]
macro_rules! match_or_panic {
($value:expr, $pattern:pat, $f:expr) => {
match $value
{
$pattern => $f,
_ => panic!("Pattern does not match.")
}
};
($value:expr, $pattern:pat) => {
match $value
{
$pattern => (),
_ => panic!("Pattern does not match.")
}
};
}
pub enum ManualItem
{
Regular,
Tool,
Texture
}
#[allow(clippy::missing_panics_doc)]
#[inline]
pub fn process_docs<S, N, P, E>(
section_start: S,
section_name: N,
process_file: P,
section_end: E
) -> String
where
S: Fn(&mut String),
N: Fn(&mut String, &str, ManualItem),
P: Fn(&mut String, &str, String, ManualItem),
E: Fn(&mut String, bool)
{
impl From<char> for ManualItem
{
#[inline]
fn from(value: char) -> Self
{
if value == 'S' || value == 'T'
{
Self::Tool
}
else if value == 'X'
{
Self::Texture
}
else
{
Self::Regular
}
}
}
#[inline]
fn stem_chars(path: &Path) -> (impl Iterator<Item = char> + '_, ManualItem)
{
let mut chars = path.file_stem().unwrap().to_str().unwrap().chars();
let first = chars.next_value();
(chars.skip_while(|c| !c.is_alphabetic()), first.into())
}
let mut string = String::new();
let mut dirs = std::fs::read_dir(PathBuf::from("docs/manual/"))
.unwrap()
.map(|entry| entry.unwrap().path())
.collect::<Vec<_>>();
dirs.sort_unstable();
let last_index = dirs.len() - 1;
for (i, dir) in dirs.into_iter().enumerate()
{
section_start(&mut string);
let (mut chars, item) = stem_chars(&dir);
let mut name = String::from(chars.next_value().to_ascii_uppercase());
while let Some(mut c) = chars.by_ref().next()
{
if c == '_'
{
c = ' ';
}
name.push(c);
}
section_name(&mut string, &name, item);
let mut paths = std::fs::read_dir(&dir)
.unwrap()
.map(|entry| entry.unwrap().path())
.collect::<Vec<_>>();
paths.sort_unstable();
for path in paths
{
let (chars, item) = stem_chars(&path);
process_file(
&mut string,
&chars.collect::<String>(),
std::fs::read_to_string(&path).unwrap(),
item
);
}
section_end(&mut string, i == last_index);
}
string
}