Migrate (#4)
Rust Build / Clippy (push) Successful in 33s
Rust Build / Check (push) Successful in 26s
Rust Build / Rustfmt (push) Successful in 32s
Rust Build / Test Suite (push) Successful in 47s
Rust Build / build (push) Successful in 30s

Reviewed-on: #4
This commit was merged in pull request #4.
This commit is contained in:
2026-06-06 12:48:58 -04:00
parent e7f6ddec9a
commit cd0ea8a387
6 changed files with 226 additions and 4 deletions
+31 -2
View File
@@ -1,3 +1,32 @@
fn main() {
println!("clean_file");
pub mod parser;
pub mod version;
#[tokio::main]
async fn main() {
let args: Vec<String> = std::env::args().collect();
if args.len() < 2 {
println!("Invalid arguments provided");
std::process::exit(-1);
}
if version::contains_version(&args) {
version::print_version();
std::process::exit(-1);
}
let filepath = &args[1];
println!("Filepath: {filepath:?}");
let prsr = parser::NumberParser {
filepath: filepath.clone(),
};
match prsr.file_dump().await {
Ok(contacts) => {
prsr.print_phone_numbers(&contacts);
prsr.save_file(contacts).await;
}
Err(err) => {
eprintln!("Error: {err:?}");
}
};
}
+168
View File
@@ -0,0 +1,168 @@
use std::io::BufRead;
const LETTERS: &str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
#[derive(Clone, Debug, Default)]
pub struct NumberParser {
pub filepath: String,
}
impl NumberParser {
pub async fn file_dump(
&self,
) -> Result<Vec<textsender_models::contact::Contact>, std::io::Error> {
println!("Dumping files");
let mut objs: Vec<textsender_models::contact::Contact> = Vec::new();
match self.read_lines(&self.filepath).await {
Ok(lines) => {
for line in lines {
let contains_letters = line.chars().any(|c| LETTERS.contains(c));
if contains_letters {
continue;
} else {
let my_obj = textsender_models::contact::Contact {
phone_number: line.clone(),
..Default::default()
};
if !my_obj.phone_number.is_empty() {
objs.push(my_obj);
}
}
}
let updated_contacts = self.update_contacts(&objs).await;
let removed_duplicates = self.remove_dups(&updated_contacts).await;
Ok(removed_duplicates)
}
Err(err) => Err(err),
}
}
pub async fn save_file(&self, numbers: Vec<textsender_models::contact::Contact>) {
let filename = String::from("numbers.json");
match serde_json::to_string(&numbers) {
Ok(json_string) => match std::fs::write(&filename, json_string) {
Ok(_) => {
println!("Saved to: {filename:?}");
}
Err(err) => {
eprintln!("Error: {err:?}");
}
},
Err(err) => {
eprintln!("Error: {err:?}");
}
};
}
pub fn print_phone_numbers(&self, contacts: &Vec<textsender_models::contact::Contact>) {
println!("Printing phone numbers");
for contact in contacts {
println!("Phone Number: {:?}", contact.phone_number);
}
println!("Total phone numbers: {:?}", contacts.len());
}
async fn read_lines(&self, filename: &String) -> Result<Vec<String>, std::io::Error> {
match std::fs::File::open(filename) {
Ok(file) => {
let reader = std::io::BufReader::new(file);
reader.lines().collect()
}
Err(err) => Err(err),
}
}
async fn remove_dups(
&self,
contacts: &Vec<textsender_models::contact::Contact>,
) -> Vec<textsender_models::contact::Contact> {
let mut unique_contacts: Vec<textsender_models::contact::Contact> = Vec::new();
let mut unique_items = std::collections::HashSet::new();
for val in contacts {
unique_items.insert(val.phone_number.clone());
}
for unique_item in unique_items {
let contact = textsender_models::contact::Contact {
phone_number: unique_item,
..Default::default()
};
unique_contacts.push(contact);
}
unique_contacts
}
async fn update_contacts(
&self,
contacts: &Vec<textsender_models::contact::Contact>,
) -> Vec<textsender_models::contact::Contact> {
let mut updated: Vec<textsender_models::contact::Contact> = Vec::new();
for ct in contacts {
let phone_number = ct.phone_number.clone();
if phone_number.len() < 2 {
println!("Invalid number: {phone_number:?}");
continue;
}
let pars = self.remove_some_data(&phone_number).await;
match self.add_prefix(&pars) {
Ok(updated_parsed) => {
let contact = textsender_models::contact::Contact {
phone_number: updated_parsed,
..Default::default()
};
updated.push(contact);
}
Err(err) => {
eprintln!("Error: {err:?}");
std::process::exit(-2);
}
};
}
updated
}
fn add_prefix(&self, raw: &String) -> Result<String, std::io::Error> {
if raw.is_empty() {
Err(std::io::Error::other("Empty"))
} else {
let mut parsed: String = String::new();
let first_char = raw.chars().nth(0).unwrap();
if first_char == '1' {
parsed = format!("+{raw}");
} else if first_char != '+' {
parsed = format!("+1{raw}");
}
Ok(parsed)
}
}
async fn remove_some_data(&self, unparsed: &str) -> String {
let mut parsed: String = String::new();
for ch in unparsed.chars() {
if ch == ' ' {
continue;
} else {
if ch.is_numeric() {
parsed.push(ch);
}
}
}
parsed
}
}
+20
View File
@@ -0,0 +1,20 @@
pub fn print_version() {
let name = env!("CARGO_PKG_NAME");
let version = env!("CARGO_PKG_VERSION");
println!("{name:?} {version:?}");
}
pub fn contains_version(args: &Vec<String>) -> bool {
let valid_flags = vec!["-v", "--version"];
for arg in args {
for valid_flag in &valid_flags {
if valid_flag == arg {
return true;
}
}
}
false
}