use std::{
collections::HashSet,
fmt,
fs::{File, OpenOptions},
hash::Hash,
marker::PhantomData,
path::Path,
str::FromStr,
};
use heck::ToPascalCase;
use serde::{
de::{self, MapAccess, Visitor},
Deserialize, Deserializer,
};
use void::Void;
pub const PUBKEY_TOKEN: &str = "Pubkey";
pub fn primitive_or_pubkey_to_token(s: &str) -> String {
if s == "publicKey" {
PUBKEY_TOKEN.to_owned()
} else if s == "string" {
s.to_pascal_case()
} else {
s.to_owned()
}
}
pub fn open_file_create_overwrite<P: AsRef<Path>>(path: P) -> std::io::Result<File> {
OpenOptions::new()
.create(true)
.write(true)
.truncate(true)
.open(path)
}
pub fn string_or_struct<'de, T, D>(deserializer: D) -> Result<T, D::Error>
where
T: Deserialize<'de> + FromStr<Err = Void>,
D: Deserializer<'de>,
{
struct StringOrStruct<T>(PhantomData<fn() -> T>);
impl<'de, T> Visitor<'de> for StringOrStruct<T>
where
T: Deserialize<'de> + FromStr<Err = Void>,
{
type Value = T;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("string or map")
}
fn visit_str<E>(self, value: &str) -> Result<T, E>
where
E: de::Error,
{
Ok(FromStr::from_str(value).unwrap())
}
fn visit_map<M>(self, map: M) -> Result<T, M::Error>
where
M: MapAccess<'de>,
{
Deserialize::deserialize(de::value::MapAccessDeserializer::new(map))
}
}
deserializer.deserialize_any(StringOrStruct(PhantomData))
}
pub struct UniqueByReportDupsResult<'a, T> {
pub unique: Vec<&'a T>,
pub duplicates: Vec<&'a T>,
}
pub fn unique_by_report_dups<'a, I, T, V, F>(vals: I, mut f: F) -> UniqueByReportDupsResult<'a, T>
where
I: Iterator<Item = &'a T>,
V: Eq + Hash,
F: FnMut(&T) -> V,
{
let mut hashes = HashSet::new();
let mut unique = Vec::new();
let mut duplicates = Vec::new();
for val in vals {
let hash = f(val);
if hashes.contains(&hash) {
duplicates.push(val);
} else {
hashes.insert(hash);
unique.push(val);
}
}
UniqueByReportDupsResult { unique, duplicates }
}