use std::{
fmt::{Display, Write},
hash::Hash,
};
use log::debug;
pub mod map_tree;
#[derive(Clone, Debug, Eq)]
pub struct MapKey {
pub key: char,
resolution: usize,
/// Part of the path, used to derive the key
part_path: String,
}
impl Hash for MapKey {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.key.hash(state)
}
}
impl PartialEq for MapKey {
fn eq(&self, other: &Self) -> bool {
self.key == other.key
}
}
impl MapKey {
pub fn new_from_part_path(part_path: &str, resolution: usize) -> Vec<Self> {
let key = Self::part_path_to_key(&part_path, resolution);
key.chars()
.map(|ch| Self {
key: ch,
resolution,
part_path: part_path.to_owned(),
})
.collect()
}
pub fn new_ones_from_path(path: &str, number_of_chars: usize) -> Vec<Self> {
let key: Vec<MapKey> = path
.split('/')
.map(|part| Self::new_from_part_path(part, number_of_chars))
.flatten()
.collect();
debug!(
"Generated full MapKeys: '{}' -> '{}'",
path,
MapKey::display(&key)
);
key
}
pub fn increment(&self, target_resolution: usize) -> Vec<Self> {
let new_resolution = target_resolution;
// debug!("Incrementing: '{}' ('{}')", &self, &self.part_path);
let added_chars = if new_resolution < self.part_path.len() {
MapKey::part_path_to_key(&self.part_path, new_resolution)
} else {
let mut generated_chars =
MapKey::part_path_to_key(&self.part_path, self.part_path.len());
generated_chars.extend(
(0..(new_resolution - self.part_path.len()))
.into_iter()
.map(|_| self.part_path.chars().last().expect("This will exists")),
);
generated_chars
};
let part_path = self.part_path.clone();
let output: Vec<Self> = added_chars
.chars()
.enumerate()
.map(|(res, ch)| MapKey {
key: ch,
resolution: res + 1,
part_path: part_path.clone(),
})
.collect();
// debug!("Finished increment: '{}' ('{}')", MapKey::display(&output), output[0].part_path);
output
}
pub fn display(values: &[Self]) -> String {
values.iter().map(|value| value.key.clone()).collect()
}
fn part_path_to_key(part: &str, number_of_chars: usize) -> String {
fn make(pat: char, part: &str, number_of_chars: usize) -> String {
let mut acc = String::new();
if !part.split(pat).all(|part| part.len() > 0) {
panic!(
"\
Can't turn this path '{}' to a mapping.
This should not happen, please report the bug!",
part
)
}
let mut last_working = None;
for i in 0..number_of_chars {
for str in part.split(pat) {
if acc.len() != number_of_chars {
acc.push(match str.chars().nth(i) {
Some(ch) => ch,
None => {
if let Some(last) = last_working {
str.chars().nth(last).expect("This should always exist")
} else {
last_working = Some(i - 1);
str.chars().nth(i - 1).expect("This should always exist")
}
}
})
}
}
}
acc
}
let value = if part.contains('_') && !part.starts_with('_') && !part.ends_with('_') {
make('_', part, number_of_chars)
} else if part.contains('-') && !part.starts_with('-') && !part.ends_with('-') {
make('-', part, number_of_chars)
} else {
part.chars().take(number_of_chars).collect::<String>()
};
assert_eq!(
value.len(),
number_of_chars,
"'{}' does not have expected length of: {}",
value,
number_of_chars
);
value
}
}
impl Display for MapKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_char(self.key)
}
}