use anyhow::{ensure, Context, Error, Result};
use json::JsonValue;
use std::collections::{HashMap, HashSet};
pub fn open_json_from_path(path: &str) -> Result<JsonValue> {
json::parse(&std::fs::read_to_string(path)?)
.with_context(|| format!("Could not parse JSON file at path {path}"))
}
pub fn json_to_set(json: &JsonValue) -> HashSet<String> {
let mut set = HashSet::<String>::new();
json.members().for_each(|x| {
set.insert(x.as_str().unwrap().to_owned());
});
set
}
pub fn json_to_map<'a>(json: &'a JsonValue) -> HashMap<String, &'a JsonValue> {
let mut map = HashMap::<String, &'a JsonValue>::new();
for (k, v) in json.entries() {
map.insert(k.to_owned(), v);
}
map
}
pub trait FromJson {
type Output;
fn parse(json: JsonValue) -> Result<Self::Output>;
}
impl FromJson for i32 {
type Output = i32;
fn parse(json: JsonValue) -> Result<i32> {
json.as_i32()
.with_context(|| format!("Could not parse {json} as i32"))
}
}
impl FromJson for i64 {
type Output = i64;
fn parse(json: JsonValue) -> Result<i64> {
json.as_i64()
.with_context(|| format!("Could not parse {json} as i64"))
}
}
impl FromJson for u32 {
type Output = u32;
fn parse(json: JsonValue) -> Result<u32> {
json.as_u32()
.with_context(|| format!("Could not parse {json} as u32"))
}
}
impl FromJson for u64 {
type Output = u64;
fn parse(json: JsonValue) -> Result<u64> {
json.as_u64()
.with_context(|| format!("Could not parse {json} as u64"))
}
}
impl FromJson for String {
type Output = String;
fn parse(json: JsonValue) -> Result<String> {
json.as_str()
.map(|s| s.to_owned())
.with_context(|| format!("Could not parse {json} as String"))
}
}
impl FromJson for bool {
type Output = bool;
fn parse(json: JsonValue) -> Result<bool> {
json.as_bool()
.with_context(|| format!("Could not parse {json} as bool"))
}
}
pub fn field_is_null(json: &JsonValue, key: &str) -> Result<bool> {
ensure!(!json.is_null(), "Cannot get field from null json");
ensure!(json.has_key(key), "Value {json} does not have {key} field");
Ok(json[key].is_null())
}
pub fn get_field<T: FromJson>(json: &JsonValue, key: &str) -> Result<T::Output, Error> {
ensure!(!json.is_null(), "Cannot get field from null json");
ensure!(json.has_key(key), "Value {json} does not have {key} field");
T::parse(json[key].clone())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_open_json_from_path() -> Result<()> {
ensure!(open_json_from_path("tests/data/keywords/fp_others.json").is_ok());
ensure!(open_json_from_path("tests/data/keywords/nonexistent.json").is_err());
ensure!(open_json_from_path("tests/data/small_file.csv").is_err());
Ok(())
}
#[test]
fn test_json_to_set() -> Result<()> {
let json = json::parse(r#"["a", "b", "c"]"#)?;
let set = json_to_set(&json);
assert_eq!(set.len(), 3);
ensure!(set.contains("a"));
ensure!(set.contains("b"));
ensure!(set.contains("c"));
Ok(())
}
}