mod de;
mod debug;
mod from;
mod index;
mod partial_eq;
mod ser;
pub mod tagged;
use crate::modules::error::{self, Error, ErrorImpl};
use serde::{
de::{Deserialize, DeserializeOwned, IntoDeserializer},
Serialize,
};
use std::{
hash::{Hash, Hasher},
mem,
};
pub use self::index::Index;
pub use self::ser::Serializer;
pub use self::tagged::{Tag, TaggedValue};
#[doc(inline)]
pub use crate::mapping::Mapping;
pub use crate::number::Number;
#[derive(Clone, PartialEq, PartialOrd)]
pub enum Value {
Null,
Bool(bool),
Number(Number),
String(String),
Sequence(Sequence),
Mapping(Mapping),
Tagged(Box<TaggedValue>),
}
impl Default for Value {
fn default() -> Value {
Value::Null
}
}
pub type Sequence = Vec<Value>;
pub fn to_value<T>(value: T) -> Result<Value, Error>
where
T: Serialize,
{
value.serialize(Serializer)
}
pub fn from_value<T>(value: Value) -> Result<T, Error>
where
T: DeserializeOwned,
{
Deserialize::deserialize(value)
}
impl Value {
pub fn get<I: Index>(&self, index: I) -> Option<&Value> {
index.index_into(self)
}
pub fn get_mut<I: Index>(
&mut self,
index: I,
) -> Option<&mut Value> {
index.index_into_mut(self)
}
pub fn is_null(&self) -> bool {
#[allow(clippy::match_like_matches_macro)]
if let Value::Null = self.untag_ref() {
true
} else {
false
}
}
pub fn as_null(&self) -> Option<()> {
match self.untag_ref() {
Value::Null => Some(()),
_ => None,
}
}
pub fn is_bool(&self) -> bool {
self.as_bool().is_some()
}
pub fn as_bool(&self) -> Option<bool> {
match self.untag_ref() {
Value::Bool(b) => Some(*b),
_ => None,
}
}
pub fn is_number(&self) -> bool {
#[allow(clippy::match_like_matches_macro)]
match self.untag_ref() {
Value::Number(_) => true,
_ => false,
}
}
pub fn is_i64(&self) -> bool {
self.as_i64().is_some()
}
pub fn as_i64(&self) -> Option<i64> {
match self.untag_ref() {
Value::Number(n) => n.as_i64(),
_ => None,
}
}
pub fn is_u64(&self) -> bool {
self.as_u64().is_some()
}
pub fn as_u64(&self) -> Option<u64> {
match self.untag_ref() {
Value::Number(n) => n.as_u64(),
_ => None,
}
}
pub fn is_f64(&self) -> bool {
match self.untag_ref() {
Value::Number(n) => n.is_f64(),
_ => false,
}
}
pub fn as_f64(&self) -> Option<f64> {
match self.untag_ref() {
Value::Number(i) => i.as_f64(),
_ => None,
}
}
pub fn is_string(&self) -> bool {
self.as_str().is_some()
}
pub fn as_str(&self) -> Option<&str> {
match self.untag_ref() {
Value::String(s) => Some(s),
_ => None,
}
}
pub fn is_sequence(&self) -> bool {
self.as_sequence().is_some()
}
pub fn as_sequence(&self) -> Option<&Sequence> {
match self.untag_ref() {
Value::Sequence(seq) => Some(seq),
_ => None,
}
}
pub fn as_sequence_mut(&mut self) -> Option<&mut Sequence> {
match self.untag_mut() {
Value::Sequence(seq) => Some(seq),
_ => None,
}
}
pub fn is_mapping(&self) -> bool {
self.as_mapping().is_some()
}
pub fn as_mapping(&self) -> Option<&Mapping> {
match self.untag_ref() {
Value::Mapping(map) => Some(map),
_ => None,
}
}
pub fn as_mapping_mut(&mut self) -> Option<&mut Mapping> {
match self.untag_mut() {
Value::Mapping(map) => Some(map),
_ => None,
}
}
pub fn apply_merge(&mut self) -> Result<(), Error> {
let mut stack = Vec::new();
stack.push(self);
while let Some(node) = stack.pop() {
match node {
Value::Mapping(mapping) => {
match mapping.remove("<<") {
Some(Value::Mapping(merge)) => {
for (k, v) in merge {
mapping.entry(k).or_insert(v);
}
}
Some(Value::Sequence(sequence)) => {
for value in sequence {
match value {
Value::Mapping(merge) => {
for (k, v) in merge {
mapping
.entry(k)
.or_insert(v);
}
}
Value::Sequence(_) => {
return Err(error::new(ErrorImpl::SequenceInMergeElement));
}
Value::Tagged(_) => {
return Err(error::new(
ErrorImpl::TaggedInMerge,
));
}
_unexpected => {
return Err(error::new(ErrorImpl::ScalarInMergeElement));
}
}
}
}
None => {}
Some(Value::Tagged(_)) => {
return Err(error::new(
ErrorImpl::TaggedInMerge,
))
}
Some(_unexpected) => {
return Err(error::new(
ErrorImpl::ScalarInMerge,
))
}
}
stack.extend(mapping.values_mut());
}
Value::Sequence(sequence) => stack.extend(sequence),
Value::Tagged(tagged) => stack.push(&mut tagged.value),
_ => {}
}
}
Ok(())
}
}
impl Eq for Value {}
impl Hash for Value {
fn hash<H: Hasher>(&self, state: &mut H) {
mem::discriminant(self).hash(state);
match self {
Value::Null => {}
Value::Bool(v) => v.hash(state),
Value::Number(v) => v.hash(state),
Value::String(v) => v.hash(state),
Value::Sequence(v) => v.hash(state),
Value::Mapping(v) => v.hash(state),
Value::Tagged(v) => v.hash(state),
}
}
}
impl IntoDeserializer<'_, Error> for Value {
type Deserializer = Self;
fn into_deserializer(self) -> Self::Deserializer {
self
}
}