use std::str;
use std::{
collections::HashMap,
fs,
io::{Error, ErrorKind},
path::Path,
};
use crate::utils;
pub fn create_non_standard() -> Result<HashMap<u16, [u8; 4]>, Error> {
let mut json_content = read_file()?;
let pairs = parse_json(&mut json_content);
create_map(pairs)
}
fn read_file() -> Result<String, Error> {
let path = Path::new("./graphemes.json");
if !path.exists() {
return Err(Error::new(
ErrorKind::NotFound,
String::from("Could not find file named 'graphemes.json' in package root directory"),
));
}
let contents = fs::read_to_string(path)?;
Ok(contents)
}
fn parse_json(json_content: &mut String) -> Vec<Vec<&str>> {
json_content.retain(|c| c != ' ' && c != '\n' && c != '{' && c != '}' && c != '\"');
json_content
.split(',')
.map(|p| {
let pair: Vec<&str> = p.split(':').collect();
if pair.len() == 2 {
Some(pair)
} else {
None
}
})
.filter(|p| p.is_some())
.map(|o| {
unsafe { o.unwrap_unchecked() }
})
.collect()
}
fn create_map(pairs: Vec<Vec<&str>>) -> Result<HashMap<u16, [u8; 4]>, Error> {
let mut graphemes: HashMap<u16, [u8; 4]> = HashMap::new();
for p in pairs {
let number: u16 = match p[0].parse() {
Ok(number) => number,
Err(_) => {
return Err(Error::new(
ErrorKind::Other,
format!("Could not parse provided key '{}' to u16", p[0]),
))
}
};
if p[1] == "-" {
return Err(Error::new(
ErrorKind::InvalidData,
"Cannot use '-' as grapheme because it is used as a negative sign",
));
}
let bytes = p[1].as_bytes();
let mut rep = vec![0; 4 - bytes.len()];
for b in bytes {
rep.push(*b);
}
if graphemes.contains_key(&number) {
return Err(Error::new(ErrorKind::InvalidInput, format!("The same number cannot be used twice. Found two specifications for number {number}")));
}
let byte_arr = utils::vec_to_arr(rep);
for g in graphemes.values() {
if g == &byte_arr {
return Err(Error::new(ErrorKind::InvalidInput, format!("The same grapheme cannot be used twice. Found two specifications for grapheme {}", str::from_utf8(g).unwrap())));
}
}
graphemes.insert(number, byte_arr);
}
let max_key = match graphemes.keys().max() {
Some(value) => value,
None => {
return Err(Error::new(
ErrorKind::Other,
"Could not parse json. No value provided",
))
}
};
for i in 0..*max_key {
if !graphemes.contains_key(&i) {
return Err(Error::new(ErrorKind::InvalidInput, format!("All values up until maximum specified value ({max_key}) must be accounted for. Could not find specification for {i}.")));
}
}
Ok(graphemes)
}