use crate::prelude::*;
use core::cmp::Ordering;
use core::hash::{Hash, Hasher};
use core::ops::{Index, IndexMut};
use core::str::FromStr;
use indexmap::map::{IntoIter, Iter, IterMut, Keys, Values, ValuesMut};
use indexmap::IndexMap;
use rustc_hash::FxBuildHasher;
use serde::{Deserialize, Serialize};
type FxIndexMap<K, V> = IndexMap<K, V, FxBuildHasher>;
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct Mapping(FxIndexMap<String, Value>);
impl Mapping {
#[must_use]
pub fn new() -> Self {
Self(FxIndexMap::default())
}
#[must_use]
pub fn with_capacity(capacity: usize) -> Self {
Self(FxIndexMap::with_capacity_and_hasher(
capacity,
FxBuildHasher,
))
}
#[must_use]
pub fn capacity(&self) -> usize {
self.0.capacity()
}
pub fn reserve(&mut self, additional: usize) {
self.0.reserve(additional);
}
pub fn shrink_to_fit(&mut self) {
self.0.shrink_to_fit();
}
#[must_use]
pub fn len(&self) -> usize {
self.0.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn clear(&mut self) {
self.0.clear();
}
pub fn insert(&mut self, key: impl Into<String>, value: Value) -> Option<Value> {
self.0.insert(key.into(), value)
}
#[must_use]
pub fn contains_key(&self, key: &str) -> bool {
self.0.contains_key(key)
}
#[must_use]
pub fn get(&self, key: &str) -> Option<&Value> {
self.0.get(key)
}
#[must_use]
pub fn get_mut(&mut self, key: &str) -> Option<&mut Value> {
self.0.get_mut(key)
}
#[must_use]
pub fn get_index(&self, index: usize) -> Option<(&String, &Value)> {
self.0.get_index(index)
}
#[must_use]
pub fn get_index_mut(&mut self, index: usize) -> Option<(&String, &mut Value)> {
self.0.get_index_mut(index)
}
pub fn remove(&mut self, key: &str) -> Option<Value> {
self.0.shift_remove(key)
}
pub fn remove_entry(&mut self, key: &str) -> Option<(String, Value)> {
self.0.shift_remove_entry(key)
}
pub fn swap_remove(&mut self, key: &str) -> Option<Value> {
self.0.swap_remove(key)
}
pub fn shift_remove(&mut self, key: &str) -> Option<Value> {
self.0.shift_remove(key)
}
pub fn entry(&mut self, key: impl Into<String>) -> indexmap::map::Entry<'_, String, Value> {
self.0.entry(key.into())
}
pub fn retain<F>(&mut self, f: F)
where
F: FnMut(&String, &mut Value) -> bool,
{
self.0.retain(f);
}
#[must_use]
pub fn iter(&self) -> Iter<'_, String, Value> {
self.0.iter()
}
pub fn iter_mut(&mut self) -> IterMut<'_, String, Value> {
self.0.iter_mut()
}
#[must_use]
pub fn keys(&self) -> Keys<'_, String, Value> {
self.0.keys()
}
#[must_use]
pub fn values(&self) -> Values<'_, String, Value> {
self.0.values()
}
pub fn values_mut(&mut self) -> ValuesMut<'_, String, Value> {
self.0.values_mut()
}
#[must_use]
pub fn first(&self) -> Option<(&String, &Value)> {
self.0.first()
}
#[must_use]
pub fn first_mut(&mut self) -> Option<(&String, &mut Value)> {
self.0.first_mut()
}
#[must_use]
pub fn last(&self) -> Option<(&String, &Value)> {
self.0.last()
}
#[must_use]
pub fn last_mut(&mut self) -> Option<(&String, &mut Value)> {
self.0.last_mut()
}
pub fn pop_first(&mut self) -> Option<(String, Value)> {
self.0.shift_remove_index(0)
}
pub fn pop_last(&mut self) -> Option<(String, Value)> {
self.0.pop()
}
pub fn sort_keys(&mut self) {
self.0.sort_keys();
}
pub fn reverse(&mut self) {
self.0.reverse();
}
pub fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = (String, Value)>,
{
self.0.extend(iter);
}
#[must_use]
pub fn into_inner(self) -> IndexMap<String, Value> {
self.0.into_iter().collect()
}
#[must_use]
pub fn from_inner(map: IndexMap<String, Value>) -> Self {
Self(map.into_iter().collect())
}
}
impl Index<&str> for Mapping {
type Output = Value;
#[track_caller]
fn index(&self, key: &str) -> &Self::Output {
self.0.get(key).expect("key not found in mapping")
}
}
impl IndexMut<&str> for Mapping {
#[track_caller]
fn index_mut(&mut self, key: &str) -> &mut Self::Output {
self.0.get_mut(key).expect("key not found in mapping")
}
}
impl IntoIterator for Mapping {
type Item = (String, Value);
type IntoIter = IntoIter<String, Value>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<'a> IntoIterator for &'a Mapping {
type Item = (&'a String, &'a Value);
type IntoIter = Iter<'a, String, Value>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
impl<'a> IntoIterator for &'a mut Mapping {
type Item = (&'a String, &'a mut Value);
type IntoIter = IterMut<'a, String, Value>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter_mut()
}
}
impl FromIterator<(String, Value)> for Mapping {
fn from_iter<I: IntoIterator<Item = (String, Value)>>(iter: I) -> Self {
Self(FxIndexMap::from_iter(iter))
}
}
impl<const N: usize> From<[(String, Value); N]> for Mapping {
fn from(arr: [(String, Value); N]) -> Self {
let mut map = FxIndexMap::with_capacity_and_hasher(N, FxBuildHasher);
for (k, v) in arr {
let _ = map.insert(k, v);
}
Self(map)
}
}
impl From<IndexMap<String, Value>> for Mapping {
fn from(map: IndexMap<String, Value>) -> Self {
Self(map.into_iter().collect())
}
}
impl From<FxIndexMap<String, Value>> for Mapping {
fn from(map: FxIndexMap<String, Value>) -> Self {
Self(map)
}
}
impl From<Mapping> for IndexMap<String, Value> {
fn from(map: Mapping) -> Self {
map.0.into_iter().collect()
}
}
impl From<Mapping> for FxIndexMap<String, Value> {
fn from(map: Mapping) -> Self {
map.0
}
}
impl From<Vec<(String, Value)>> for Mapping {
fn from(v: Vec<(String, Value)>) -> Self {
Self(v.into_iter().collect())
}
}
impl Hash for Mapping {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.len().hash(state);
for (k, v) in &self.0 {
k.hash(state);
v.hash(state);
}
}
}
impl PartialOrd for Mapping {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Mapping {
fn cmp(&self, other: &Self) -> Ordering {
self.len().cmp(&other.len()).then_with(|| {
for ((ak, av), (bk, bv)) in self.iter().zip(other.iter()) {
match ak.cmp(bk) {
Ordering::Equal => {}
ord => return ord,
}
match av.cmp(bv) {
Ordering::Equal => continue,
ord => return ord,
}
}
Ordering::Equal
})
}
}
impl fmt::Display for Mapping {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{{")?;
for (i, (k, v)) in self.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{k}: {v}")?;
}
write!(f, "}}")
}
}
impl Serialize for Mapping {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
use serde::ser::SerializeMap;
let mut map = serializer.serialize_map(Some(self.len()))?;
for (k, v) in self {
map.serialize_entry(k, v)?;
}
map.end()
}
}
impl<'de> Deserialize<'de> for Mapping {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde::de::{MapAccess, Visitor};
struct MappingVisitor;
impl<'de> Visitor<'de> for MappingVisitor {
type Value = Mapping;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("a YAML mapping")
}
fn visit_map<A>(self, mut map: A) -> Result<Mapping, A::Error>
where
A: MapAccess<'de>,
{
let mut mapping = Mapping::with_capacity(map.size_hint().unwrap_or(0));
while let Some((key, value)) = map.next_entry::<String, Value>()? {
let _ = mapping.insert(key, value);
}
Ok(mapping)
}
}
deserializer.deserialize_map(MappingVisitor)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct MappingAny(FxIndexMap<Value, Value>);
impl MappingAny {
#[must_use]
pub fn new() -> Self {
Self(FxIndexMap::default())
}
#[must_use]
pub fn with_capacity(capacity: usize) -> Self {
Self(FxIndexMap::with_capacity_and_hasher(
capacity,
FxBuildHasher,
))
}
#[must_use]
pub fn capacity(&self) -> usize {
self.0.capacity()
}
pub fn reserve(&mut self, additional: usize) {
self.0.reserve(additional);
}
pub fn shrink_to_fit(&mut self) {
self.0.shrink_to_fit();
}
#[must_use]
pub fn len(&self) -> usize {
self.0.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn clear(&mut self) {
self.0.clear();
}
pub fn insert(&mut self, key: Value, value: Value) -> Option<Value> {
self.0.insert(key, value)
}
#[must_use]
pub fn contains_key(&self, key: &Value) -> bool {
self.0.contains_key(key)
}
#[must_use]
pub fn get(&self, key: &Value) -> Option<&Value> {
self.0.get(key)
}
#[must_use]
pub fn get_mut(&mut self, key: &Value) -> Option<&mut Value> {
self.0.get_mut(key)
}
#[must_use]
pub fn get_index(&self, index: usize) -> Option<(&Value, &Value)> {
self.0.get_index(index)
}
#[must_use]
pub fn get_index_mut(&mut self, index: usize) -> Option<(&Value, &mut Value)> {
self.0.get_index_mut(index)
}
pub fn remove(&mut self, key: &Value) -> Option<Value> {
self.0.shift_remove(key)
}
pub fn remove_entry(&mut self, key: &Value) -> Option<(Value, Value)> {
self.0.shift_remove_entry(key)
}
pub fn swap_remove(&mut self, key: &Value) -> Option<Value> {
self.0.swap_remove(key)
}
pub fn shift_remove(&mut self, key: &Value) -> Option<Value> {
self.0.shift_remove(key)
}
pub fn entry(&mut self, key: Value) -> indexmap::map::Entry<'_, Value, Value> {
self.0.entry(key)
}
pub fn retain<F>(&mut self, f: F)
where
F: FnMut(&Value, &mut Value) -> bool,
{
self.0.retain(f);
}
#[must_use]
pub fn iter(&self) -> Iter<'_, Value, Value> {
self.0.iter()
}
pub fn iter_mut(&mut self) -> IterMut<'_, Value, Value> {
self.0.iter_mut()
}
#[must_use]
pub fn keys(&self) -> Keys<'_, Value, Value> {
self.0.keys()
}
#[must_use]
pub fn values(&self) -> Values<'_, Value, Value> {
self.0.values()
}
pub fn values_mut(&mut self) -> ValuesMut<'_, Value, Value> {
self.0.values_mut()
}
#[must_use]
pub fn first(&self) -> Option<(&Value, &Value)> {
self.0.first()
}
#[must_use]
pub fn first_mut(&mut self) -> Option<(&Value, &mut Value)> {
self.0.first_mut()
}
#[must_use]
pub fn last(&self) -> Option<(&Value, &Value)> {
self.0.last()
}
#[must_use]
pub fn last_mut(&mut self) -> Option<(&Value, &mut Value)> {
self.0.last_mut()
}
pub fn pop_first(&mut self) -> Option<(Value, Value)> {
self.0.shift_remove_index(0)
}
pub fn pop_last(&mut self) -> Option<(Value, Value)> {
self.0.pop()
}
pub fn sort_keys(&mut self) {
self.0.sort_keys();
}
pub fn reverse(&mut self) {
self.0.reverse();
}
pub fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = (Value, Value)>,
{
self.0.extend(iter);
}
#[must_use]
pub fn into_inner(self) -> IndexMap<Value, Value> {
self.0.into_iter().collect()
}
#[must_use]
pub fn from_inner(map: IndexMap<Value, Value>) -> Self {
Self(map.into_iter().collect())
}
#[must_use]
pub fn into_mapping(self) -> Option<Mapping> {
let mut mapping = Mapping::with_capacity(self.len());
for (k, v) in self.0 {
if let Value::String(s) = k {
let _ = mapping.insert(s, v);
} else {
return None;
}
}
Some(mapping)
}
}
impl Index<&Value> for MappingAny {
type Output = Value;
#[track_caller]
fn index(&self, key: &Value) -> &Self::Output {
self.0.get(key).expect("key not found in mapping")
}
}
impl IndexMut<&Value> for MappingAny {
#[track_caller]
fn index_mut(&mut self, key: &Value) -> &mut Self::Output {
self.0.get_mut(key).expect("key not found in mapping")
}
}
impl IntoIterator for MappingAny {
type Item = (Value, Value);
type IntoIter = IntoIter<Value, Value>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<'a> IntoIterator for &'a MappingAny {
type Item = (&'a Value, &'a Value);
type IntoIter = Iter<'a, Value, Value>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
impl<'a> IntoIterator for &'a mut MappingAny {
type Item = (&'a Value, &'a mut Value);
type IntoIter = IterMut<'a, Value, Value>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter_mut()
}
}
impl FromIterator<(Value, Value)> for MappingAny {
fn from_iter<I: IntoIterator<Item = (Value, Value)>>(iter: I) -> Self {
Self(IndexMap::from_iter(iter))
}
}
impl<const N: usize> From<[(Value, Value); N]> for MappingAny {
fn from(arr: [(Value, Value); N]) -> Self {
let mut map = FxIndexMap::with_capacity_and_hasher(N, FxBuildHasher);
for (k, v) in arr {
let _ = map.insert(k, v);
}
Self(map)
}
}
impl From<IndexMap<Value, Value>> for MappingAny {
fn from(map: IndexMap<Value, Value>) -> Self {
Self(map.into_iter().collect())
}
}
impl From<FxIndexMap<Value, Value>> for MappingAny {
fn from(map: FxIndexMap<Value, Value>) -> Self {
Self(map)
}
}
impl From<MappingAny> for IndexMap<Value, Value> {
fn from(map: MappingAny) -> Self {
map.0.into_iter().collect()
}
}
impl From<MappingAny> for FxIndexMap<Value, Value> {
fn from(map: MappingAny) -> Self {
map.0
}
}
impl From<Mapping> for MappingAny {
fn from(map: Mapping) -> Self {
let mut any = MappingAny::with_capacity(map.len());
for (k, v) in map {
let _ = any.insert(Value::String(k), v);
}
any
}
}
impl Hash for MappingAny {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.len().hash(state);
for (k, v) in &self.0 {
k.hash(state);
v.hash(state);
}
}
}
impl PartialOrd for MappingAny {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for MappingAny {
fn cmp(&self, other: &Self) -> Ordering {
self.len().cmp(&other.len()).then_with(|| {
for ((ak, av), (bk, bv)) in self.iter().zip(other.iter()) {
match ak.cmp(bk) {
Ordering::Equal => {}
ord => return ord,
}
match av.cmp(bv) {
Ordering::Equal => continue,
ord => return ord,
}
}
Ordering::Equal
})
}
}
impl fmt::Display for MappingAny {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{{")?;
for (i, (k, v)) in self.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{k}: {v}")?;
}
write!(f, "}}")
}
}
impl Serialize for MappingAny {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
use serde::ser::SerializeMap;
let mut map = serializer.serialize_map(Some(self.len()))?;
for (k, v) in self {
map.serialize_entry(k, v)?;
}
map.end()
}
}
impl<'de> Deserialize<'de> for MappingAny {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde::de::{MapAccess, Visitor};
struct MappingAnyVisitor;
impl<'de> Visitor<'de> for MappingAnyVisitor {
type Value = MappingAny;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("a YAML mapping")
}
fn visit_map<A>(self, mut map: A) -> Result<MappingAny, A::Error>
where
A: MapAccess<'de>,
{
let mut mapping = MappingAny::with_capacity(map.size_hint().unwrap_or(0));
while let Some((key, value)) = map.next_entry::<Value, Value>()? {
let _ = mapping.insert(key, value);
}
Ok(mapping)
}
}
deserializer.deserialize_map(MappingAnyVisitor)
}
}
pub type Sequence = Vec<Value>;
#[derive(Debug, Clone, Copy)]
pub enum Number {
Integer(i64),
Float(f64),
}
impl Number {
#[must_use]
pub fn as_i64(&self) -> Option<i64> {
match self {
Number::Integer(n) => Some(*n),
Number::Float(_) => None,
}
}
#[must_use]
pub fn as_u64(&self) -> Option<u64> {
match self {
Number::Integer(n) if *n >= 0 => Some(*n as u64),
_ => None,
}
}
#[must_use]
pub fn as_f64(&self) -> f64 {
match self {
Number::Integer(n) => *n as f64,
Number::Float(n) => *n,
}
}
#[must_use]
pub fn is_integer(&self) -> bool {
matches!(self, Number::Integer(_))
}
#[must_use]
pub fn is_float(&self) -> bool {
matches!(self, Number::Float(_))
}
#[must_use]
pub fn is_i64(&self) -> bool {
matches!(self, Number::Integer(_))
}
#[must_use]
pub fn is_u64(&self) -> bool {
matches!(self, Number::Integer(n) if *n >= 0)
}
#[must_use]
pub fn is_f64(&self) -> bool {
true
}
#[must_use]
pub fn is_nan(&self) -> bool {
match self {
Number::Float(n) => n.is_nan(),
Number::Integer(_) => false,
}
}
#[must_use]
pub fn is_infinite(&self) -> bool {
match self {
Number::Float(n) => n.is_infinite(),
Number::Integer(_) => false,
}
}
#[must_use]
pub fn is_finite(&self) -> bool {
match self {
Number::Float(n) => n.is_finite(),
Number::Integer(_) => true,
}
}
}
impl fmt::Display for Number {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Number::Integer(n) => write!(f, "{n}"),
Number::Float(n) => write!(f, "{n}"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ParseNumberError {
_private: (),
}
impl fmt::Display for ParseNumberError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "invalid number")
}
}
#[cfg(feature = "std")]
impl std::error::Error for ParseNumberError {}
impl FromStr for Number {
type Err = ParseNumberError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = s.trim();
match s {
".nan" | ".NaN" | ".NAN" => return Ok(Number::Float(f64::NAN)),
".inf" | ".Inf" | ".INF" => return Ok(Number::Float(f64::INFINITY)),
"+.inf" | "+.Inf" | "+.INF" => return Ok(Number::Float(f64::INFINITY)),
"-.inf" | "-.Inf" | "-.INF" => return Ok(Number::Float(f64::NEG_INFINITY)),
_ => {}
}
if let Ok(n) = s.parse::<i64>() {
return Ok(Number::Integer(n));
}
if s.len() > 2 {
let (prefix, rest) = s.split_at(2);
match prefix {
"0x" | "0X" => {
if let Ok(n) = i64::from_str_radix(rest, 16) {
return Ok(Number::Integer(n));
}
}
"0o" | "0O" => {
if let Ok(n) = i64::from_str_radix(rest, 8) {
return Ok(Number::Integer(n));
}
}
"0b" | "0B" => {
if let Ok(n) = i64::from_str_radix(rest, 2) {
return Ok(Number::Integer(n));
}
}
_ => {}
}
}
if let Ok(n) = s.parse::<f64>() {
return Ok(Number::Float(n));
}
Err(ParseNumberError { _private: () })
}
}
impl PartialEq for Number {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Number::Integer(a), Number::Integer(b)) => a == b,
(Number::Float(a), Number::Float(b)) => {
(a.is_nan() && b.is_nan()) || a == b
}
_ => false,
}
}
}
impl Eq for Number {}
impl Hash for Number {
fn hash<H: Hasher>(&self, state: &mut H) {
match self {
Number::Integer(n) => {
0u8.hash(state);
n.hash(state);
}
Number::Float(n) => {
1u8.hash(state);
let bits = if n.is_nan() {
0x7FF8_0000_0000_0001
} else if *n == 0.0 {
0
} else {
n.to_bits()
};
bits.hash(state);
}
}
}
}
impl PartialOrd for Number {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Number {
fn cmp(&self, other: &Self) -> Ordering {
match (self, other) {
(Number::Integer(a), Number::Integer(b)) => a.cmp(b),
(Number::Float(a), Number::Float(b)) => {
match (a.is_nan(), b.is_nan()) {
(true, true) => Ordering::Equal,
(true, false) => Ordering::Greater,
(false, true) => Ordering::Less,
(false, false) => a.partial_cmp(b).unwrap_or(Ordering::Equal),
}
}
(Number::Integer(a), Number::Float(b)) => {
if b.is_nan() {
Ordering::Less
} else if *a > (1_i64 << 53) || *a < -(1_i64 << 53) {
let a_f = *a as f64;
if (a_f as i64) == *a {
a_f.partial_cmp(b).unwrap_or(Ordering::Equal)
} else {
if *a > 0 {
if *b < (1_i64 << 53) as f64 {
Ordering::Greater
} else {
(*a as f64).partial_cmp(b).unwrap_or(Ordering::Equal)
}
} else if *b > -(1_i64 << 53) as f64 {
Ordering::Less
} else {
(*a as f64).partial_cmp(b).unwrap_or(Ordering::Equal)
}
}
} else {
(*a as f64).partial_cmp(b).unwrap_or(Ordering::Equal)
}
}
(Number::Float(a), Number::Integer(b)) => {
match Number::Integer(*b).cmp(&Number::Float(*a)) {
Ordering::Less => Ordering::Greater,
Ordering::Greater => Ordering::Less,
Ordering::Equal => Ordering::Equal,
}
}
}
}
}
impl From<i8> for Number {
fn from(v: i8) -> Self {
Number::Integer(i64::from(v))
}
}
impl From<i16> for Number {
fn from(v: i16) -> Self {
Number::Integer(i64::from(v))
}
}
impl From<i32> for Number {
fn from(v: i32) -> Self {
Number::Integer(i64::from(v))
}
}
impl From<i64> for Number {
fn from(v: i64) -> Self {
Number::Integer(v)
}
}
impl From<isize> for Number {
fn from(v: isize) -> Self {
Number::Integer(v as i64)
}
}
impl From<u8> for Number {
fn from(v: u8) -> Self {
Number::Integer(i64::from(v))
}
}
impl From<u16> for Number {
fn from(v: u16) -> Self {
Number::Integer(i64::from(v))
}
}
impl From<u32> for Number {
fn from(v: u32) -> Self {
Number::Integer(i64::from(v))
}
}
impl From<u64> for Number {
fn from(v: u64) -> Self {
if v <= i64::MAX as u64 {
Number::Integer(v as i64)
} else {
Number::Float(v as f64)
}
}
}
impl From<usize> for Number {
fn from(v: usize) -> Self {
Number::from(v as u64)
}
}
impl From<f32> for Number {
fn from(v: f32) -> Self {
Number::Float(f64::from(v))
}
}
impl From<f64> for Number {
fn from(v: f64) -> Self {
Number::Float(v)
}
}
#[must_use]
pub fn nobang(s: &str) -> &str {
s.strip_prefix('!').unwrap_or(s)
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MaybeTag<T> {
Tag(String),
NotTag(T),
}
pub fn check_for_tag<T: fmt::Display>(value: &T) -> MaybeTag<String> {
let s = value.to_string();
if s.starts_with('!') {
MaybeTag::Tag(s)
} else {
MaybeTag::NotTag(s)
}
}
pub(crate) const TAGGED_VALUE_FIELD_TAG: &str = "$__noyalib_tag";
pub(crate) const TAGGED_VALUE_FIELD_VALUE: &str = "$__noyalib_value";
#[derive(Debug, Clone)]
pub struct Tag(String);
impl Tag {
#[must_use]
pub fn new(tag: impl Into<String>) -> Self {
Self(tag.into())
}
#[must_use]
pub fn as_str(&self) -> &str {
&self.0
}
#[must_use]
pub fn into_string(self) -> String {
self.0
}
#[must_use]
pub fn nobang(&self) -> &str {
nobang(&self.0)
}
}
impl fmt::Display for Tag {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl From<&str> for Tag {
fn from(s: &str) -> Self {
Self::new(s)
}
}
impl From<String> for Tag {
fn from(s: String) -> Self {
Self(s)
}
}
impl AsRef<str> for Tag {
fn as_ref(&self) -> &str {
&self.0
}
}
impl PartialEq for Tag {
fn eq(&self, other: &Self) -> bool {
nobang(&self.0) == nobang(&other.0)
}
}
impl Eq for Tag {}
impl Hash for Tag {
fn hash<H: Hasher>(&self, state: &mut H) {
nobang(&self.0).hash(state);
}
}
impl PartialOrd for Tag {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Tag {
fn cmp(&self, other: &Self) -> Ordering {
nobang(&self.0).cmp(nobang(&other.0))
}
}
impl TryFrom<&[u8]> for Tag {
type Error = core::str::Utf8Error;
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
core::str::from_utf8(bytes).map(Tag::new)
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct TaggedValue {
tag: Tag,
value: Box<Value>,
}
impl TaggedValue {
#[must_use]
pub fn new(tag: Tag, value: Value) -> Self {
Self {
tag,
value: Box::new(value),
}
}
#[must_use]
pub fn tag(&self) -> &Tag {
&self.tag
}
#[must_use]
pub fn value(&self) -> &Value {
&self.value
}
#[must_use]
pub fn value_mut(&mut self) -> &mut Value {
&mut self.value
}
#[must_use]
pub fn into_parts(self) -> (Tag, Value) {
(self.tag, *self.value)
}
}
impl fmt::Display for TaggedValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} {}", self.tag, self.value)
}
}
impl Serialize for TaggedValue {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
use serde::ser::SerializeMap;
let mut map = serializer.serialize_map(Some(1))?;
map.serialize_entry(self.tag.as_str(), self.value())?;
map.end()
}
}
impl<'de> Deserialize<'de> for TaggedValue {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde::de::{MapAccess, Visitor};
struct TaggedValueVisitor;
impl<'de> Visitor<'de> for TaggedValueVisitor {
type Value = TaggedValue;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("a single-entry map representing a tagged value")
}
fn visit_map<A>(self, mut map: A) -> Result<TaggedValue, A::Error>
where
A: MapAccess<'de>,
{
let (tag, value): (String, Value) = map
.next_entry()?
.ok_or_else(|| serde::de::Error::custom("expected a single-entry map"))?;
Ok(TaggedValue::new(Tag::new(tag), value))
}
}
deserializer.deserialize_map(TaggedValueVisitor)
}
}
impl<'de> serde::Deserializer<'de> for &'de TaggedValue {
type Error = crate::Error;
fn deserialize_any<V>(self, visitor: V) -> crate::Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_map(TaggedValueMapAccess {
tag: Some(self.tag.as_str()),
value: Some(self.value()),
})
}
fn deserialize_enum<V>(
self,
_name: &'static str,
_variants: &'static [&'static str],
visitor: V,
) -> crate::Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_enum(TaggedValueEnumAccess { tagged: self })
}
serde::forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
byte_buf option unit unit_struct newtype_struct seq tuple
tuple_struct map struct identifier ignored_any
}
}
struct TaggedValueMapAccess<'de> {
tag: Option<&'de str>,
value: Option<&'de Value>,
}
impl<'de> serde::de::MapAccess<'de> for TaggedValueMapAccess<'de> {
type Error = crate::Error;
fn next_key_seed<K>(&mut self, seed: K) -> crate::Result<Option<K::Value>>
where
K: serde::de::DeserializeSeed<'de>,
{
match self.tag.take() {
Some(tag) => seed
.deserialize(serde::de::value::BorrowedStrDeserializer::new(tag))
.map(Some),
None => Ok(None),
}
}
fn next_value_seed<V>(&mut self, seed: V) -> crate::Result<V::Value>
where
V: serde::de::DeserializeSeed<'de>,
{
match self.value.take() {
Some(value) => seed.deserialize(value),
None => Err(serde::de::Error::custom("value is missing")),
}
}
}
pub(crate) struct TagPreservingMapAccess<'de> {
state: TagPreservingState<'de>,
}
#[derive(Clone, Copy)]
enum TagPreservingState<'de> {
EmitTagKey { tag: &'de str, value: &'de Value },
EmitTagValue { tag: &'de str, value: &'de Value },
EmitValueKey { value: &'de Value },
EmitValueValue { value: &'de Value },
Done,
}
impl<'de> TagPreservingMapAccess<'de> {
pub(crate) fn new(tag: &'de str, value: &'de Value) -> Self {
Self {
state: TagPreservingState::EmitTagKey { tag, value },
}
}
}
impl<'de> serde::de::MapAccess<'de> for TagPreservingMapAccess<'de> {
type Error = crate::Error;
fn next_key_seed<K>(&mut self, seed: K) -> crate::Result<Option<K::Value>>
where
K: serde::de::DeserializeSeed<'de>,
{
match self.state {
TagPreservingState::EmitTagKey { tag, value } => {
self.state = TagPreservingState::EmitTagValue { tag, value };
seed.deserialize(
serde::de::value::BorrowedStrDeserializer::<crate::Error>::new(
TAGGED_VALUE_FIELD_TAG,
),
)
.map(Some)
}
TagPreservingState::EmitValueKey { value } => {
self.state = TagPreservingState::EmitValueValue { value };
seed.deserialize(
serde::de::value::BorrowedStrDeserializer::<crate::Error>::new(
TAGGED_VALUE_FIELD_VALUE,
),
)
.map(Some)
}
TagPreservingState::Done => Ok(None),
TagPreservingState::EmitTagValue { .. } | TagPreservingState::EmitValueValue { .. } => {
Err(serde::de::Error::custom(
"TagPreservingMapAccess: next_key called before next_value",
))
}
}
}
fn next_value_seed<V>(&mut self, seed: V) -> crate::Result<V::Value>
where
V: serde::de::DeserializeSeed<'de>,
{
match self.state {
TagPreservingState::EmitTagValue { tag, value } => {
self.state = TagPreservingState::EmitValueKey { value };
seed.deserialize(
serde::de::value::BorrowedStrDeserializer::<crate::Error>::new(tag),
)
}
TagPreservingState::EmitValueValue { value } => {
self.state = TagPreservingState::Done;
seed.deserialize(crate::de::Deserializer::with_options_preserving_tags(
value, None, false,
))
}
_ => Err(serde::de::Error::custom(
"TagPreservingMapAccess: next_value called out of order",
)),
}
}
}
struct TaggedValueEnumAccess<'de> {
tagged: &'de TaggedValue,
}
impl<'de> serde::de::EnumAccess<'de> for TaggedValueEnumAccess<'de> {
type Error = crate::Error;
type Variant = TaggedValueVariantAccess<'de>;
fn variant_seed<V>(self, seed: V) -> crate::Result<(V::Value, Self::Variant)>
where
V: serde::de::DeserializeSeed<'de>,
{
let variant = seed.deserialize(
serde::de::value::BorrowedStrDeserializer::<crate::Error>::new(
self.tagged.tag.nobang(),
),
)?;
Ok((
variant,
TaggedValueVariantAccess {
value: self.tagged.value(),
},
))
}
}
struct TaggedValueVariantAccess<'de> {
value: &'de Value,
}
impl<'de> serde::de::VariantAccess<'de> for TaggedValueVariantAccess<'de> {
type Error = crate::Error;
fn unit_variant(self) -> crate::Result<()> {
Ok(())
}
fn newtype_variant_seed<T>(self, seed: T) -> crate::Result<T::Value>
where
T: serde::de::DeserializeSeed<'de>,
{
seed.deserialize(self.value)
}
fn tuple_variant<V>(self, _len: usize, visitor: V) -> crate::Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
serde::Deserializer::deserialize_seq(self.value, visitor)
}
fn struct_variant<V>(
self,
_fields: &'static [&'static str],
visitor: V,
) -> crate::Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
serde::Deserializer::deserialize_map(self.value, visitor)
}
}
#[derive(Debug, Clone, Default)]
pub enum Value {
#[default]
Null,
Bool(bool),
Number(Number),
String(String),
Sequence(Sequence),
Mapping(Mapping),
Tagged(Box<TaggedValue>),
}
impl Value {
#[must_use]
pub fn is_null(&self) -> bool {
matches!(self, Value::Null)
}
#[must_use]
pub fn is_bool(&self) -> bool {
matches!(self, Value::Bool(_))
}
#[must_use]
pub fn is_number(&self) -> bool {
matches!(self, Value::Number(_))
}
#[must_use]
pub fn is_string(&self) -> bool {
matches!(self, Value::String(_))
}
#[must_use]
pub fn is_sequence(&self) -> bool {
matches!(self, Value::Sequence(_))
}
#[must_use]
pub fn is_mapping(&self) -> bool {
matches!(self, Value::Mapping(_))
}
#[must_use]
pub fn is_tagged(&self) -> bool {
matches!(self, Value::Tagged(_))
}
#[must_use]
pub fn as_bool(&self) -> Option<bool> {
match self {
Value::Bool(b) => Some(*b),
_ => None,
}
}
#[must_use]
pub fn as_null(&self) -> Option<()> {
match self {
Value::Null => Some(()),
_ => None,
}
}
#[must_use]
pub fn as_i64(&self) -> Option<i64> {
match self {
Value::Number(n) => n.as_i64(),
_ => None,
}
}
#[must_use]
pub fn as_u64(&self) -> Option<u64> {
match self {
Value::Number(n) => n.as_u64(),
_ => None,
}
}
#[must_use]
pub fn as_f64(&self) -> Option<f64> {
match self {
Value::Number(n) => Some(n.as_f64()),
_ => None,
}
}
#[must_use]
pub fn is_i64(&self) -> bool {
match self {
Value::Number(n) => n.is_i64(),
_ => false,
}
}
#[must_use]
pub fn is_u64(&self) -> bool {
match self {
Value::Number(n) => n.is_u64(),
_ => false,
}
}
#[must_use]
pub fn is_f64(&self) -> bool {
matches!(self, Value::Number(_))
}
#[must_use]
pub fn as_str(&self) -> Option<&str> {
match self {
Value::String(s) => Some(s),
_ => None,
}
}
#[must_use]
pub fn as_sequence(&self) -> Option<&Sequence> {
match self {
Value::Sequence(s) => Some(s),
_ => None,
}
}
#[must_use]
pub fn as_sequence_mut(&mut self) -> Option<&mut Sequence> {
match self {
Value::Sequence(s) => Some(s),
_ => None,
}
}
#[must_use]
pub fn as_mapping(&self) -> Option<&Mapping> {
match self {
Value::Mapping(m) => Some(m),
_ => None,
}
}
#[must_use]
pub fn as_mapping_mut(&mut self) -> Option<&mut Mapping> {
match self {
Value::Mapping(m) => Some(m),
_ => None,
}
}
#[must_use]
pub fn as_tagged(&self) -> Option<&TaggedValue> {
match self {
Value::Tagged(t) => Some(t),
_ => None,
}
}
#[must_use]
pub fn as_tagged_mut(&mut self) -> Option<&mut TaggedValue> {
match self {
Value::Tagged(t) => Some(t),
_ => None,
}
}
#[must_use]
pub fn get<I: ValueIndex>(&self, index: I) -> Option<&Value> {
index.index_into(self)
}
#[must_use]
pub fn get_mut<I: ValueIndex>(&mut self, index: I) -> Option<&mut Value> {
index.index_into_mut(self)
}
#[must_use]
pub fn get_path(&self, path: &str) -> Option<&Value> {
let segments = parse_path(path);
let mut current = self;
for segment in segments {
current = match segment {
QuerySegment::Key(key) => current.get(key.as_str())?,
QuerySegment::Index(idx) => current.get(idx)?,
QuerySegment::Wildcard | QuerySegment::RecursiveDescent => {
return self.query(path).into_iter().next();
}
};
}
Some(current)
}
#[must_use]
pub fn query(&self, path: &str) -> Vec<&Value> {
let segments = parse_path(path);
let mut results = Vec::new();
query_recursive(self, &segments, 0, &mut results);
results
}
#[must_use]
pub fn get_path_mut(&mut self, path: &str) -> Option<&mut Value> {
let segments = parse_path(path);
let mut current = self;
for segment in segments {
current = match segment {
QuerySegment::Key(key) => current.get_mut(key.as_str())?,
QuerySegment::Index(idx) => current.get_mut(idx)?,
QuerySegment::Wildcard | QuerySegment::RecursiveDescent => return None,
};
}
Some(current)
}
pub fn merge(&mut self, other: Value) {
match (self, other) {
(Value::Mapping(base), Value::Mapping(other)) => {
for (key, other_value) in other {
match base.get_mut(&key) {
Some(base_value) => {
base_value.merge(other_value);
}
None => {
let _ = base.insert(key, other_value);
}
}
}
}
(this, other) => {
*this = other;
}
}
}
pub fn merge_concat(&mut self, other: Value) {
match (self, other) {
(Value::Mapping(base), Value::Mapping(other)) => {
for (key, other_value) in other {
match base.get_mut(&key) {
Some(base_value) => {
base_value.merge_concat(other_value);
}
None => {
let _ = base.insert(key, other_value);
}
}
}
}
(Value::Sequence(base), Value::Sequence(other)) => {
base.extend(other);
}
(this, other) => {
*this = other;
}
}
}
pub fn remove(&mut self, key: &str) -> Option<Value> {
match self {
Value::Mapping(map) => map.shift_remove(key),
_ => None,
}
}
pub fn insert(&mut self, key: impl Into<String>, value: Value) -> Option<Value> {
match self {
Value::Mapping(map) => map.insert(key.into(), value),
_ => None,
}
}
pub fn apply_merge(&mut self) -> crate::Result<()> {
match self {
Value::Mapping(mapping) => {
for value in mapping.values_mut() {
value.apply_merge()?;
}
let merge_value = mapping.remove("<<");
let merge_sequence = match merge_value {
Some(Value::Sequence(seq)) => seq,
Some(value) => vec![value],
None => vec![],
};
for value in merge_sequence {
match value {
Value::Mapping(merge_map) => {
for (k, v) in merge_map {
let _ = mapping.entry(k).or_insert(v);
}
}
Value::Sequence(_) => {
return Err(crate::Error::SequenceInMergeElement);
}
Value::Tagged(_) => {
return Err(crate::Error::TaggedInMerge);
}
_ => {
return Err(crate::Error::ScalarInMergeElement);
}
}
}
}
Value::Sequence(seq) => {
for value in seq {
value.apply_merge()?;
}
}
Value::Tagged(tagged) => {
tagged.value_mut().apply_merge()?;
}
_ => {}
}
Ok(())
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
pub fn interpolate_properties<S>(
&mut self,
properties: &std::collections::HashMap<String, S>,
) -> crate::Result<()>
where
S: AsRef<str>,
{
self.interpolate_inner(
&|name| match properties.get(name) {
Some(v) => ResolveOutcome::Found(v.as_ref().to_owned()),
None => ResolveOutcome::Missing,
},
MissingAction::Error(false),
)
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
pub fn interpolate_properties_redacted<S>(
&mut self,
properties: &std::collections::HashMap<String, S>,
) -> crate::Result<()>
where
S: AsRef<str>,
{
self.interpolate_inner(
&|name| match properties.get(name) {
Some(v) => ResolveOutcome::Found(v.as_ref().to_owned()),
None => ResolveOutcome::Missing,
},
MissingAction::Error(true),
)
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
pub fn interpolate_properties_lossy<S>(
&mut self,
properties: &std::collections::HashMap<String, S>,
) where
S: AsRef<str>,
{
let _ = self.interpolate_inner(
&|name| match properties.get(name) {
Some(v) => ResolveOutcome::Found(v.as_ref().to_owned()),
None => ResolveOutcome::Missing,
},
MissingAction::Empty,
);
}
#[cfg(feature = "std")]
pub(crate) fn interpolate_inner(
&mut self,
resolve: &dyn Fn(&str) -> ResolveOutcome,
missing_action: MissingAction,
) -> crate::Result<()> {
match self {
Value::String(s) => {
if let Some(updated) = expand_placeholders(s, resolve, missing_action)? {
*s = updated;
}
}
Value::Sequence(seq) => {
for v in seq {
v.interpolate_inner(resolve, missing_action)?;
}
}
Value::Mapping(map) => {
for v in map.values_mut() {
v.interpolate_inner(resolve, missing_action)?;
}
}
Value::Tagged(tagged) => {
tagged
.value_mut()
.interpolate_inner(resolve, missing_action)?;
}
Value::Null | Value::Bool(_) | Value::Number(_) => {}
}
Ok(())
}
#[must_use]
pub fn untag(self) -> Self {
match self {
Value::Tagged(tagged) => tagged.value.untag(),
Value::Sequence(seq) => Value::Sequence(seq.into_iter().map(Value::untag).collect()),
Value::Mapping(map) => {
let untagged: Mapping = map.into_iter().map(|(k, v)| (k, v.untag())).collect();
Value::Mapping(untagged)
}
other => other,
}
}
#[must_use]
pub fn untag_ref(&self) -> &Self {
match self {
Value::Tagged(tagged) => tagged.value.untag_ref(),
other => other,
}
}
#[must_use]
pub fn untag_mut(&mut self) -> &mut Self {
match self {
Value::Tagged(tagged) => tagged.value.untag_mut(),
other => other,
}
}
}
use crate::path::{parse_query_path, QuerySegment};
fn parse_path(path: &str) -> Vec<QuerySegment> {
parse_query_path(path)
}
fn query_recursive<'a>(
value: &'a Value,
segments: &[QuerySegment],
depth: usize,
results: &mut Vec<&'a Value>,
) {
if depth >= segments.len() {
results.push(value);
return;
}
match &segments[depth] {
QuerySegment::Key(key) => {
if let Some(child) = value.get(key.as_str()) {
query_recursive(child, segments, depth + 1, results);
}
}
QuerySegment::Index(idx) => {
if let Some(child) = value.get(*idx) {
query_recursive(child, segments, depth + 1, results);
}
}
QuerySegment::Wildcard => match value {
Value::Sequence(seq) => {
for item in seq {
query_recursive(item, segments, depth + 1, results);
}
}
Value::Mapping(map) => {
for (_, v) in map.iter() {
query_recursive(v, segments, depth + 1, results);
}
}
_ => {}
},
QuerySegment::RecursiveDescent => {
let remaining = &segments[depth + 1..];
if !remaining.is_empty() {
query_recursive(value, segments, depth + 1, results);
match value {
Value::Sequence(seq) => {
for item in seq {
query_recursive(item, segments, depth, results);
}
}
Value::Mapping(map) => {
for (_, v) in map.iter() {
query_recursive(v, segments, depth, results);
}
}
Value::Tagged(t) => {
query_recursive(t.value(), segments, depth, results);
}
_ => {}
}
}
}
}
}
impl PartialEq for Value {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Value::Null, Value::Null) => true,
(Value::Bool(a), Value::Bool(b)) => a == b,
(Value::Number(a), Value::Number(b)) => a == b,
(Value::String(a), Value::String(b)) => a == b,
(Value::Sequence(a), Value::Sequence(b)) => a == b,
(Value::Mapping(a), Value::Mapping(b)) => a == b,
(Value::Tagged(a), Value::Tagged(b)) => a == b,
_ => false,
}
}
}
impl Eq for Value {}
impl Hash for Value {
fn hash<H: Hasher>(&self, state: &mut H) {
core::mem::discriminant(self).hash(state);
match self {
Value::Null => {}
Value::Bool(b) => b.hash(state),
Value::Number(n) => n.hash(state),
Value::String(s) => s.hash(state),
Value::Sequence(seq) => {
seq.len().hash(state);
for v in seq {
v.hash(state);
}
}
Value::Mapping(map) => {
map.len().hash(state);
for (k, v) in map {
k.hash(state);
v.hash(state);
}
}
Value::Tagged(tagged) => {
tagged.tag().hash(state);
tagged.value().hash(state);
}
}
}
}
impl PartialOrd for Value {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Value {
fn cmp(&self, other: &Self) -> Ordering {
fn type_order(v: &Value) -> u8 {
match v {
Value::Null => 0,
Value::Bool(_) => 1,
Value::Number(_) => 2,
Value::String(_) => 3,
Value::Sequence(_) => 4,
Value::Mapping(_) => 5,
Value::Tagged(_) => 6,
}
}
match type_order(self).cmp(&type_order(other)) {
Ordering::Equal => {}
ord => return ord,
}
match (self, other) {
(Value::Null, Value::Null) => Ordering::Equal,
(Value::Bool(a), Value::Bool(b)) => a.cmp(b),
(Value::Number(a), Value::Number(b)) => a.cmp(b),
(Value::String(a), Value::String(b)) => a.cmp(b),
(Value::Sequence(a), Value::Sequence(b)) => a.len().cmp(&b.len()).then_with(|| {
for (av, bv) in a.iter().zip(b.iter()) {
match av.cmp(bv) {
Ordering::Equal => continue,
ord => return ord,
}
}
Ordering::Equal
}),
(Value::Mapping(a), Value::Mapping(b)) => a.len().cmp(&b.len()).then_with(|| {
for ((ak, av), (bk, bv)) in a.iter().zip(b.iter()) {
match ak.cmp(bk) {
Ordering::Equal => {}
ord => return ord,
}
match av.cmp(bv) {
Ordering::Equal => continue,
ord => return ord,
}
}
Ordering::Equal
}),
(Value::Tagged(a), Value::Tagged(b)) => a
.tag()
.as_str()
.cmp(b.tag().as_str())
.then_with(|| a.value().cmp(b.value())),
_ => unreachable!("type_order check ensures same variants"),
}
}
}
impl fmt::Display for Value {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Value::Null => write!(f, "null"),
Value::Bool(b) => write!(f, "{b}"),
Value::Number(n) => write!(f, "{n}"),
Value::String(s) => write!(f, "{s}"),
Value::Sequence(s) => {
write!(f, "[")?;
for (i, v) in s.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{v}")?;
}
write!(f, "]")
}
Value::Mapping(m) => {
write!(f, "{{")?;
for (i, (k, v)) in m.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{k}: {v}")?;
}
write!(f, "}}")
}
Value::Tagged(t) => write!(f, "{t}"),
}
}
}
pub trait ValueIndex {
fn index_into(self, value: &Value) -> Option<&Value>;
fn index_into_mut(self, value: &mut Value) -> Option<&mut Value>;
fn index_or_insert(self, value: &mut Value) -> &mut Value;
}
impl ValueIndex for usize {
fn index_into(self, value: &Value) -> Option<&Value> {
match value {
Value::Sequence(s) => s.get(self),
Value::Tagged(t) => self.index_into(t.value()),
_ => None,
}
}
fn index_into_mut(self, value: &mut Value) -> Option<&mut Value> {
match value {
Value::Sequence(s) => s.get_mut(self),
Value::Tagged(t) => self.index_into_mut(t.value_mut()),
_ => None,
}
}
#[track_caller]
fn index_or_insert(self, value: &mut Value) -> &mut Value {
match value {
Value::Sequence(s) => {
let len = s.len();
s.get_mut(self).unwrap_or_else(|| {
panic!(
"cannot access index {} of YAML sequence of length {}",
self, len
)
})
}
Value::Tagged(t) => self.index_or_insert(t.value_mut()),
_ => panic!(
"cannot access index {} of YAML {}",
self,
value_type_name(value)
),
}
}
}
impl ValueIndex for &str {
fn index_into(self, value: &Value) -> Option<&Value> {
match value {
Value::Mapping(m) => m.get(self),
Value::Tagged(t) => self.index_into(t.value()),
_ => None,
}
}
fn index_into_mut(self, value: &mut Value) -> Option<&mut Value> {
match value {
Value::Mapping(m) => m.get_mut(self),
Value::Tagged(t) => self.index_into_mut(t.value_mut()),
_ => None,
}
}
#[track_caller]
fn index_or_insert(self, value: &mut Value) -> &mut Value {
if let Value::Null = value {
*value = Value::Mapping(Mapping::new());
}
match value {
Value::Mapping(m) => {
let _ = m.entry(self.to_owned()).or_insert(Value::Null);
m.get_mut(self).unwrap()
}
Value::Tagged(t) => self.index_or_insert(t.value_mut()),
_ => panic!(
"cannot access key {:?} in YAML {}",
self,
value_type_name(value)
),
}
}
}
impl ValueIndex for String {
fn index_into(self, value: &Value) -> Option<&Value> {
self.as_str().index_into(value)
}
fn index_into_mut(self, value: &mut Value) -> Option<&mut Value> {
self.as_str().index_into_mut(value)
}
#[track_caller]
fn index_or_insert(self, value: &mut Value) -> &mut Value {
self.as_str().index_or_insert(value)
}
}
impl ValueIndex for &String {
fn index_into(self, value: &Value) -> Option<&Value> {
self.as_str().index_into(value)
}
fn index_into_mut(self, value: &mut Value) -> Option<&mut Value> {
self.as_str().index_into_mut(value)
}
#[track_caller]
fn index_or_insert(self, value: &mut Value) -> &mut Value {
self.as_str().index_or_insert(value)
}
}
impl ValueIndex for &Value {
fn index_into(self, value: &Value) -> Option<&Value> {
match self {
Value::String(s) => s.as_str().index_into(value),
Value::Number(Number::Integer(n)) if *n >= 0 => {
usize::try_from(*n).ok()?.index_into(value)
}
_ => None,
}
}
fn index_into_mut(self, value: &mut Value) -> Option<&mut Value> {
match self {
Value::String(s) => s.as_str().index_into_mut(value),
Value::Number(Number::Integer(n)) if *n >= 0 => {
usize::try_from(*n).ok()?.index_into_mut(value)
}
_ => None,
}
}
#[track_caller]
fn index_or_insert(self, value: &mut Value) -> &mut Value {
match self {
Value::String(s) => s.as_str().index_or_insert(value),
Value::Number(Number::Integer(n)) if *n >= 0 => {
let idx =
usize::try_from(*n).unwrap_or_else(|_| panic!("index {} overflows usize", n));
idx.index_or_insert(value)
}
_ => panic!("cannot index with {:?}", self),
}
}
}
#[cfg(feature = "std")]
pub(crate) enum ResolveOutcome {
Found(String),
Missing,
#[allow(dead_code)]
Error(crate::Error),
}
#[derive(Debug, Clone, Copy)]
pub(crate) enum MissingAction {
Empty,
Error(bool),
}
fn expand_placeholders(
s: &str,
resolve: &dyn Fn(&str) -> ResolveOutcome,
missing_action: MissingAction,
) -> crate::Result<Option<String>> {
let bytes = s.as_bytes();
if !bytes.contains(&b'$') && !bytes.contains(&b'}') {
return Ok(None);
}
let mut out = String::with_capacity(s.len());
let mut i = 0;
let mut touched = false;
while i < bytes.len() {
let b = bytes[i];
if b == b'$' && i + 1 < bytes.len() && bytes[i + 1] == b'$' {
out.push('$');
i += 2;
touched = true;
continue;
}
if b == b'$' && i + 1 < bytes.len() && bytes[i + 1] == b'{' {
if i + 2 < bytes.len() && bytes[i + 2] == b'{' {
out.push_str("${");
i += 3;
touched = true;
continue;
}
let name_start = i + 2;
let mut j = name_start;
while j < bytes.len() && bytes[j] != b'}' && bytes[j] != b':' {
let c = bytes[j];
let ok = c.is_ascii_alphanumeric() || c == b'_' || c == b'.';
if !ok {
return Err(crate::Error::Custom(format!(
"interpolate_properties: invalid character {:?} in placeholder",
c as char
)));
}
j += 1;
}
if j >= bytes.len() {
return Err(crate::Error::Custom(
"interpolate_properties: unterminated `${...}` placeholder".into(),
));
}
if name_start == j {
return Err(crate::Error::Custom(
"interpolate_properties: empty placeholder `${}`".into(),
));
}
let name = &s[name_start..j];
let mut default: Option<&str> = None;
let mut close = j;
if bytes[j] == b':' {
if j + 1 >= bytes.len() || bytes[j + 1] != b'-' {
return Err(crate::Error::Custom(
"interpolate_properties: expected `:-default` after `${name:`".into(),
));
}
let default_start = j + 2;
let mut k = default_start;
while k < bytes.len() && bytes[k] != b'}' {
k += 1;
}
if k >= bytes.len() {
return Err(crate::Error::Custom(
"interpolate_properties: unterminated `${name:-default}`".into(),
));
}
default = Some(&s[default_start..k]);
close = k;
}
let value = match resolve(name) {
ResolveOutcome::Found(v) => v,
ResolveOutcome::Missing => match default {
Some(d) => d.to_owned(),
None => match missing_action {
MissingAction::Empty => String::new(),
MissingAction::Error(redact) => {
return Err(crate::Error::Custom(if redact {
"interpolate_properties: unknown placeholder `${<redacted>}`".into()
} else {
format!("interpolate_properties: unknown placeholder `${{{name}}}`")
}));
}
},
},
ResolveOutcome::Error(e) => return Err(e),
};
out.push_str(&value);
i = close + 1;
touched = true;
continue;
}
if b == b'}' && i + 1 < bytes.len() && bytes[i + 1] == b'}' {
out.push('}');
i += 2;
touched = true;
continue;
}
let c = s[i..].chars().next().expect("char at boundary");
out.push(c);
i += c.len_utf8();
}
if touched {
Ok(Some(out))
} else {
Ok(None)
}
}
fn value_type_name(value: &Value) -> &'static str {
match value {
Value::Null => "null",
Value::Bool(_) => "boolean",
Value::Number(_) => "number",
Value::String(_) => "string",
Value::Sequence(_) => "sequence",
Value::Mapping(_) => "mapping",
Value::Tagged(_) => "tagged value",
}
}
impl<'de> Deserialize<'de> for Value {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde::de::{MapAccess, SeqAccess, Visitor};
struct ValueVisitor;
impl<'de> Visitor<'de> for ValueVisitor {
type Value = Value;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("any valid YAML value")
}
fn visit_bool<E>(self, v: bool) -> Result<Value, E> {
Ok(Value::Bool(v))
}
fn visit_i64<E>(self, v: i64) -> Result<Value, E> {
Ok(Value::Number(Number::Integer(v)))
}
fn visit_u64<E>(self, v: u64) -> Result<Value, E> {
Ok(Value::Number(Number::Integer(v as i64)))
}
fn visit_f64<E>(self, v: f64) -> Result<Value, E> {
Ok(Value::Number(Number::Float(v)))
}
fn visit_str<E>(self, v: &str) -> Result<Value, E> {
Ok(Value::String(v.to_owned()))
}
fn visit_string<E>(self, v: String) -> Result<Value, E> {
Ok(Value::String(v))
}
fn visit_none<E>(self) -> Result<Value, E> {
Ok(Value::Null)
}
fn visit_unit<E>(self) -> Result<Value, E> {
Ok(Value::Null)
}
fn visit_seq<A>(self, mut seq: A) -> Result<Value, A::Error>
where
A: SeqAccess<'de>,
{
let mut vec = match seq.size_hint() {
Some(n) if n > 0 && n < 1 << 20 => Vec::with_capacity(n),
_ => Vec::new(),
};
while let Some(elem) = seq.next_element()? {
vec.push(elem);
}
Ok(Value::Sequence(vec))
}
fn visit_map<A>(self, mut map: A) -> Result<Value, A::Error>
where
A: MapAccess<'de>,
{
let first_key: Option<String> = map.next_key()?;
if let Some(k) = first_key.as_deref() {
if k == TAGGED_VALUE_FIELD_TAG {
let tag_str: String = map.next_value()?;
let second_key: String = map.next_key()?.ok_or_else(|| {
<A::Error as serde::de::Error>::custom(
"tag-preserving map missing $__noyalib_value entry",
)
})?;
if second_key != TAGGED_VALUE_FIELD_VALUE {
return Err(<A::Error as serde::de::Error>::custom(format!(
"tag-preserving map: expected `{}`, got `{}`",
TAGGED_VALUE_FIELD_VALUE, second_key
)));
}
let inner: Value = map.next_value()?;
return Ok(Value::Tagged(Box::new(TaggedValue::new(
Tag::new(tag_str),
inner,
))));
}
}
let mut mapping = match map.size_hint() {
Some(n) if n > 0 && n < 1 << 20 => Mapping::with_capacity(n),
_ => Mapping::new(),
};
if let Some(k) = first_key {
let v: Value = map.next_value()?;
let _ = mapping.insert(k, v);
}
while let Some((key, value)) = map.next_entry::<String, Value>()? {
let _ = mapping.insert(key, value);
}
Ok(Value::Mapping(mapping))
}
}
deserializer.deserialize_any(ValueVisitor)
}
}
impl Serialize for Value {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
match self {
Value::Null => serializer.serialize_none(),
Value::Bool(b) => serializer.serialize_bool(*b),
Value::Number(Number::Integer(n)) => serializer.serialize_i64(*n),
Value::Number(Number::Float(n)) => serializer.serialize_f64(*n),
Value::String(s) => serializer.serialize_str(s),
Value::Sequence(s) => s.serialize(serializer),
Value::Mapping(m) => {
use serde::ser::SerializeMap;
let mut map = serializer.serialize_map(Some(m.len()))?;
for (k, v) in m {
map.serialize_entry(k, v)?;
}
map.end()
}
Value::Tagged(tagged) => {
use serde::ser::SerializeMap;
let mut map = serializer.serialize_map(Some(1))?;
map.serialize_entry(tagged.tag().as_str(), tagged.value())?;
map.end()
}
}
}
}
impl<'de> serde::de::IntoDeserializer<'de, crate::Error> for &'de Value {
type Deserializer = Self;
fn into_deserializer(self) -> Self::Deserializer {
self
}
}
struct ValueSeqAccess<'de> {
iter: core::slice::Iter<'de, Value>,
}
impl<'de> serde::de::SeqAccess<'de> for ValueSeqAccess<'de> {
type Error = crate::Error;
fn next_element_seed<T>(&mut self, seed: T) -> crate::Result<Option<T::Value>>
where
T: serde::de::DeserializeSeed<'de>,
{
match self.iter.next() {
Some(value) => seed.deserialize(value).map(Some),
None => Ok(None),
}
}
}
struct ValueMapAccess<'de> {
iter: Iter<'de, String, Value>,
value: Option<&'de Value>,
}
impl<'de> serde::de::MapAccess<'de> for ValueMapAccess<'de> {
type Error = crate::Error;
fn next_key_seed<K>(&mut self, seed: K) -> crate::Result<Option<K::Value>>
where
K: serde::de::DeserializeSeed<'de>,
{
match self.iter.next() {
Some((key, value)) => {
self.value = Some(value);
seed.deserialize(serde::de::value::BorrowedStrDeserializer::new(key))
.map(Some)
}
None => Ok(None),
}
}
fn next_value_seed<V>(&mut self, seed: V) -> crate::Result<V::Value>
where
V: serde::de::DeserializeSeed<'de>,
{
match self.value.take() {
Some(value) => seed.deserialize(value),
None => Err(serde::de::Error::custom("value is missing")),
}
}
}
impl<'de> serde::Deserializer<'de> for &'de Value {
type Error = crate::Error;
fn deserialize_any<V>(self, visitor: V) -> crate::Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
match self {
Value::Null => visitor.visit_unit(),
Value::Bool(b) => visitor.visit_bool(*b),
Value::Number(Number::Integer(n)) => visitor.visit_i64(*n),
Value::Number(Number::Float(n)) => visitor.visit_f64(*n),
Value::String(s) => visitor.visit_borrowed_str(s),
Value::Sequence(seq) => visitor.visit_seq(ValueSeqAccess { iter: seq.iter() }),
Value::Mapping(map) => visitor.visit_map(ValueMapAccess {
iter: map.iter(),
value: None,
}),
Value::Tagged(tagged) => {
let tagged_ref: &'de TaggedValue = tagged;
serde::Deserializer::deserialize_any(tagged_ref, visitor)
}
}
}
fn deserialize_enum<V>(
self,
name: &'static str,
variants: &'static [&'static str],
visitor: V,
) -> crate::Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
match self {
Value::Tagged(tagged) => {
let tagged_ref: &'de TaggedValue = tagged;
serde::Deserializer::deserialize_enum(tagged_ref, name, variants, visitor)
}
Value::String(s) => visitor
.visit_enum(serde::de::value::BorrowedStrDeserializer::<crate::Error>::new(s)),
_ => serde::Deserializer::deserialize_any(self, visitor),
}
}
fn deserialize_seq<V>(self, visitor: V) -> crate::Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
match self {
Value::Sequence(seq) => visitor.visit_seq(ValueSeqAccess { iter: seq.iter() }),
_ => serde::Deserializer::deserialize_any(self, visitor),
}
}
fn deserialize_map<V>(self, visitor: V) -> crate::Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
match self {
Value::Mapping(map) => visitor.visit_map(ValueMapAccess {
iter: map.iter(),
value: None,
}),
_ => serde::Deserializer::deserialize_any(self, visitor),
}
}
fn deserialize_struct<V>(
self,
name: &'static str,
_fields: &'static [&'static str],
visitor: V,
) -> crate::Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
if name == crate::spanned::SPANNED_TYPE_NAME {
return visitor.visit_map(crate::de::SpannedMapAccess::new(self, None));
}
serde::Deserializer::deserialize_map(self, visitor)
}
serde::forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
byte_buf option unit unit_struct newtype_struct tuple
tuple_struct identifier ignored_any
}
}
impl From<()> for Value {
fn from(_: ()) -> Self {
Value::Null
}
}
impl From<bool> for Value {
fn from(v: bool) -> Self {
Value::Bool(v)
}
}
impl From<i8> for Value {
fn from(v: i8) -> Self {
Value::Number(Number::Integer(i64::from(v)))
}
}
impl From<i16> for Value {
fn from(v: i16) -> Self {
Value::Number(Number::Integer(i64::from(v)))
}
}
impl From<i32> for Value {
fn from(v: i32) -> Self {
Value::Number(Number::Integer(i64::from(v)))
}
}
impl From<i64> for Value {
fn from(v: i64) -> Self {
Value::Number(Number::Integer(v))
}
}
impl From<u8> for Value {
fn from(v: u8) -> Self {
Value::Number(Number::Integer(i64::from(v)))
}
}
impl From<u16> for Value {
fn from(v: u16) -> Self {
Value::Number(Number::Integer(i64::from(v)))
}
}
impl From<u32> for Value {
fn from(v: u32) -> Self {
Value::Number(Number::Integer(i64::from(v)))
}
}
impl From<f32> for Value {
fn from(v: f32) -> Self {
Value::Number(Number::Float(f64::from(v)))
}
}
impl From<f64> for Value {
fn from(v: f64) -> Self {
Value::Number(Number::Float(v))
}
}
impl From<String> for Value {
fn from(v: String) -> Self {
Value::String(v)
}
}
impl From<&str> for Value {
fn from(v: &str) -> Self {
Value::String(v.to_owned())
}
}
impl<T: Into<Value>> From<Vec<T>> for Value {
fn from(v: Vec<T>) -> Self {
Value::Sequence(v.into_iter().map(Into::into).collect())
}
}
impl<T: Into<Value>> From<Option<T>> for Value {
fn from(v: Option<T>) -> Self {
match v {
Some(v) => v.into(),
None => Value::Null,
}
}
}
impl From<Number> for Value {
fn from(v: Number) -> Self {
Value::Number(v)
}
}
impl From<Mapping> for Value {
fn from(v: Mapping) -> Self {
Value::Mapping(v)
}
}
impl From<TaggedValue> for Value {
fn from(v: TaggedValue) -> Self {
Value::Tagged(Box::new(v))
}
}
impl From<u64> for Value {
fn from(v: u64) -> Self {
Value::Number(Number::from(v))
}
}
impl From<isize> for Value {
fn from(v: isize) -> Self {
Value::Number(Number::from(v))
}
}
impl From<usize> for Value {
fn from(v: usize) -> Self {
Value::Number(Number::from(v))
}
}
impl<'a> From<Cow<'a, str>> for Value {
fn from(v: Cow<'a, str>) -> Self {
Value::String(v.into_owned())
}
}
impl<T: Clone + Into<Value>> From<&[T]> for Value {
fn from(v: &[T]) -> Self {
Value::Sequence(v.iter().cloned().map(Into::into).collect())
}
}
impl<T: Into<Value>> FromIterator<T> for Value {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
Value::Sequence(iter.into_iter().map(Into::into).collect())
}
}
impl Index<usize> for Value {
type Output = Value;
#[track_caller]
fn index(&self, index: usize) -> &Self::Output {
self.get(index)
.expect("index out of bounds or not a sequence")
}
}
impl IndexMut<usize> for Value {
#[track_caller]
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
self.get_mut(index)
.expect("index out of bounds or not a sequence")
}
}
impl Index<&str> for Value {
type Output = Value;
#[track_caller]
fn index(&self, key: &str) -> &Self::Output {
self.get(key).expect("key not found or not a mapping")
}
}
impl IndexMut<&str> for Value {
#[track_caller]
fn index_mut(&mut self, key: &str) -> &mut Self::Output {
self.get_mut(key).expect("key not found or not a mapping")
}
}