use std::fmt;
use std::hash::{Hash, Hasher};
use oneyaml_core::Limits;
mod index;
#[cfg(feature = "serde_json")]
mod json;
mod mapping;
mod number;
mod serde_impl;
mod tag;
pub(crate) mod walk;
pub use index::ValueIndex;
pub(crate) use mapping::KeyRef;
pub use mapping::{IntoIter as MappingIntoIter, Iter as MappingIter, Mapping};
pub use number::Number;
pub(crate) use number::{MAX_CONVERTED_DIGITS, Radix};
pub(crate) use serde_impl::{
VALUE_MAGIC, arm, disarm, hand_off, is_tls_gone, take_handed_over, tls_gone_ser,
};
pub use tag::Tag;
pub(crate) use tag::{TagPrefix, TagStr};
#[cfg(test)]
mod tests;
pub(crate) const STRING_TAG: u8 = 3;
#[non_exhaustive]
#[derive(Default)]
pub enum Value {
#[default]
Null,
Bool(bool),
Number(Number),
String(String),
Sequence(Sequence),
Mapping(Mapping),
Tagged(Box<TaggedValue>),
}
#[derive(Default)]
pub struct Sequence {
pub(crate) items: Vec<Value>,
}
impl Sequence {
#[must_use]
pub const fn new() -> Self {
Self { items: Vec::new() }
}
#[must_use]
pub fn len(&self) -> usize {
self.items.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
#[must_use]
pub fn get(&self, index: usize) -> Option<&Value> {
self.items.get(index)
}
pub fn get_mut(&mut self, index: usize) -> Option<&mut Value> {
self.items.get_mut(index)
}
#[must_use]
pub fn first(&self) -> Option<&Value> {
self.items.first()
}
#[must_use]
pub fn last(&self) -> Option<&Value> {
self.items.last()
}
pub fn push(&mut self, value: Value) {
self.items.push(value);
}
pub fn pop(&mut self) -> Option<Value> {
self.items.pop()
}
pub fn insert_at(&mut self, index: usize, value: Value) -> Result<(), Value> {
if index > self.items.len() {
return Err(value);
}
self.items.insert(index, value);
Ok(())
}
pub fn remove_at(&mut self, index: usize) -> Option<Value> {
(index < self.items.len()).then(|| self.items.remove(index))
}
pub fn clear(&mut self) {
walk::drop_items(std::mem::take(&mut self.items));
}
pub fn iter(&self) -> std::slice::Iter<'_, Value> {
self.items.iter()
}
pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, Value> {
self.items.iter_mut()
}
#[must_use]
pub fn as_slice(&self) -> &[Value] {
&self.items
}
#[must_use]
pub fn into_vec(mut self) -> Vec<Value> {
std::mem::take(&mut self.items)
}
}
impl Extend<Value> for Sequence {
fn extend<I: IntoIterator<Item = Value>>(&mut self, iter: I) {
self.items.extend(iter);
}
}
impl<'a> IntoIterator for &'a mut Sequence {
type Item = &'a mut Value;
type IntoIter = std::slice::IterMut<'a, Value>;
fn into_iter(self) -> Self::IntoIter {
self.items.iter_mut()
}
}
impl From<Vec<Value>> for Sequence {
fn from(items: Vec<Value>) -> Self {
Self { items }
}
}
impl FromIterator<Value> for Sequence {
fn from_iter<I: IntoIterator<Item = Value>>(iter: I) -> Self {
Self {
items: iter.into_iter().collect(),
}
}
}
impl IntoIterator for Sequence {
type Item = Value;
type IntoIter = std::vec::IntoIter<Value>;
fn into_iter(self) -> Self::IntoIter {
self.into_vec().into_iter()
}
}
impl<'a> IntoIterator for &'a Sequence {
type Item = &'a Value;
type IntoIter = std::slice::Iter<'a, Value>;
fn into_iter(self) -> Self::IntoIter {
self.items.iter()
}
}
impl Drop for Sequence {
fn drop(&mut self) {
walk::drop_items(std::mem::take(&mut self.items));
}
}
impl Clone for Sequence {
fn clone(&self) -> Self {
Self {
items: self.items.iter().map(walk::clone_value).collect(),
}
}
}
impl PartialEq for Sequence {
fn eq(&self, other: &Self) -> bool {
walk::eq_sequences(self, other)
}
}
impl Eq for Sequence {}
impl Hash for Sequence {
fn hash<H: Hasher>(&self, state: &mut H) {
state.write_u64(walk::digest_sequence(self));
}
}
impl fmt::Debug for Sequence {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
walk::debug_sequence(self, f)
}
}
pub struct TaggedValue {
pub tag: Tag,
pub value: Value,
}
impl TaggedValue {
#[must_use]
pub fn into_parts(mut self) -> (Tag, Value) {
let tag = std::mem::replace(&mut self.tag, Tag::new(String::new()));
(tag, std::mem::replace(&mut self.value, Value::Null))
}
}
impl Drop for TaggedValue {
fn drop(&mut self) {
walk::drop_value(std::mem::replace(&mut self.value, Value::Null));
}
}
impl Clone for TaggedValue {
fn clone(&self) -> Self {
Self {
tag: self.tag.clone(),
value: walk::clone_value(&self.value),
}
}
}
impl PartialEq for TaggedValue {
fn eq(&self, other: &Self) -> bool {
self.tag == other.tag && walk::eq(&self.value, &other.value)
}
}
impl Eq for TaggedValue {}
impl Hash for TaggedValue {
fn hash<H: Hasher>(&self, state: &mut H) {
self.tag.hash(state);
state.write_u64(walk::digest(&self.value));
}
}
impl fmt::Debug for TaggedValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "TaggedValue({}, ", self.tag)?;
walk::debug_value(&self.value, f)?;
f.write_str(")")
}
}
impl Clone for Value {
fn clone(&self) -> Self {
walk::clone_value(self)
}
}
impl PartialEq for Value {
fn eq(&self, other: &Self) -> bool {
walk::eq(self, other)
}
}
impl Eq for Value {}
impl Hash for Value {
fn hash<H: Hasher>(&self, state: &mut H) {
state.write_u64(walk::digest(self));
}
}
impl fmt::Debug for Value {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
walk::debug_value(self, f)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) struct DepthExceeded {
pub(crate) limit: usize,
}
impl DepthExceeded {
pub(crate) fn into_error(self) -> crate::Error {
crate::Error::new(
oneyaml_core::code::VALUE_DEPTH_EXCEEDED,
format!("Value nests deeper than {} levels", self.limit),
None,
)
.with_help(format!(
"raise Limits::max_depth (currently {})",
self.limit
))
}
}
impl Value {
#[must_use]
pub fn depth(&self) -> usize {
walk::depth(self, usize::MAX)
}
pub(crate) fn check_depth(&self, limits: &Limits) -> Result<(), DepthExceeded> {
let limit = limits.get_max_depth();
if walk::depth(self, limit) > limit {
Err(DepthExceeded { limit })
} else {
Ok(())
}
}
#[must_use]
pub fn is_null(&self) -> bool {
matches!(self, Value::Null)
}
#[must_use]
pub fn as_null(&self) -> Option<()> {
self.is_null().then_some(())
}
#[must_use]
pub fn is_bool(&self) -> bool {
matches!(self, Value::Bool(_))
}
#[must_use]
pub fn as_bool(&self) -> Option<bool> {
match self {
Value::Bool(b) => Some(*b),
_ => None,
}
}
#[must_use]
pub fn is_number(&self) -> bool {
matches!(self, Value::Number(_))
}
#[must_use]
pub fn as_number(&self) -> Option<&Number> {
match self {
Value::Number(n) => Some(n),
_ => None,
}
}
#[must_use]
pub fn is_i64(&self) -> bool {
self.as_i64().is_some()
}
#[must_use]
pub fn as_i64(&self) -> Option<i64> {
self.as_number().and_then(Number::as_i64)
}
#[must_use]
pub fn is_u64(&self) -> bool {
self.as_u64().is_some()
}
#[must_use]
pub fn as_u64(&self) -> Option<u64> {
self.as_number().and_then(Number::as_u64)
}
#[must_use]
pub fn is_f64(&self) -> bool {
self.as_number().is_some_and(Number::is_float)
}
#[must_use]
pub fn as_f64(&self) -> Option<f64> {
self.as_number().and_then(Number::as_f64)
}
#[must_use]
pub fn is_string(&self) -> bool {
matches!(self, Value::String(_))
}
#[must_use]
pub fn as_str(&self) -> Option<&str> {
match self {
Value::String(s) => Some(s),
_ => None,
}
}
#[must_use]
pub fn is_sequence(&self) -> bool {
matches!(self, Value::Sequence(_))
}
#[must_use]
pub fn as_sequence(&self) -> Option<&Sequence> {
match self {
Value::Sequence(s) => Some(s),
_ => None,
}
}
pub fn as_sequence_mut(&mut self) -> Option<&mut Sequence> {
match self {
Value::Sequence(s) => Some(s),
_ => None,
}
}
#[must_use]
pub fn is_mapping(&self) -> bool {
matches!(self, Value::Mapping(_))
}
#[must_use]
pub fn as_mapping(&self) -> Option<&Mapping> {
match self {
Value::Mapping(m) => Some(m),
_ => None,
}
}
pub fn as_mapping_mut(&mut self) -> Option<&mut Mapping> {
match self {
Value::Mapping(m) => Some(m),
_ => None,
}
}
#[must_use]
pub fn is_tagged(&self) -> bool {
matches!(self, Value::Tagged(_))
}
#[must_use]
pub fn as_tagged(&self) -> Option<&TaggedValue> {
match self {
Value::Tagged(t) => Some(t),
_ => None,
}
}
#[must_use]
pub fn untag_ref(&self) -> &Value {
let mut v = self;
while let Value::Tagged(t) = v {
v = &t.value;
}
v
}
pub fn untag_mut(&mut self) -> &mut Value {
let mut v = self;
while let Value::Tagged(t) = v {
v = &mut t.value;
}
v
}
#[must_use]
pub fn untag(self) -> Value {
let mut v = self;
while let Value::Tagged(t) = v {
v = t.into_parts().1;
}
v
}
#[must_use]
pub fn get<I: ValueIndex>(&self, index: I) -> Option<&Value> {
index.index_into(self)
}
pub fn get_mut<I: ValueIndex>(&mut self, index: I) -> Option<&mut Value> {
index.index_into_mut(self)
}
}
macro_rules! from_number {
($($t:ty),*) => {$(
impl From<$t> for Value {
fn from(v: $t) -> Self {
Value::Number(Number::from(v))
}
}
)*};
}
from_number!(
i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, f32, f64
);
impl From<Number> for Value {
fn from(v: Number) -> Self {
Value::Number(v)
}
}
impl From<bool> for Value {
fn from(v: bool) -> Self {
Value::Bool(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 From<Sequence> for Value {
fn from(v: Sequence) -> Self {
Value::Sequence(v)
}
}
impl From<Vec<Value>> for Value {
fn from(v: Vec<Value>) -> Self {
Value::Sequence(Sequence::from(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 FromIterator<Value> for Value {
fn from_iter<I: IntoIterator<Item = Value>>(iter: I) -> Self {
Value::Sequence(iter.into_iter().collect())
}
}