#[cfg(not(target_arch = "wasm32"))]
use {
rayon::iter::{IntoParallelRefIterator, ParallelIterator},
std::{fs, str},
};
pub mod bytes;
use once_cell::sync::Lazy;
use regex::Regex;
use serde::Serialize;
use crate::Data;
use crate::DATA;
include!(concat!(env!("OUT_DIR"), "/regex_data.rs"));
#[derive(Serialize, Debug)]
pub struct Match {
pub text: String,
pub data: Data,
}
impl Match {
pub fn new(text: String, data: Data) -> Match {
Match { text, data }
}
}
pub struct Identifier {
pub min_rarity: f32,
pub max_rarity: f32,
pub tags: Vec<String>,
pub exclude_tags: Vec<String>,
pub boundaryless: bool,
pub file_support: bool,
}
impl Identifier {
#[inline]
pub fn min_rarity(mut self, rarity: f32) -> Self {
self.min_rarity = rarity;
self
}
#[inline]
pub fn max_rarity(mut self, rarity: f32) -> Self {
self.max_rarity = rarity;
self
}
#[inline]
pub fn include_tags(mut self, tags: &[String]) -> Self {
self.tags.extend_from_slice(tags);
self
}
#[inline]
pub fn exclude_tags(mut self, tags: &[String]) -> Self {
self.exclude_tags.extend_from_slice(tags);
self
}
#[inline]
pub fn boundaryless(mut self, boundaryless: bool) -> Self {
self.boundaryless = boundaryless;
self
}
#[inline]
pub fn file_support(mut self, support: bool) -> Self {
self.file_support = support;
self
}
}
impl Default for Identifier {
fn default() -> Self {
Identifier {
min_rarity: 0.0,
max_rarity: 1.0,
tags: vec![],
exclude_tags: vec![],
boundaryless: false,
file_support: false,
}
}
}
#[cfg(not(target_arch = "wasm32"))]
impl Identifier {
pub fn identify(&self, text: &str) -> Vec<Match> {
let regexes = if self.boundaryless {
&BOUNDARYLESS_REGEX
} else {
®EX
};
if self.file_support && is_file(text) {
let strings = read_file_to_strings(text);
strings
.par_iter()
.map(|text| {
DATA.iter()
.enumerate()
.filter_map(|(i, e)| {
if is_valid_filter(self, e) && regexes[i].is_match(text) {
Some(Match::new(text.to_owned(), e.clone()))
} else {
None
}
})
.collect::<Vec<Match>>()
})
.flatten()
.collect()
} else {
DATA.iter()
.enumerate()
.filter_map(|(i, e)| {
if is_valid_filter(self, e) && regexes[i].is_match(text) {
Some(Match::new(text.to_owned(), e.clone()))
} else {
None
}
})
.collect::<Vec<Match>>()
}
}
pub fn first_match(&self, text: &str) -> Option<Match> {
let regexes = if self.boundaryless {
&BOUNDARYLESS_REGEX
} else {
®EX
};
for (i, x) in DATA
.iter()
.enumerate()
.filter(|(_, x)| is_valid_filter(self, x))
{
if regexes[i].is_match(text) {
return Some(Match::new(text.to_owned(), x.clone()));
}
}
None
}
}
#[cfg(target_arch = "wasm32")]
impl Identifier {
pub fn identify(&self, text: &[String]) -> Vec<Match> {
let regexes = if self.boundaryless {
&BOUNDARYLESS_REGEX
} else {
®EX
};
DATA.iter()
.enumerate()
.filter_map(|(i, e)| {
if is_valid_filter(self, e) && regexes[i].is_match(text) {
Some(Match::new(text.to_owned(), e.clone()))
} else {
None
}
})
.collect::<Vec<Match>>()
}
}
impl Identifier {
#[inline]
pub fn to_json(result: &[Match]) -> String {
serde_json::to_string_pretty(result).unwrap_or_default()
}
}
#[cfg(not(target_arch = "wasm32"))]
fn is_file(name: &str) -> bool {
if let Ok(s) = fs::metadata(name) {
s.is_file()
} else {
false
}
}
fn is_valid_filter(configs: &Identifier, regex_data: &Data) -> bool {
if regex_data.rarity < configs.min_rarity {
return false;
}
if regex_data.rarity > configs.max_rarity {
return false;
}
if configs
.tags
.iter()
.any(|y| !regex_data.tags.iter().any(|x| x == y))
{
return false;
}
if configs
.exclude_tags
.iter()
.any(|y| regex_data.tags.iter().any(|x| x == y))
{
return false;
}
true
}
#[cfg(not(target_arch = "wasm32"))]
fn read_file_to_strings(filename: &str) -> Vec<String> {
let file = fs::read(filename).expect("File not found");
let mut printable_text: Vec<String> = Vec::new();
let mut buffer: Vec<u8> = Vec::new();
let mut use_current_buffer = false;
for character in file {
if character.is_ascii_graphic() {
use_current_buffer = true;
buffer.push(character);
} else if use_current_buffer {
if buffer.len() >= 4 {
printable_text.push(
String::from_utf8(buffer.clone()).expect("failed to convert u8 to string"),
);
}
buffer.clear();
use_current_buffer = false;
}
}
printable_text.push(String::from_utf8(buffer).expect("failed to convert u8 to string"));
printable_text
}