use std::fmt;
use std::path::{Path, PathBuf, Component};
use serde::de::{self, Unexpected, Deserializer};
pub fn diff_paths<P, B>(path: P, base: B) -> Option<PathBuf>
where P: AsRef<Path>, B: AsRef<Path>
{
let (path, base) = (path.as_ref(), base.as_ref());
if path.has_root() != base.has_root() {
return None;
}
let mut ita = path.components();
let mut itb = base.components();
let mut comps: Vec<Component> = vec![];
loop {
match (ita.next(), itb.next()) {
(None, None) => break,
(Some(a), None) => {
comps.push(a);
comps.extend(ita.by_ref());
break;
}
(None, _) => comps.push(Component::ParentDir),
(Some(a), Some(b)) if comps.is_empty() && a == b => (),
(Some(a), Some(b)) if b == Component::CurDir => comps.push(a),
(Some(_), Some(b)) if b == Component::ParentDir => return None,
(Some(a), Some(_)) => {
comps.push(Component::ParentDir);
for _ in itb {
comps.push(Component::ParentDir);
}
comps.push(a);
comps.extend(ita.by_ref());
break;
}
}
}
Some(comps.iter().map(|c| c.as_os_str()).collect())
}
pub fn bool_from_str_or_int<'de, D: Deserializer<'de>>(de: D) -> Result<bool, D::Error> {
struct Visitor;
impl<'de> de::Visitor<'de> for Visitor {
type Value = bool;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("a boolean")
}
fn visit_str<E: de::Error>(self, val: &str) -> Result<bool, E> {
match val {
v if uncased::eq(v, "true") => Ok(true),
v if uncased::eq(v, "false") => Ok(false),
s => Err(E::invalid_value(Unexpected::Str(s), &"true or false"))
}
}
fn visit_u64<E: de::Error>(self, n: u64) -> Result<bool, E> {
match n {
0 | 1 => Ok(n != 0),
n => Err(E::invalid_value(Unexpected::Unsigned(n), &"0 or 1"))
}
}
fn visit_i64<E: de::Error>(self, n: i64) -> Result<bool, E> {
match n {
0 | 1 => Ok(n != 0),
n => Err(E::invalid_value(Unexpected::Signed(n), &"0 or 1"))
}
}
fn visit_bool<E: de::Error>(self, b: bool) -> Result<bool, E> {
Ok(b)
}
}
de.deserialize_any(Visitor)
}
pub mod vec_tuple_map {
use std::fmt;
use serde::{de, Deserialize, Serialize, Deserializer, Serializer};
pub fn serialize<S, K, V>(vec: &[(K, V)], se: S) -> Result<S::Ok, S::Error>
where S: Serializer, K: Serialize, V: Serialize
{
se.collect_map(vec.iter().map(|(ref k, ref v)| (k, v)))
}
pub fn deserialize<'de, K, V, D>(de: D) -> Result<Vec<(K, V)>, D::Error>
where D: Deserializer<'de>, K: Deserialize<'de>, V: Deserialize<'de>
{
struct Visitor<K, V>(std::marker::PhantomData<Vec<(K, V)>>);
impl<'de, K, V> de::Visitor<'de> for Visitor<K, V>
where K: Deserialize<'de>, V: Deserialize<'de>,
{
type Value = Vec<(K, V)>;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("a map")
}
fn visit_map<A>(self, mut map: A) -> Result<Vec<(K, V)>, A::Error>
where A: de::MapAccess<'de>
{
let mut vec = Vec::with_capacity(map.size_hint().unwrap_or(0));
while let Some((k, v)) = map.next_entry()? {
vec.push((k, v));
}
Ok(vec)
}
}
de.deserialize_map(Visitor(std::marker::PhantomData))
}
}
use crate::value::{Value, Dict};
pub fn nest(key: &str, value: Value) -> Value {
fn value_from(mut keys: std::str::Split<'_, char>, value: Value) -> Value {
match keys.next() {
Some(k) if !k.is_empty() => {
let mut dict = Dict::new();
dict.insert(k.into(), value_from(keys, value));
dict.into()
}
Some(_) | None => value
}
}
value_from(key.split('.'), value)
}
#[doc(hidden)]
#[macro_export]
macro_rules! map {
($($key:expr => $value:expr),* $(,)?) => ({
let mut map = $crate::value::Map::new();
$(map.insert($key, $value);)*
map
});
}
pub use map;
#[doc(hidden)]
#[macro_export]
macro_rules! make_cloneable {
($Trait:path: $Cloneable:ident) => {
trait $Cloneable {
fn box_clone(&self) -> Box<dyn $Trait>;
}
impl std::clone::Clone for Box<dyn $Trait> {
fn clone(&self) -> Box<dyn $Trait> {
(&**self).box_clone()
}
}
impl std::fmt::Debug for Box<dyn $Trait> {
fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
Ok(())
}
}
impl<T: $Trait + Clone> $Cloneable for T {
fn box_clone(&self) -> Box<dyn $Trait> {
Box::new(self.clone())
}
}
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! cloneable_fn_trait {
($Name:ident: $($rest:tt)*) => {
trait $Name: $($rest)* + Cloneable + 'static { }
impl<F: Clone + 'static> $Name for F where F: $($rest)* { }
$crate::make_cloneable!($Name: Cloneable);
}
}
pub(crate) use cloneable_fn_trait;