use std::borrow::Cow;
use crate::value::Value;
pub trait AsKey: sealed::Sealed {
}
pub(crate) use sealed::KeyArg;
mod sealed {
use super::{Cow, Value};
#[derive(Clone, Debug)]
pub enum KeyArg<'a> {
Str(&'a str),
Value(Cow<'a, Value>),
}
pub trait Sealed {
fn key_arg(&self) -> KeyArg<'_>;
}
}
impl KeyArg<'_> {
pub(crate) fn to_value(&self) -> Value {
match self {
KeyArg::Str(s) => Value::from(*s),
KeyArg::Value(v) => v.as_ref().clone(),
}
}
pub(crate) fn as_str(&self) -> Option<&str> {
match self {
KeyArg::Str(s) => Some(s),
KeyArg::Value(v) => match v.as_ref() {
Value::String(s) => Some(s),
_ => None,
},
}
}
pub(crate) fn label(&self) -> String {
if let Some(s) = self.as_str() {
return s.to_owned();
}
match self {
KeyArg::Value(v) => match v.untag_ref() {
Value::Null => "null".to_owned(),
Value::Bool(b) => b.to_string(),
Value::Number(n) => n.to_string(),
Value::String(s) => s.clone(),
_ => "?".to_owned(),
},
KeyArg::Str(s) => (*s).to_owned(),
}
}
pub(crate) fn is_collection(&self) -> bool {
match self {
KeyArg::Str(_) => false,
KeyArg::Value(v) => matches!(v.untag_ref(), Value::Sequence(_) | Value::Mapping(_)),
}
}
}
impl AsKey for str {}
impl sealed::Sealed for str {
fn key_arg(&self) -> KeyArg<'_> {
KeyArg::Str(self)
}
}
impl AsKey for String {}
impl sealed::Sealed for String {
fn key_arg(&self) -> KeyArg<'_> {
KeyArg::Str(self)
}
}
impl AsKey for Value {}
impl sealed::Sealed for Value {
fn key_arg(&self) -> KeyArg<'_> {
KeyArg::Value(Cow::Borrowed(self))
}
}
impl AsKey for bool {}
impl sealed::Sealed for bool {
fn key_arg(&self) -> KeyArg<'_> {
KeyArg::Value(Cow::Owned(Value::Bool(*self)))
}
}
impl<T: AsKey + ?Sized> AsKey for &T {}
impl<T: sealed::Sealed + ?Sized> sealed::Sealed for &T {
fn key_arg(&self) -> KeyArg<'_> {
(**self).key_arg()
}
}
macro_rules! int_key {
($($t:ty),*) => {$(
impl AsKey for $t {}
impl sealed::Sealed for $t {
fn key_arg(&self) -> KeyArg<'_> {
KeyArg::Value(Cow::Owned(Value::from(*self)))
}
}
)*};
}
int_key!(
i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize
);
pub(crate) fn arg<K: AsKey + ?Sized>(k: &K) -> KeyArg<'_> {
sealed::Sealed::key_arg(k)
}