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(&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 { 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 { let key: Vec = 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 { 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 = 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::() }; 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) } }