mod cmd;
pub use cmd::split_with_quotes;
#[cfg(feature = "graphql")]
use async_graphql::{InputValueError, InputValueResult, Name, ScalarType, Value};
use hmac_sha256::HMAC;
use serde::{Deserialize, Serialize};
use std::collections::{BTreeMap, HashMap};
use std::fmt::{Debug, Display, Formatter};
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
#[derive(Serialize, Deserialize, Clone, Default, PartialEq, Eq)]
pub struct MultiLanguageItem(pub BTreeMap<String, String>);
impl Display for MultiLanguageItem {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let english_name = self.0.get("en").unwrap_or_else(|| {
self.0
.iter()
.find(|(key, _)| key.starts_with("en"))
.map_or_else(
|| self.0.iter().next().map(|(_, value)| value).unwrap(),
|(_, value)| value,
)
});
f.write_str(english_name)
}
}
impl Debug for MultiLanguageItem {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
impl IntoIterator for MultiLanguageItem {
type Item = (String, String);
type IntoIter = std::collections::btree_map::IntoIter<String, String>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl MultiLanguageItem {
#[must_use]
pub fn from_string(default: String) -> Self {
Self(BTreeMap::from([("en".to_string(), default)]))
}
#[must_use]
pub fn from_hashmap(map: HashMap<String, String>) -> Self {
Self(map.into_iter().collect())
}
}
#[cfg(feature = "graphql")]
#[async_graphql::Scalar]
impl ScalarType for MultiLanguageItem {
fn parse(value: Value) -> InputValueResult<Self> {
if let Value::String(value) = value {
Ok(Self(BTreeMap::from([("en".to_string(), value)])))
} else if let Value::Object(value) = value {
let mut map = BTreeMap::new();
for (k, v) in value {
if let Value::String(v) = v {
map.insert(k.as_str().to_string(), v);
} else {
return Err(InputValueError::expected_type(v.clone()));
}
}
Ok(Self(map))
} else {
Err(InputValueError::expected_type(value))
}
}
fn to_value(&self) -> Value {
Value::Object(
self.0
.clone()
.into_iter()
.map(|(k, v)| (Name::new(k), Value::String(v)))
.collect(),
)
}
}
#[must_use]
pub fn derive_entropy(identifier: &str, n5i_seed: &str) -> String {
let mut hasher = HMAC::new(n5i_seed);
hasher.update(identifier.as_bytes());
let result = hasher.finalize();
hex::encode(result)
}
#[macro_export]
macro_rules! for_each_type {
($func:ident, $($type:ty),*) => {
$(
$func::<$type>();
)*
};
($func:ident, $($type:ty),*; $call:tt) => {
$(
$func::<$type>$call;
)*
};
}
#[macro_export]
macro_rules! for_each_type_parallel {
($func:ident, $($type:ty),*) => {
tokio::join!(
$(
$func::<$type>()
),*
).await;
};
($func:ident, $($type:ty),*; $call:tt) => {
tokio::join!(
$(
$func::<$type>$call
),*
).await;
};
}
#[macro_export]
macro_rules! for_each_type_parallel_result {
($func:ident, $($type:ty),*) => {
tokio::try_join!(
$(
$func::<$type>()
),*
)
};
($func:ident, $($type:ty),*; $call:tt) => {
tokio::try_join!(
$(
async { $func::<$type>$call.await }
),*
)
};
}
#[must_use]
pub const fn is_ip_private(ip: IpAddr) -> bool {
match ip {
IpAddr::V4(ip) => {
ip.octets()[0] == 0 || ip.is_private()
|| is_shared_4(ip)
|| ip.is_loopback()
|| ip.is_link_local()
|| (
ip.octets()[0] == 192 && ip.octets()[1] == 0 && ip.octets()[2] == 0
&& ip.octets()[3] != 9 && ip.octets()[3] != 10
)
|| ip.is_documentation()
|| is_benchmarking_4(ip)
|| is_reserved_4(ip)
|| ip.is_broadcast()
}
IpAddr::V6(ip) => {
ip.is_unspecified()
|| ip.is_loopback()
|| matches!(ip.segments(), [0, 0, 0, 0, 0, 0xffff, _, _])
|| matches!(ip.segments(), [0x64, 0xff9b, 1, _, _, _, _, _])
|| matches!(ip.segments(), [0x100, 0, 0, 0, _, _, _, _])
|| (matches!(ip.segments(), [0x2001, b, _, _, _, _, _, _] if b < 0x200)
&& !(
u128::from_be_bytes(ip.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0001
|| u128::from_be_bytes(ip.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0002
|| matches!(ip.segments(), [0x2001, 3, _, _, _, _, _, _])
|| matches!(ip.segments(), [0x2001, 4, 0x112, _, _, _, _, _])
|| matches!(ip.segments(), [0x2001, b, _, _, _, _, _, _] if b >= 0x20 && b <= 0x3F)
))
|| matches!(ip.segments(), [0x2002, _, _, _, _, _, _, _])
|| is_documentation_6(&ip)
|| is_unique_local_6(&ip)
|| is_unicast_link_local_6(&ip)
}
}
}
const fn is_reserved_4(ip: Ipv4Addr) -> bool {
ip.octets()[0] & 240 == 240 && !ip.is_broadcast()
}
const fn is_benchmarking_4(ip: Ipv4Addr) -> bool {
ip.octets()[0] == 198 && (ip.octets()[1] & 0xfe) == 18
}
const fn is_shared_4(ip: Ipv4Addr) -> bool {
ip.octets()[0] == 100 && (ip.octets()[1] & 0b1100_0000 == 0b0100_0000)
}
const fn is_documentation_6(ip: &Ipv6Addr) -> bool {
ip.segments()[0] == 0x2001 && ip.segments()[1] == 0xdb8
}
const fn is_unique_local_6(ip: &Ipv6Addr) -> bool {
(ip.segments()[0] & 0xfe00) == 0xfc00
}
const fn is_unicast_link_local_6(ip: &Ipv6Addr) -> bool {
(ip.segments()[0] & 0xffc0) == 0xfe80
}
#[inline]
#[must_use]
pub const fn is_false(v: &bool) -> bool {
!*v
}
#[inline]
#[must_use]
pub const fn true_default() -> bool {
true
}