use crate::error::{Error, Result};
use crate::prelude::*;
use crate::span_context;
use crate::value::{Number, Value};
use serde::Deserialize;
use serde::de::{self, DeserializeSeed, IntoDeserializer, MapAccess, SeqAccess, Visitor};
#[derive(Debug, Clone, Copy)]
pub struct Deserializer<'de> {
pub(crate) value: &'de Value,
pub(crate) span_ctx: Option<&'de span_context::SpanContext>,
pub(crate) ignore_binary_tag_for_string: bool,
pub(crate) preserve_tags: bool,
}
impl<'de> Deserializer<'de> {
#[must_use]
pub fn new(value: &'de Value) -> Self {
Deserializer {
value,
span_ctx: None,
ignore_binary_tag_for_string: false,
preserve_tags: false,
}
}
#[must_use]
pub fn with_span_context(value: &'de Value, span_ctx: &'de span_context::SpanContext) -> Self {
Deserializer {
value,
span_ctx: Some(span_ctx),
ignore_binary_tag_for_string: false,
preserve_tags: false,
}
}
pub(crate) fn with_options(
value: &'de Value,
span_ctx: Option<&'de span_context::SpanContext>,
ignore_binary_tag_for_string: bool,
) -> Self {
Deserializer {
value,
span_ctx,
ignore_binary_tag_for_string,
preserve_tags: false,
}
}
pub(crate) fn with_options_preserving_tags(
value: &'de Value,
span_ctx: Option<&'de span_context::SpanContext>,
ignore_binary_tag_for_string: bool,
) -> Self {
Deserializer {
value,
span_ctx,
ignore_binary_tag_for_string,
preserve_tags: true,
}
}
pub(crate) fn descend(&self, value: &'de Value) -> Self {
Deserializer {
value,
span_ctx: self.span_ctx,
ignore_binary_tag_for_string: self.ignore_binary_tag_for_string,
preserve_tags: self.preserve_tags,
}
}
fn wrap_err<T>(&self, res: Result<T>) -> Result<T> {
match res {
Err(Error::Deserialize(msg)) => {
if let Some(ctx) = self.span_ctx {
let ptr: *const Value = self.value;
let addr = ptr as usize;
if let Some(span) = ctx.spans.get(&addr) {
return Err(Error::deserialize_at(msg, &ctx.source, span.0));
}
}
Err(Error::Deserialize(msg))
}
_ => res,
}
}
}
impl<'de> de::Deserializer<'de> for Deserializer<'de> {
type Error = Error;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
match self.value {
Value::Null => self.wrap_err(visitor.visit_none()),
Value::Bool(b) => self.wrap_err(visitor.visit_bool(*b)),
Value::Number(Number::Integer(n)) => self.wrap_err(visitor.visit_i64(*n)),
Value::Number(Number::Float(n)) => self.wrap_err(visitor.visit_f64(*n)),
Value::String(s) => self.wrap_err(visitor.visit_str(s)),
Value::Sequence(_) => self.deserialize_seq(visitor),
Value::Mapping(_) => self.deserialize_map(visitor),
Value::Tagged(tagged) => {
if self.preserve_tags {
self.wrap_err(visitor.visit_map(crate::value::TagPreservingMapAccess::new(
tagged.tag().as_str(),
tagged.value(),
)))
} else {
let de = self.descend(tagged.value());
de.deserialize_any(visitor)
}
}
}
}
fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
match self.value {
Value::Bool(b) => self.wrap_err(visitor.visit_bool(*b)),
_ => self.wrap_err(Err(Error::TypeMismatch {
expected: "bool",
found: type_name(self.value),
})),
}
}
fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
self.deserialize_i64(visitor)
}
fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
self.deserialize_i64(visitor)
}
fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
self.deserialize_i64(visitor)
}
fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
match self.value {
Value::Number(Number::Integer(n)) => self.wrap_err(visitor.visit_i64(*n)),
Value::Number(Number::Float(n))
if n.fract() == 0.0
&& *n >= i64::MIN as f64
&& *n <= i64::MAX as f64
&& !n.is_nan() =>
{
self.wrap_err(visitor.visit_i64(*n as i64))
}
_ => self.wrap_err(Err(Error::TypeMismatch {
expected: "integer",
found: type_name(self.value),
})),
}
}
fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
self.deserialize_u64(visitor)
}
fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
self.deserialize_u64(visitor)
}
fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
self.deserialize_u64(visitor)
}
fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
match self.value {
Value::Number(Number::Integer(n)) if *n >= 0 => {
self.wrap_err(visitor.visit_u64(*n as u64))
}
Value::Number(Number::Float(n))
if n.fract() == 0.0 && *n >= 0.0 && *n <= u64::MAX as f64 && !n.is_nan() =>
{
self.wrap_err(visitor.visit_u64(*n as u64))
}
_ => self.wrap_err(Err(Error::TypeMismatch {
expected: "unsigned integer",
found: type_name(self.value),
})),
}
}
fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
self.deserialize_f64(visitor)
}
fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
match self.value {
Value::Number(Number::Float(n)) => self.wrap_err(visitor.visit_f64(*n)),
Value::Number(Number::Integer(n)) => self.wrap_err(visitor.visit_f64(*n as f64)),
_ => self.wrap_err(Err(Error::TypeMismatch {
expected: "float",
found: type_name(self.value),
})),
}
}
fn deserialize_char<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
match self.value {
Value::String(s) if s.chars().count() == 1 => {
self.wrap_err(visitor.visit_char(s.chars().next().unwrap()))
}
_ => self.wrap_err(Err(Error::TypeMismatch {
expected: "char",
found: type_name(self.value),
})),
}
}
fn deserialize_str<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
match self.value {
Value::String(s) => self.wrap_err(visitor.visit_str(s)),
Value::Tagged(boxed)
if self.ignore_binary_tag_for_string && is_binary_tag(boxed.tag().as_str()) =>
{
match boxed.value() {
Value::String(s) => self.wrap_err(visitor.visit_str(s)),
other => self.wrap_err(Err(Error::TypeMismatch {
expected: "string-shaped !!binary content",
found: type_name(other),
})),
}
}
_ => self.wrap_err(Err(Error::TypeMismatch {
expected: "string",
found: type_name(self.value),
})),
}
}
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
self.deserialize_str(visitor)
}
fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
match self.value {
Value::String(s) => self.wrap_err(visitor.visit_bytes(s.as_bytes())),
Value::Tagged(boxed) if is_binary_tag(boxed.tag().as_str()) => match boxed.value() {
Value::String(s) => match crate::base64::decode(s) {
Ok(bytes) => self.wrap_err(visitor.visit_byte_buf(bytes)),
Err(why) => self.wrap_err(Err(Error::Deserialize(format!("!!binary: {why}")))),
},
other => self.wrap_err(Err(Error::TypeMismatch {
expected: "string-shaped !!binary content",
found: type_name(other),
})),
},
_ => self.wrap_err(Err(Error::TypeMismatch {
expected: "bytes",
found: type_name(self.value),
})),
}
}
fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
self.deserialize_bytes(visitor)
}
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
match self.value {
Value::Null => self.wrap_err(visitor.visit_none()),
_ => self.wrap_err(visitor.visit_some(self)),
}
}
fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
match self.value {
Value::Null => self.wrap_err(visitor.visit_unit()),
_ => self.wrap_err(Err(Error::TypeMismatch {
expected: "null",
found: type_name(self.value),
})),
}
}
fn deserialize_unit_struct<V>(self, _name: &'static str, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
self.deserialize_unit(visitor)
}
fn deserialize_newtype_struct<V>(self, name: &'static str, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
if name == crate::spanned::SPANNED_TYPE_NAME {
return visitor.visit_map(SpannedMapAccess::new(self.value, self.span_ctx));
}
self.wrap_err(visitor.visit_newtype_struct(self))
}
fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
match self.value {
Value::Sequence(seq) => {
self.wrap_err(visitor.visit_seq(ValueSeqAccess::from_de(&self, seq)))
}
Value::Tagged(tagged) => self.descend(tagged.value()).deserialize_seq(visitor),
_ => self.wrap_err(Err(Error::TypeMismatch {
expected: "sequence",
found: type_name(self.value),
})),
}
}
fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
self.deserialize_seq(visitor)
}
fn deserialize_tuple_struct<V>(
self,
_name: &'static str,
_len: usize,
visitor: V,
) -> Result<V::Value>
where
V: Visitor<'de>,
{
self.deserialize_seq(visitor)
}
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
match self.value {
Value::Mapping(map) => {
self.wrap_err(visitor.visit_map(ValueMapAccess::from_de(&self, map)))
}
Value::Tagged(tagged) => self.descend(tagged.value()).deserialize_map(visitor),
_ => self.wrap_err(Err(Error::TypeMismatch {
expected: "mapping",
found: type_name(self.value),
})),
}
}
fn deserialize_struct<V>(
self,
name: &'static str,
_fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value>
where
V: Visitor<'de>,
{
if name == crate::spanned::SPANNED_TYPE_NAME {
return visitor.visit_map(SpannedMapAccess::new(self.value, self.span_ctx));
}
self.deserialize_map(visitor)
}
fn deserialize_enum<V>(
self,
_name: &'static str,
_variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value>
where
V: Visitor<'de>,
{
match self.value {
Value::String(variant) => {
let de: de::value::StrDeserializer<'de, Error> =
variant.as_str().into_deserializer();
self.wrap_err(visitor.visit_enum(de))
}
Value::Mapping(map) if map.len() == 1 => {
let (variant, value) = map.iter().next().unwrap();
self.wrap_err(visitor.visit_enum(EnumAccess {
variant,
value,
span_ctx: self.span_ctx,
}))
}
_ => self.wrap_err(Err(Error::TypeMismatch {
expected: "string or single-key mapping",
found: type_name(self.value),
})),
}
}
fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
match self.value {
Value::String(s) => self.wrap_err(visitor.visit_str(s)),
_ => self.deserialize_any(visitor),
}
}
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
self.wrap_err(visitor.visit_unit())
}
}
pub(crate) struct ValueSeqAccess<'de> {
iter: core::slice::Iter<'de, Value>,
span_ctx: Option<&'de span_context::SpanContext>,
ignore_binary_tag_for_string: bool,
preserve_tags: bool,
}
impl<'de> ValueSeqAccess<'de> {
pub(crate) fn from_de(de: &Deserializer<'de>, seq: &'de [Value]) -> Self {
ValueSeqAccess {
iter: seq.iter(),
span_ctx: de.span_ctx,
ignore_binary_tag_for_string: de.ignore_binary_tag_for_string,
preserve_tags: de.preserve_tags,
}
}
}
impl<'de> SeqAccess<'de> for ValueSeqAccess<'de> {
type Error = Error;
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
where
T: DeserializeSeed<'de>,
{
match self.iter.next() {
Some(value) => {
let de = Deserializer {
value,
span_ctx: self.span_ctx,
ignore_binary_tag_for_string: self.ignore_binary_tag_for_string,
preserve_tags: self.preserve_tags,
};
seed.deserialize(de).map(Some)
}
None => Ok(None),
}
}
}
pub(crate) struct ValueMapAccess<'de> {
iter: indexmap::map::Iter<'de, String, Value>,
value: Option<&'de Value>,
span_ctx: Option<&'de span_context::SpanContext>,
ignore_binary_tag_for_string: bool,
preserve_tags: bool,
}
impl<'de> ValueMapAccess<'de> {
pub(crate) fn from_de(de: &Deserializer<'de>, map: &'de crate::value::Mapping) -> Self {
ValueMapAccess {
iter: map.iter(),
value: None,
span_ctx: de.span_ctx,
ignore_binary_tag_for_string: de.ignore_binary_tag_for_string,
preserve_tags: de.preserve_tags,
}
}
fn child_de(&self, value: &'de Value) -> Deserializer<'de> {
Deserializer {
value,
span_ctx: self.span_ctx,
ignore_binary_tag_for_string: self.ignore_binary_tag_for_string,
preserve_tags: self.preserve_tags,
}
}
}
impl<'de> MapAccess<'de> for ValueMapAccess<'de> {
type Error = Error;
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
where
K: DeserializeSeed<'de>,
{
match self.iter.next() {
Some((key, value)) => {
self.value = Some(value);
let de = self.child_de(value);
let key_de: de::value::StrDeserializer<'de, Error> =
key.as_str().into_deserializer();
de.wrap_err(seed.deserialize(key_de).map(Some))
}
None => Ok(None),
}
}
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
where
V: DeserializeSeed<'de>,
{
match self.value.take() {
Some(value) => {
let de = self.child_de(value);
let res = seed.deserialize(de);
de.wrap_err(res)
}
None => Err(de::Error::custom("value is missing")),
}
}
}
struct EnumAccess<'de> {
variant: &'de str,
value: &'de Value,
span_ctx: Option<&'de span_context::SpanContext>,
}
impl<'de> de::EnumAccess<'de> for EnumAccess<'de> {
type Error = Error;
type Variant = VariantAccess<'de>;
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant)>
where
V: DeserializeSeed<'de>,
{
let de: de::value::StrDeserializer<'de, Error> = self.variant.into_deserializer();
let variant = seed.deserialize(de)?;
let visitor = VariantAccess {
value: self.value,
span_ctx: self.span_ctx,
};
Ok((variant, visitor))
}
}
struct VariantAccess<'de> {
value: &'de Value,
span_ctx: Option<&'de span_context::SpanContext>,
}
impl<'de> de::VariantAccess<'de> for VariantAccess<'de> {
type Error = Error;
fn unit_variant(self) -> Result<()> {
let de = if let Some(ctx) = self.span_ctx {
Deserializer::with_span_context(self.value, ctx)
} else {
Deserializer::new(self.value)
};
Deserialize::deserialize(de)
}
fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value>
where
T: DeserializeSeed<'de>,
{
let de = if let Some(ctx) = self.span_ctx {
Deserializer::with_span_context(self.value, ctx)
} else {
Deserializer::new(self.value)
};
seed.deserialize(de)
}
fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
let de = if let Some(ctx) = self.span_ctx {
Deserializer::with_span_context(self.value, ctx)
} else {
Deserializer::new(self.value)
};
de::Deserializer::deserialize_seq(de, visitor)
}
fn struct_variant<V>(self, _fields: &'static [&'static str], visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
let de = if let Some(ctx) = self.span_ctx {
Deserializer::with_span_context(self.value, ctx)
} else {
Deserializer::new(self.value)
};
de::Deserializer::deserialize_map(de, visitor)
}
}
pub(crate) struct SpannedMapAccess<'de> {
value: &'de Value,
span_ctx: Option<&'de span_context::SpanContext>,
fields: core::slice::Iter<'static, &'static str>,
}
impl<'de> SpannedMapAccess<'de> {
pub(crate) fn new(value: &'de Value, span_ctx: Option<&'de span_context::SpanContext>) -> Self {
SpannedMapAccess {
value,
span_ctx,
fields: crate::spanned::SPANNED_FIELDS.iter(),
}
}
}
impl<'de> MapAccess<'de> for SpannedMapAccess<'de> {
type Error = Error;
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
where
K: DeserializeSeed<'de>,
{
match self.fields.next() {
Some(field) => {
use serde::de::value::BorrowedStrDeserializer;
let de: BorrowedStrDeserializer<'_, Error> = BorrowedStrDeserializer::new(field);
seed.deserialize(de).map(Some)
}
None => Ok(None),
}
}
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
where
V: DeserializeSeed<'de>,
{
use crate::spanned::*;
let last_field = SPANNED_FIELDS[SPANNED_FIELDS.len() - 1 - (self.fields.len())];
if last_field == SPANNED_FIELD_VALUE {
let de = if let Some(ctx) = self.span_ctx {
Deserializer::with_span_context(self.value, ctx)
} else {
Deserializer::new(self.value)
};
return de.wrap_err(seed.deserialize(de));
}
let ptr: *const Value = self.value;
let addr = ptr as usize;
let span = self.span_ctx.and_then(|ctx| ctx.spans.get(&addr));
let loc = if let Some(s) = span {
crate::error::Location::from_index(&self.span_ctx.unwrap().source, s.0)
} else {
crate::error::Location::default()
};
let end_loc = if let Some(s) = span {
crate::error::Location::from_index(&self.span_ctx.unwrap().source, s.1)
} else {
crate::error::Location::default()
};
let val = match last_field {
SPANNED_FIELD_START_LINE => loc.line(),
SPANNED_FIELD_START_COLUMN => loc.column(),
SPANNED_FIELD_START_INDEX => loc.index(),
SPANNED_FIELD_END_LINE => end_loc.line(),
SPANNED_FIELD_END_COLUMN => end_loc.column(),
SPANNED_FIELD_END_INDEX => end_loc.index(),
_ => crate::error::invariant_violated(
"spanned-field index outside the SPANNED_FIELDS array",
),
};
seed.deserialize(val.into_deserializer())
}
}
pub(crate) fn is_binary_tag(tag: &str) -> bool {
matches!(
tag,
"!!binary" | "binary" | "tag:yaml.org,2002:binary" | "!<tag:yaml.org,2002:binary>"
)
}
fn type_name(value: &Value) -> String {
match value {
Value::Null => "null".to_owned(),
Value::Bool(_) => "bool".to_owned(),
Value::Number(Number::Integer(_)) => "integer".to_owned(),
Value::Number(Number::Float(_)) => "float".to_owned(),
Value::String(_) => "string".to_owned(),
Value::Sequence(_) => "sequence".to_owned(),
Value::Mapping(_) => "mapping".to_owned(),
Value::Tagged(tagged) => format!("tagged value (!{})", tagged.tag().as_str()),
}
}