use crate::{datetime, extension::TomlValueExt, Map, Uuid};
use std::{
net::{AddrParseError, IpAddr, Ipv4Addr, Ipv6Addr},
time::Duration,
};
use toml::value::{Array, Table};
use url::{self, Url};
pub trait TomlTableExt {
fn get_bool(&self, key: &str) -> Option<bool>;
fn get_u8(&self, key: &str) -> Option<u8>;
fn get_u16(&self, key: &str) -> Option<u16>;
fn get_u32(&self, key: &str) -> Option<u32>;
fn get_u64(&self, key: &str) -> Option<u64>;
fn get_usize(&self, key: &str) -> Option<usize>;
fn get_i8(&self, key: &str) -> Option<i8>;
fn get_i16(&self, key: &str) -> Option<i16>;
fn get_i32(&self, key: &str) -> Option<i32>;
fn get_i64(&self, key: &str) -> Option<i64>;
fn get_isize(&self, key: &str) -> Option<isize>;
fn get_f32(&self, key: &str) -> Option<f32>;
fn get_f64(&self, key: &str) -> Option<f64>;
fn get_str(&self, key: &str) -> Option<&str>;
fn get_array(&self, key: &str) -> Option<&Array>;
fn get_str_array(&self, key: &str) -> Option<Vec<&str>>;
fn get_table(&self, key: &str) -> Option<&Table>;
fn get_first_table(&self, key: &str) -> Option<&Table>;
fn get_last_table(&self, key: &str) -> Option<&Table>;
fn get_duration(&self, key: &str) -> Option<Duration>;
fn parse_uuid(&self, key: &str) -> Option<Result<Uuid, uuid::Error>>;
fn parse_url(&self, key: &str) -> Option<Result<Url, url::ParseError>>;
fn parse_ip(&self, key: &str) -> Option<Result<IpAddr, AddrParseError>>;
fn parse_ipv4(&self, key: &str) -> Option<Result<Ipv4Addr, AddrParseError>>;
fn parse_ipv6(&self, key: &str) -> Option<Result<Ipv6Addr, AddrParseError>>;
fn to_map(&self) -> Map;
}
impl TomlTableExt for Table {
#[inline]
fn get_bool(&self, key: &str) -> Option<bool> {
self.get(key).and_then(|v| v.as_bool())
}
#[inline]
fn get_u8(&self, key: &str) -> Option<u8> {
self.get(key)
.and_then(|v| v.as_integer())
.and_then(|i| u8::try_from(i).ok())
}
#[inline]
fn get_u16(&self, key: &str) -> Option<u16> {
self.get(key)
.and_then(|v| v.as_integer())
.and_then(|i| u16::try_from(i).ok())
}
#[inline]
fn get_u32(&self, key: &str) -> Option<u32> {
self.get(key)
.and_then(|v| v.as_integer())
.and_then(|i| u32::try_from(i).ok())
}
#[inline]
fn get_u64(&self, key: &str) -> Option<u64> {
self.get(key)
.and_then(|v| v.as_integer())
.and_then(|i| u64::try_from(i).ok())
}
#[inline]
fn get_usize(&self, key: &str) -> Option<usize> {
self.get(key)
.and_then(|v| v.as_integer())
.and_then(|i| usize::try_from(i).ok())
}
#[inline]
fn get_i8(&self, key: &str) -> Option<i8> {
self.get(key)
.and_then(|v| v.as_integer())
.and_then(|i| i8::try_from(i).ok())
}
#[inline]
fn get_i16(&self, key: &str) -> Option<i16> {
self.get(key)
.and_then(|v| v.as_integer())
.and_then(|i| i16::try_from(i).ok())
}
#[inline]
fn get_i32(&self, key: &str) -> Option<i32> {
self.get(key)
.and_then(|v| v.as_integer())
.and_then(|i| i32::try_from(i).ok())
}
#[inline]
fn get_i64(&self, key: &str) -> Option<i64> {
self.get(key).and_then(|v| v.as_integer())
}
#[inline]
fn get_isize(&self, key: &str) -> Option<isize> {
self.get(key)
.and_then(|v| v.as_integer())
.and_then(|i| isize::try_from(i).ok())
}
#[inline]
fn get_f32(&self, key: &str) -> Option<f32> {
self.get(key).and_then(|v| v.as_float()).map(|f| f as f32)
}
#[inline]
fn get_f64(&self, key: &str) -> Option<f64> {
self.get(key).and_then(|v| v.as_float())
}
#[inline]
fn get_str(&self, key: &str) -> Option<&str> {
self.get(key).and_then(|v| v.as_str())
}
#[inline]
fn get_array(&self, key: &str) -> Option<&Array> {
self.get(key).and_then(|v| v.as_array())
}
#[inline]
fn get_str_array(&self, key: &str) -> Option<Vec<&str>> {
self.get_array(key)
.map(|values| values.iter().filter_map(|v| v.as_str()).collect::<Vec<_>>())
}
#[inline]
fn get_table(&self, key: &str) -> Option<&Table> {
self.get(key).and_then(|v| v.as_table())
}
#[inline]
fn get_first_table(&self, key: &str) -> Option<&Table> {
self.get_array(key)?.first()?.as_table()
}
#[inline]
fn get_last_table(&self, key: &str) -> Option<&Table> {
self.get_array(key)?.last()?.as_table()
}
fn get_duration(&self, key: &str) -> Option<Duration> {
self.get_str(key)
.and_then(|s| datetime::parse_duration(s).ok())
}
fn parse_uuid(&self, key: &str) -> Option<Result<Uuid, uuid::Error>> {
self.get_str(key)
.map(|s| s.trim_start_matches("urn:uuid:"))
.filter(|s| !s.chars().all(|c| c == '0' || c == '-'))
.map(|s| s.parse())
}
#[inline]
fn parse_url(&self, key: &str) -> Option<Result<Url, url::ParseError>> {
self.get_str(key).map(|s| s.parse())
}
#[inline]
fn parse_ip(&self, key: &str) -> Option<Result<IpAddr, AddrParseError>> {
self.get_str(key).map(|s| s.parse())
}
#[inline]
fn parse_ipv4(&self, key: &str) -> Option<Result<Ipv4Addr, AddrParseError>> {
self.get_str(key).map(|s| s.parse())
}
#[inline]
fn parse_ipv6(&self, key: &str) -> Option<Result<Ipv6Addr, AddrParseError>> {
self.get_str(key).map(|s| s.parse())
}
fn to_map(&self) -> Map {
let mut map = Map::with_capacity(self.len());
for (key, value) in self.iter() {
map.insert(key.to_owned(), value.to_json_value());
}
map
}
}