use std::collections::{HashMap, HashSet}; use std::fs::File; use std::io::{self, BufReader, Error, Read, Write}; use std::path::Path; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; use serde_json::{self, Deserializer, Value}; use crate::utils::file_utils::{file_reader, file_writer}; fn read_skipping_ws(mut reader: impl Read) -> io::Result { loop { let mut byte = 0u8; reader.read_exact(std::slice::from_mut(&mut byte))?; if !byte.is_ascii_whitespace() { return Ok(byte); } } } fn invalid_data(msg: &str) -> io::Error { io::Error::new(io::ErrorKind::InvalidData, msg) } fn deserialize_single(reader: R) -> io::Result { let next_obj = Deserializer::from_reader(reader).into_iter::().next(); next_obj.map_or_else( || Err(invalid_data("premature EOF")), |result| result.map_err(Into::into), ) } fn yield_next_obj( mut reader: R, at_start: &mut bool, ) -> io::Result> { if *at_start { match read_skipping_ws(&mut reader)? { b',' => deserialize_single(reader).map(Some), b']' => Ok(None), _ => Err(invalid_data("`,` or `]` not found")), } } else { *at_start = true; if read_skipping_ws(&mut reader)? == b'[' { // read the next char to see if the array is empty let peek = read_skipping_ws(&mut reader)?; if peek == b']' { Ok(None) } else { deserialize_single(io::Cursor::new([peek]).chain(reader)).map(Some) } } else { Err(invalid_data("`[` not found")) } } } // https://stackoverflow.com/questions/68641157/how-can-i-stream-elements-from-inside-a-json-array-using-serde-json pub fn json_iter_array( mut reader: R, ) -> impl Iterator> { let mut at_start = false; std::iter::from_fn(move || yield_next_obj(&mut reader, &mut at_start).transpose()) } pub fn json_filter_file(file_path: &Path, filter: &HashMap<&str, HashSet, S>) -> Vec { let mut filtered: Vec = Vec::with_capacity(1024); if !file_path.exists() { return filtered; // Return early if the file does not exist } let Ok(file) = File::open(file_path) else { return filtered; }; let reader = file_reader(file); for entry in json_iter_array::>(reader).flatten() { if let Some(item) = entry.as_object() { if filter.iter().all(|(&key, filter_set)| { item.get(key).is_some_and(|field_value| match field_value { Value::String(s) => filter_set.contains(s.as_str()), Value::Number(n) => filter_set.contains(n.as_str()), _ => false, }) }) { filtered.push(entry); } } } filtered } pub fn json_write_documents_to_file(file: &Path, value: &T) -> Result<(), Error> where T: ?Sized + Serialize, { let file = File::create(file)?; let mut writer = file_writer(&file); serde_json::to_writer(&mut writer, value)?; writer.flush() } pub fn string_or_number_u32<'de, D>(deserializer: D) -> Result where D: serde::Deserializer<'de>, { let value: Value = serde::Deserialize::deserialize(deserializer)?; match value { Value::Number(num) => { if let Some(v) = num.as_u64() { u32::try_from(v) .map_err(|_| serde::de::Error::custom("Number out of range for u32")) } else { Err(serde::de::Error::custom("Invalid number")) } } Value::String(s) => s .parse::() .map_err(|_| serde::de::Error::custom("Invalid string number")), _ => Err(serde::de::Error::custom("Expected number or string")), } } pub fn opt_string_or_number_u32<'de, D>(deserializer: D) -> Result, D::Error> where D: serde::Deserializer<'de>, { let value: Value = serde::Deserialize::deserialize(deserializer)?; match value { Value::Null => Ok(None), // Handle null explicitly Value::Number(num) => { if let Some(v) = num.as_u64() { u32::try_from(v) .map(Some) .map_err(|_| serde::de::Error::custom("Number out of range for u32")) } else { Err(serde::de::Error::custom("Invalid number")) } } Value::String(s) => s .parse::() .map(Some) .map_err(|_| serde::de::Error::custom("Invalid string number")), _ => Err(serde::de::Error::custom("Expected number, string, or null")), } } pub fn string_or_number_f64<'de, D>(deserializer: D) -> Result where D: serde::Deserializer<'de>, { let value: Value = serde::Deserialize::deserialize(deserializer)?; match value { Value::Number(num) => num .as_f64() .ok_or_else(|| serde::de::Error::custom("Invalid number")), Value::String(s) => s .parse::() .map_err(|_| serde::de::Error::custom("Invalid string number")), _ => Err(serde::de::Error::custom("Expected number or string")), } } pub fn get_u64_from_serde_value(value: &Value) -> Option { match value { Value::Number(num_val) => num_val.as_u64(), Value::String(str_val) => str_val.parse::().ok(), _ => None, } } pub fn get_u32_from_serde_value(value: &Value) -> Option { get_u64_from_serde_value(value).and_then(|val| u32::try_from(val).ok()) } pub fn get_string_from_serde_value(value: &Value) -> Option { match value { Value::Number(num_val) => num_val.as_i64().map(|num| num.to_string()), Value::String(str_val) => { if str_val.is_empty() { None } else { Some(str_val.clone()) } } _ => None, } } pub fn string_default_on_null<'de, D>(deserializer: D) -> Result where D: serde::Deserializer<'de>, { let value: Option = Option::deserialize(deserializer)?; Ok(value.unwrap_or_default()) }