use std::borrow::Cow;
use serde::de::value::{BorrowedStrDeserializer, StringDeserializer};
use serde::de::{
self, DeserializeSeed, EnumAccess, IntoDeserializer, MapAccess, SeqAccess, VariantAccess,
Visitor,
};
use serde::Deserialize;
use crate::error::{Error, Result};
use crate::tokens::{CTOR_SENTINEL, TOKEN_DATETIME, TOKEN_INT, TOKEN_IP, TOKEN_IPPORT, TOKEN_UINT};
pub fn from_str<'a, T: Deserialize<'a>>(input: &'a str) -> Result<T> {
from_slice(input.as_bytes())
}
pub fn from_slice<'a, T: Deserialize<'a>>(input: &'a [u8]) -> Result<T> {
let mut de = Deserializer::from_slice(input);
let value = T::deserialize(&mut de)?;
de.end()?;
Ok(value)
}
pub fn from_str_partial<'a, T: Deserialize<'a>>(input: &'a str) -> Result<(T, usize)> {
let mut de = Deserializer::from_slice(input.as_bytes());
let value = T::deserialize(&mut de)?;
de.skip_whitespace();
Ok((value, de.pos))
}
#[inline]
fn is_ident_start(b: u8) -> bool {
b.is_ascii_alphabetic() || b == b'_'
}
#[inline]
fn is_ident_continue(b: u8) -> bool {
b.is_ascii_alphanumeric() || b == b'_'
}
fn int_range(ty: &str) -> Option<(i128, i128)> {
Some(match ty {
"int" | "int64" => (i64::MIN as i128, i64::MAX as i128),
"uint" | "uint64" => (0, u64::MAX as i128),
"int8" => (i8::MIN as i128, i8::MAX as i128),
"int16" => (i16::MIN as i128, i16::MAX as i128),
"int32" => (i32::MIN as i128, i32::MAX as i128),
"uint8" => (0, u8::MAX as i128),
"uint16" => (0, u16::MAX as i128),
"uint32" => (0, u32::MAX as i128),
_ => return None,
})
}
fn parse_i128_str(s: &str) -> Option<i128> {
let (neg, digits) = match s.as_bytes().split_first() {
Some((b'-', rest)) => (true, rest),
Some((b'+', rest)) => (false, rest),
_ => (false, s.as_bytes()),
};
if digits.is_empty() {
return None;
}
let mut acc: i128 = 0;
for &b in digits {
let d = b.wrapping_sub(b'0');
if d > 9 {
return None;
}
acc = acc.checked_mul(10)?.checked_sub(d as i128)?;
}
if neg {
Some(acc)
} else {
acc.checked_neg()
}
}
#[inline]
fn scan_string_end(bytes: &[u8], from: usize) -> (usize, bool) {
let mut pos = from;
let mut non_ascii = 0u8;
while pos < bytes.len() {
let b = bytes[pos];
if (b == b'"') | (b == b'\\') | (b < 0x20) {
break;
}
non_ascii |= b;
pos += 1;
}
(pos, non_ascii < 0x80)
}
#[inline]
fn str_in_string(bytes: &[u8], offset: usize) -> Result<&str> {
std::str::from_utf8(bytes).map_err(|_| Error::syntax("invalid UTF-8 in string", offset))
}
#[inline]
fn str_run(bytes: &[u8], ascii: bool, offset: usize) -> Result<&str> {
if ascii {
debug_assert!(bytes.is_ascii());
Ok(unsafe { std::str::from_utf8_unchecked(bytes) })
} else {
str_in_string(bytes, offset)
}
}
const POW10: [f64; 23] = [
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16,
1e17, 1e18, 1e19, 1e20, 1e21, 1e22,
];
const MAX_DEPTH: usize = 128;
pub struct Deserializer<'de> {
input: &'de [u8],
pos: usize,
remaining_depth: usize,
}
impl<'de> Deserializer<'de> {
pub fn from_slice(input: &'de [u8]) -> Self {
Deserializer {
input,
pos: 0,
remaining_depth: MAX_DEPTH,
}
}
#[allow(clippy::should_implement_trait)]
pub fn from_str(input: &'de str) -> Self {
Deserializer::from_slice(input.as_bytes())
}
pub fn end(&mut self) -> Result<()> {
self.skip_whitespace();
if self.pos < self.input.len() {
Err(Error::TrailingData { offset: self.pos })
} else {
Ok(())
}
}
#[inline]
fn peek(&self) -> Option<u8> {
self.input.get(self.pos).copied()
}
#[inline]
fn peek_or_eof(&self) -> Result<u8> {
self.peek().ok_or(Error::Eof)
}
#[inline]
fn skip_whitespace(&mut self) {
let bytes = self.input;
let mut pos = self.pos;
while pos < bytes.len() && matches!(bytes[pos], b' ' | b'\t' | b'\n' | b'\r') {
pos += 1;
}
self.pos = pos;
}
#[inline]
fn skip_ws_or_eof(&mut self) -> Result<u8> {
let bytes = self.input;
let mut pos = self.pos;
while pos < bytes.len() {
let b = bytes[pos];
if b == b' ' || b == b'\t' || b == b'\n' || b == b'\r' {
pos += 1;
} else {
self.pos = pos;
return Ok(b);
}
}
self.pos = pos;
Err(Error::Eof)
}
fn error(&self, msg: impl Into<String>) -> Error {
Error::syntax(msg, self.pos)
}
fn expect_byte(&mut self, expected: u8, context: &str) -> Result<()> {
match self.skip_ws_or_eof()? {
b if b == expected => {
self.pos += 1;
Ok(())
}
b => Err(self.error(format!(
"expected '{}' {context}, found '{}'",
expected as char, b as char
))),
}
}
#[inline]
fn peek_ident(&self) -> &'de str {
let bytes = self.input;
let start = self.pos;
let mut end = start;
if end < bytes.len() && is_ident_start(bytes[end]) {
end += 1;
while end < bytes.len() && is_ident_continue(bytes[end]) {
end += 1;
}
}
debug_assert!(self.input[start..end].is_ascii());
unsafe { std::str::from_utf8_unchecked(&bytes[start..end]) }
}
fn parse_ident(&mut self) -> &'de str {
let ident = self.peek_ident();
self.pos += ident.len();
ident
}
fn read_key(&mut self) -> Result<Cow<'de, str>> {
match self.skip_ws_or_eof()? {
b'"' => self.parse_string(),
b if is_ident_start(b) => Ok(Cow::Borrowed(self.parse_ident())),
b => Err(self.error(format!("expected object key, found '{}'", b as char))),
}
}
#[inline]
fn parse_string(&mut self) -> Result<Cow<'de, str>> {
debug_assert_eq!(self.peek(), Some(b'"'));
let bytes = self.input;
let start = self.pos + 1;
let (stop, ascii) = scan_string_end(bytes, start);
if bytes.get(stop) == Some(&b'"') {
self.pos = stop + 1;
return Ok(Cow::Borrowed(str_run(&bytes[start..stop], ascii, start)?));
}
self.parse_string_cold(start, stop, ascii)
}
#[cold]
#[inline(never)]
fn parse_string_cold(&mut self, start: usize, stop: usize, ascii: bool) -> Result<Cow<'de, str>> {
let bytes = self.input;
self.pos = stop;
match bytes.get(stop) {
None => return Err(Error::Eof),
Some(&b) if b < 0x20 => {
return Err(self.error("control character must be escaped in string"))
}
_ => {} }
let mut out = String::new();
out.push_str(str_run(&bytes[start..stop], ascii, start)?);
loop {
let run_start = self.pos;
let (run_end, run_ascii) = scan_string_end(bytes, run_start);
if run_end > run_start {
out.push_str(str_run(&bytes[run_start..run_end], run_ascii, run_start)?);
self.pos = run_end;
}
match self.peek_or_eof()? {
b'"' => {
self.pos += 1;
return Ok(Cow::Owned(out));
}
b'\\' => {
self.pos += 1;
match self.peek_or_eof()? {
b'"' => out.push('"'),
b'\\' => out.push('\\'),
b'/' => out.push('/'),
b'b' => out.push('\u{0008}'),
b'f' => out.push('\u{000C}'),
b'n' => out.push('\n'),
b'r' => out.push('\r'),
b't' => out.push('\t'),
b'u' => {
self.pos += 1;
out.push(self.parse_unicode_escape()?);
continue;
}
b => {
return Err(self.error(format!("invalid escape '\\{}'", b as char)))
}
}
self.pos += 1;
}
b if b < 0x20 => {
return Err(self.error("control character must be escaped in string"))
}
_ => unreachable!("run loop stops only at quote, backslash, or control"),
}
}
}
fn read_hex4(&mut self) -> Result<u16> {
let mut value: u16 = 0;
for _ in 0..4 {
let b = self.peek_or_eof()?;
let digit = match b {
b'0'..=b'9' => b - b'0',
b'a'..=b'f' => b - b'a' + 10,
b'A'..=b'F' => b - b'A' + 10,
_ => return Err(self.error("invalid \\u escape: expected hex digit")),
};
value = value << 4 | digit as u16;
self.pos += 1;
}
Ok(value)
}
fn parse_unicode_escape(&mut self) -> Result<char> {
let hi = self.read_hex4()?;
if (0xD800..=0xDBFF).contains(&hi) {
if self.peek() == Some(b'\\') && self.input.get(self.pos + 1) == Some(&b'u') {
self.pos += 2;
let lo = self.read_hex4()?;
if (0xDC00..=0xDFFF).contains(&lo) {
let c = 0x10000 + ((hi - 0xD800) as u32) * 0x400 + (lo - 0xDC00) as u32;
return char::from_u32(c)
.ok_or_else(|| self.error("invalid unicode code point"));
}
}
return Err(self.error("unpaired high surrogate in \\u escape"));
}
if (0xDC00..=0xDFFF).contains(&hi) {
return Err(self.error("unexpected low surrogate in \\u escape"));
}
char::from_u32(hi as u32).ok_or_else(|| self.error("invalid unicode code point"))
}
fn parse_f64(&mut self) -> Result<f64> {
let bytes = self.input;
let len = bytes.len();
let start = self.pos;
let mut pos = start;
let neg = pos < len && bytes[pos] == b'-';
if neg {
pos += 1;
}
let mut significand: u64 = 0;
let mut n_digits: u32 = 0;
let mut decimal_exp: i64 = 0;
match bytes.get(pos) {
Some(b'0') => pos += 1,
Some(b'1'..=b'9') => {
while let Some(&d) = bytes.get(pos) {
if !d.is_ascii_digit() {
break;
}
significand = significand.wrapping_mul(10).wrapping_add((d - b'0') as u64);
n_digits += 1;
pos += 1;
}
}
_ => {
self.pos = pos;
return Err(self.error("invalid number: expected digit"));
}
}
if pos < len && bytes[pos] == b'.' {
pos += 1;
let frac_start = pos;
while let Some(&d) = bytes.get(pos) {
if !d.is_ascii_digit() {
break;
}
significand = significand.wrapping_mul(10).wrapping_add((d - b'0') as u64);
n_digits += 1;
decimal_exp -= 1;
pos += 1;
}
if pos == frac_start {
self.pos = pos;
return Err(self.error("invalid number: expected digit after decimal point"));
}
}
if pos < len && matches!(bytes[pos], b'e' | b'E') {
pos += 1;
let exp_neg = pos < len && bytes[pos] == b'-';
if pos < len && matches!(bytes[pos], b'+' | b'-') {
pos += 1;
}
let exp_start = pos;
let mut e: i64 = 0;
while let Some(&d) = bytes.get(pos) {
if !d.is_ascii_digit() {
break;
}
e = e.saturating_mul(10).saturating_add((d - b'0') as i64);
pos += 1;
}
if pos == exp_start {
self.pos = pos;
return Err(self.error("invalid number: expected digit in exponent"));
}
decimal_exp = if exp_neg {
decimal_exp.saturating_sub(e)
} else {
decimal_exp.saturating_add(e)
};
}
self.pos = pos;
if n_digits <= 15 && (-22..=22).contains(&decimal_exp) {
let mag = significand as f64;
let mag = if decimal_exp >= 0 {
mag * POW10[decimal_exp as usize]
} else {
mag / POW10[(-decimal_exp) as usize]
};
return Ok(if neg { -mag } else { mag });
}
let text = unsafe { std::str::from_utf8_unchecked(&bytes[start..pos]) };
let value = text
.parse::<f64>()
.map_err(|_| Error::syntax(format!("invalid number '{text}'"), start))?;
if !value.is_finite() {
return Err(Error::syntax(format!("number '{text}' is out of range"), start));
}
Ok(value)
}
fn read_bracket_arg(&mut self) -> Result<Cow<'de, str>> {
self.expect_byte(b'(', "after type name")?;
match self.skip_ws_or_eof()? {
b'"' => {
let s = self.parse_string()?;
self.expect_byte(b')', "to close type constructor")?;
Ok(s)
}
_ => {
let bytes = self.input;
let start = self.pos;
let mut pos = start;
while pos < bytes.len() && bytes[pos] != b')' {
pos += 1;
}
if pos >= bytes.len() {
self.pos = pos;
return Err(Error::Eof);
}
let slice = &bytes[start..pos];
self.pos = pos + 1; let s = std::str::from_utf8(slice)
.map_err(|_| self.error("invalid UTF-8 in type constructor"))?;
Ok(Cow::Borrowed(s.trim()))
}
}
}
fn finish_typed_int(&mut self, ty: &str) -> Result<i128> {
let (min, max) = int_range(ty)
.ok_or_else(|| self.error(format!("'{ty}' is not a valid value")))?;
let arg = self.read_bracket_arg()?;
let text = arg.trim();
let n = parse_i128_str(text)
.ok_or_else(|| self.error(format!("invalid integer literal '{text}' for {ty}")))?;
if n < min || n > max {
return Err(self.error(format!("integer {n} out of range for {ty}")));
}
Ok(n)
}
fn read_integer(&mut self) -> Result<i128> {
match self.skip_ws_or_eof()? {
b if is_ident_start(b) => {
let ident = self.parse_ident();
self.finish_typed_int(ident)
}
b'-' | b'0'..=b'9' => self.parse_int_literal(),
b => Err(self.error(format!("expected an integer, found '{}'", b as char))),
}
}
fn parse_int_literal(&mut self) -> Result<i128> {
let bytes = self.input;
let start = self.pos;
let mut pos = start;
let neg = bytes[pos] == b'-';
if neg {
pos += 1;
}
let first = match bytes.get(pos) {
Some(&d @ b'0'..=b'9') => d,
_ => {
self.pos = pos;
return Err(self.error("invalid number: expected digit"));
}
};
pos += 1;
let mut acc = -((first - b'0') as i64);
if first != b'0' {
while let Some(&d) = bytes.get(pos) {
if !d.is_ascii_digit() {
break;
}
match acc.checked_mul(10).and_then(|a| a.checked_sub((d - b'0') as i64)) {
Some(v) => acc = v,
None => return self.parse_int_literal_wide(start, neg),
}
pos += 1;
}
}
if matches!(bytes.get(pos), Some(b'.' | b'e' | b'E')) {
self.pos = pos;
return Err(self.error("expected an integer, found a floating-point number"));
}
self.pos = pos;
Ok(if neg {
acc as i128
} else {
match acc.checked_neg() {
Some(v) => v as i128,
None => -(acc as i128),
}
})
}
#[cold]
#[inline(never)]
fn parse_int_literal_wide(&mut self, start: usize, neg: bool) -> Result<i128> {
let bytes = self.input;
let mut pos = if neg { start + 1 } else { start };
let mut acc: i128 = 0;
while let Some(&d) = bytes.get(pos) {
if !d.is_ascii_digit() {
break;
}
acc = acc
.checked_mul(10)
.and_then(|a| a.checked_sub((d - b'0') as i128))
.ok_or_else(|| self.error("integer literal out of range"))?;
pos += 1;
}
if matches!(bytes.get(pos), Some(b'.' | b'e' | b'E')) {
self.pos = pos;
return Err(self.error("expected an integer, found a floating-point number"));
}
self.pos = pos;
if neg {
Ok(acc)
} else {
acc.checked_neg()
.ok_or_else(|| self.error("integer literal out of range"))
}
}
fn read_extended_arg(&mut self, expected: &str) -> Result<String> {
match self.skip_ws_or_eof()? {
b'"' => Ok(self.parse_string()?.into_owned()),
b if is_ident_start(b) => {
let ident = self.parse_ident();
if ident != expected {
return Err(self.error(format!("expected '{expected}(...)', found '{ident}'")));
}
Ok(self.read_bracket_arg()?.into_owned())
}
b => Err(self.error(format!(
"expected '{expected}(...)' or a string, found '{}'",
b as char
))),
}
}
}
macro_rules! deserialize_integer {
($method:ident, $visit:ident, $ty:ty) => {
fn $method<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
let n = self.read_integer()?;
let v = <$ty>::try_from(n)
.map_err(|_| self.error(format!("integer {n} out of range for {}", stringify!($ty))))?;
visitor.$visit(v)
}
};
}
impl<'de> de::Deserializer<'de> for &mut Deserializer<'de> {
type Error = Error;
fn deserialize_any<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
match self.skip_ws_or_eof()? {
b'"' => match self.parse_string()? {
Cow::Borrowed(s) => visitor.visit_borrowed_str(s),
Cow::Owned(s) => visitor.visit_string(s),
},
b'{' => {
self.pos += 1;
self.parse_object(visitor)
}
b'[' => {
self.pos += 1;
self.parse_array(visitor)
}
b'-' | b'0'..=b'9' => {
let n = self.parse_f64()?;
visitor.visit_f64(n)
}
b if is_ident_start(b) => {
let ident = self.parse_ident();
match ident {
"true" => visitor.visit_bool(true),
"false" => visitor.visit_bool(false),
"null" => visitor.visit_unit(),
"int8" => visitor.visit_i8(self.finish_typed_int(ident)? as i8),
"int16" => visitor.visit_i16(self.finish_typed_int(ident)? as i16),
"int32" => visitor.visit_i32(self.finish_typed_int(ident)? as i32),
"int64" => visitor.visit_i64(self.finish_typed_int(ident)? as i64),
"uint8" => visitor.visit_u8(self.finish_typed_int(ident)? as u8),
"uint16" => visitor.visit_u16(self.finish_typed_int(ident)? as u16),
"uint32" => visitor.visit_u32(self.finish_typed_int(ident)? as u32),
"uint64" => visitor.visit_u64(self.finish_typed_int(ident)? as u64),
"int" => {
let n = self.finish_typed_int(ident)? as i64;
visitor.visit_map(TokenMap::new(TOKEN_INT, n.into_deserializer()))
}
"uint" => {
let n = self.finish_typed_int(ident)? as u64;
visitor.visit_map(TokenMap::new(TOKEN_UINT, n.into_deserializer()))
}
"datetime" => {
let s = self.read_bracket_arg()?.into_owned();
visitor.visit_map(TokenMap::new(TOKEN_DATETIME, s.into_deserializer()))
}
"ip" => {
let s = self.read_bracket_arg()?.into_owned();
visitor.visit_map(TokenMap::new(TOKEN_IP, s.into_deserializer()))
}
"ipport" => {
let s = self.read_bracket_arg()?.into_owned();
visitor.visit_map(TokenMap::new(TOKEN_IPPORT, s.into_deserializer()))
}
"bytes" => {
let arg = self.read_bracket_arg()?;
let bytes = crate::base64::decode(arg.trim())
.map_err(|_| self.error("invalid base64 in bytes(...)"))?;
visitor.visit_byte_buf(bytes)
}
other => {
let name = other.to_owned();
self.enter()?;
self.expect_byte(b'(', "after constructor name")?;
let value = visitor.visit_map(CtorMap::new(name, &mut *self))?;
self.expect_byte(b')', "to close constructor")?;
self.remaining_depth += 1;
Ok(value)
}
}
}
b => Err(self.error(format!("unexpected character '{}'", b as char))),
}
}
deserialize_integer!(deserialize_i8, visit_i8, i8);
deserialize_integer!(deserialize_i16, visit_i16, i16);
deserialize_integer!(deserialize_i32, visit_i32, i32);
deserialize_integer!(deserialize_i64, visit_i64, i64);
deserialize_integer!(deserialize_i128, visit_i128, i128);
deserialize_integer!(deserialize_u8, visit_u8, u8);
deserialize_integer!(deserialize_u16, visit_u16, u16);
deserialize_integer!(deserialize_u32, visit_u32, u32);
deserialize_integer!(deserialize_u64, visit_u64, u64);
deserialize_integer!(deserialize_u128, visit_u128, u128);
fn deserialize_bool<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
match self.skip_ws_or_eof()? {
b if is_ident_start(b) => match self.parse_ident() {
"true" => visitor.visit_bool(true),
"false" => visitor.visit_bool(false),
other => Err(self.error(format!("expected a boolean, found '{other}'"))),
},
b => Err(self.error(format!("expected a boolean, found '{}'", b as char))),
}
}
fn deserialize_f32<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
let n = self.read_float()?;
visitor.visit_f32(n as f32)
}
fn deserialize_f64<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
let n = self.read_float()?;
visitor.visit_f64(n)
}
fn deserialize_char<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
self.skip_whitespace();
if self.peek() != Some(b'"') {
return Err(self.error("expected a single-character string"));
}
let s = self.parse_string()?;
let mut chars = s.chars();
match (chars.next(), chars.next()) {
(Some(c), None) => visitor.visit_char(c),
_ => Err(self.error("expected a single-character string")),
}
}
fn deserialize_str<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
match self.skip_ws_or_eof()? {
b'"' => match self.parse_string()? {
Cow::Borrowed(s) => visitor.visit_borrowed_str(s),
Cow::Owned(s) => visitor.visit_string(s),
},
b => Err(self.error(format!("expected a string, found '{}'", b as char))),
}
}
fn deserialize_string<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
self.deserialize_str(visitor)
}
fn deserialize_bytes<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
let bytes = self.read_bytes()?;
visitor.visit_byte_buf(bytes)
}
fn deserialize_byte_buf<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
let bytes = self.read_bytes()?;
visitor.visit_byte_buf(bytes)
}
fn deserialize_option<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
self.skip_whitespace();
if self.peek().map(is_ident_start).unwrap_or(false) && self.peek_ident() == "null" {
self.pos += 4;
visitor.visit_none()
} else {
visitor.visit_some(self)
}
}
fn deserialize_unit<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
match self.skip_ws_or_eof()? {
b if is_ident_start(b) => match self.parse_ident() {
"null" => visitor.visit_unit(),
other => Err(self.error(format!("expected null, found '{other}'"))),
},
b => Err(self.error(format!("expected null, found '{}'", b as char))),
}
}
fn deserialize_unit_struct<V: Visitor<'de>>(
self,
_name: &'static str,
visitor: V,
) -> Result<V::Value> {
self.deserialize_unit(visitor)
}
fn deserialize_newtype_struct<V: Visitor<'de>>(
self,
name: &'static str,
visitor: V,
) -> Result<V::Value> {
match crate::tokens::strip_ctor(name) {
Some(ctor) => {
let s = self.read_extended_arg(ctor)?;
visitor.visit_newtype_struct(string_deserializer(s))
}
None => visitor.visit_newtype_struct(self),
}
}
fn deserialize_seq<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
self.expect_byte(b'[', "to begin an array")?;
self.parse_array(visitor)
}
fn deserialize_tuple<V: Visitor<'de>>(self, _len: usize, visitor: V) -> Result<V::Value> {
self.deserialize_seq(visitor)
}
fn deserialize_tuple_struct<V: Visitor<'de>>(
self,
_name: &'static str,
_len: usize,
visitor: V,
) -> Result<V::Value> {
self.deserialize_seq(visitor)
}
fn deserialize_map<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
self.expect_byte(b'{', "to begin an object")?;
self.parse_object(visitor)
}
fn deserialize_struct<V: Visitor<'de>>(
self,
_name: &'static str,
_fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value> {
self.deserialize_map(visitor)
}
fn deserialize_enum<V: Visitor<'de>>(
self,
_name: &'static str,
_variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value> {
match self.skip_ws_or_eof()? {
b'{' => {
self.pos += 1;
let value = visitor.visit_enum(EnumObjectAccess { de: &mut *self })?;
self.expect_byte(b'}', "to close enum variant")?;
Ok(value)
}
b'"' => {
let variant = self.parse_string()?;
visitor.visit_enum(variant.into_deserializer())
}
b if is_ident_start(b) => {
let variant = self.parse_ident();
visitor.visit_enum(variant.into_deserializer())
}
b => Err(self.error(format!("expected an enum variant, found '{}'", b as char))),
}
}
fn deserialize_identifier<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
match self.skip_ws_or_eof()? {
b'"' => match self.parse_string()? {
Cow::Borrowed(s) => visitor.visit_borrowed_str(s),
Cow::Owned(s) => visitor.visit_string(s),
},
b if is_ident_start(b) => visitor.visit_borrowed_str(self.parse_ident()),
b => Err(self.error(format!("expected an identifier, found '{}'", b as char))),
}
}
fn deserialize_ignored_any<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
self.deserialize_any(visitor)
}
}
impl<'de> Deserializer<'de> {
fn enter(&mut self) -> Result<()> {
self.remaining_depth = self
.remaining_depth
.checked_sub(1)
.ok_or_else(|| self.error("nesting too deep"))?;
Ok(())
}
fn parse_array<V: Visitor<'de>>(&mut self, visitor: V) -> Result<V::Value> {
self.enter()?;
let value = visitor.visit_seq(ContainerAccess::new(self))?;
self.finish_container(b']')?;
self.remaining_depth += 1;
Ok(value)
}
fn parse_object<V: Visitor<'de>>(&mut self, visitor: V) -> Result<V::Value> {
self.enter()?;
let value = visitor.visit_map(ContainerAccess::new(self))?;
self.finish_container(b'}')?;
self.remaining_depth += 1;
Ok(value)
}
fn finish_container(&mut self, end: u8) -> Result<()> {
self.skip_whitespace();
if self.peek() == Some(b',') {
self.pos += 1;
self.skip_whitespace();
}
match self.peek() {
Some(b) if b == end => {
self.pos += 1;
Ok(())
}
Some(b) => Err(self.error(format!(
"expected '{}' to close container, found '{}'",
end as char, b as char
))),
None => Err(Error::Eof),
}
}
fn read_float(&mut self) -> Result<f64> {
match self.skip_ws_or_eof()? {
b if is_ident_start(b) => {
let ident = self.parse_ident();
Ok(self.finish_typed_int(ident)? as f64)
}
b'-' | b'0'..=b'9' => self.parse_f64(),
b => Err(self.error(format!("expected a number, found '{}'", b as char))),
}
}
fn read_bytes(&mut self) -> Result<Vec<u8>> {
let arg = match self.skip_ws_or_eof()? {
b'"' => self.parse_string()?.into_owned(),
b if is_ident_start(b) => {
let ident = self.parse_ident();
if ident != "bytes" {
return Err(self.error(format!("expected 'bytes(...)', found '{ident}'")));
}
self.read_bracket_arg()?.into_owned()
}
b => return Err(self.error(format!("expected bytes, found '{}'", b as char))),
};
crate::base64::decode(arg.trim()).map_err(|_| self.error("invalid base64 in bytes(...)"))
}
}
fn string_deserializer(s: String) -> StringDeserializer<Error> {
s.into_deserializer()
}
struct ContainerAccess<'a, 'de> {
de: &'a mut Deserializer<'de>,
first: bool,
}
impl<'a, 'de> ContainerAccess<'a, 'de> {
fn new(de: &'a mut Deserializer<'de>) -> Self {
ContainerAccess { de, first: true }
}
fn advance(&mut self, end: u8) -> Result<bool> {
let b = self.de.skip_ws_or_eof()?;
if self.first {
self.first = false;
Ok(b != end)
} else if b == end {
Ok(false)
} else if b == b',' {
self.de.pos += 1;
match self.de.skip_ws_or_eof()? {
c if c == end => Ok(false),
_ => Ok(true),
}
} else {
Err(self.de.error(format!(
"expected ',' or '{}', found '{}'",
end as char, b as char
)))
}
}
}
impl<'a, 'de> SeqAccess<'de> for ContainerAccess<'a, 'de> {
type Error = Error;
fn next_element_seed<T: DeserializeSeed<'de>>(&mut self, seed: T) -> Result<Option<T::Value>> {
if !self.advance(b']')? {
return Ok(None);
}
seed.deserialize(&mut *self.de).map(Some)
}
}
impl<'a, 'de> MapAccess<'de> for ContainerAccess<'a, 'de> {
type Error = Error;
fn next_key_seed<K: DeserializeSeed<'de>>(&mut self, seed: K) -> Result<Option<K::Value>> {
if !self.advance(b'}')? {
return Ok(None);
}
seed.deserialize(MapKey { de: &mut *self.de }).map(Some)
}
fn next_value_seed<V: DeserializeSeed<'de>>(&mut self, seed: V) -> Result<V::Value> {
self.de.expect_byte(b':', "after object key")?;
seed.deserialize(&mut *self.de)
}
}
struct MapKey<'a, 'de> {
de: &'a mut Deserializer<'de>,
}
macro_rules! mapkey_integer {
($method:ident, $visit:ident, $ty:ty) => {
fn $method<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
let key = self.de.read_key()?;
let n: $ty = key
.parse()
.map_err(|_| self.de.error(format!("invalid {} key '{key}'", stringify!($ty))))?;
visitor.$visit(n)
}
};
}
impl<'a, 'de> de::Deserializer<'de> for MapKey<'a, 'de> {
type Error = Error;
fn deserialize_any<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
match self.de.read_key()? {
Cow::Borrowed(s) => visitor.visit_borrowed_str(s),
Cow::Owned(s) => visitor.visit_string(s),
}
}
mapkey_integer!(deserialize_i8, visit_i8, i8);
mapkey_integer!(deserialize_i16, visit_i16, i16);
mapkey_integer!(deserialize_i32, visit_i32, i32);
mapkey_integer!(deserialize_i64, visit_i64, i64);
mapkey_integer!(deserialize_u8, visit_u8, u8);
mapkey_integer!(deserialize_u16, visit_u16, u16);
mapkey_integer!(deserialize_u32, visit_u32, u32);
mapkey_integer!(deserialize_u64, visit_u64, u64);
fn deserialize_bool<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
match self.de.read_key()?.as_ref() {
"true" => visitor.visit_bool(true),
"false" => visitor.visit_bool(false),
other => Err(self.de.error(format!("invalid boolean key '{other}'"))),
}
}
fn deserialize_enum<V: Visitor<'de>>(
self,
_name: &'static str,
_variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value> {
let key = self.de.read_key()?.into_owned();
visitor.visit_enum(key.into_deserializer())
}
serde::forward_to_deserialize_any! {
f32 f64 char str string bytes byte_buf option unit unit_struct
newtype_struct seq tuple tuple_struct map struct identifier ignored_any
i128 u128
}
}
struct TokenMap<P> {
key: Option<&'static str>,
value: Option<P>,
}
impl<P> TokenMap<P> {
fn new(key: &'static str, value: P) -> Self {
TokenMap {
key: Some(key),
value: Some(value),
}
}
}
impl<'de, P: de::Deserializer<'de, Error = Error>> MapAccess<'de> for TokenMap<P> {
type Error = Error;
fn next_key_seed<K: DeserializeSeed<'de>>(&mut self, seed: K) -> Result<Option<K::Value>> {
match self.key.take() {
Some(key) => seed
.deserialize(BorrowedStrDeserializer::new(key))
.map(Some),
None => Ok(None),
}
}
fn next_value_seed<V: DeserializeSeed<'de>>(&mut self, seed: V) -> Result<V::Value> {
let value = self.value.take().expect("value requested before key");
seed.deserialize(value)
}
}
struct CtorMap<'a, 'de> {
de: &'a mut Deserializer<'de>,
key: Option<String>,
}
impl<'a, 'de> CtorMap<'a, 'de> {
fn new(name: String, de: &'a mut Deserializer<'de>) -> Self {
CtorMap {
de,
key: Some(format!("{CTOR_SENTINEL}{name}")),
}
}
}
impl<'a, 'de> MapAccess<'de> for CtorMap<'a, 'de> {
type Error = Error;
fn next_key_seed<K: DeserializeSeed<'de>>(&mut self, seed: K) -> Result<Option<K::Value>> {
match self.key.take() {
Some(key) => seed.deserialize(string_deserializer(key)).map(Some),
None => Ok(None),
}
}
fn next_value_seed<V: DeserializeSeed<'de>>(&mut self, seed: V) -> Result<V::Value> {
self.de.skip_whitespace();
seed.deserialize(&mut *self.de)
}
}
struct EnumObjectAccess<'a, 'de> {
de: &'a mut Deserializer<'de>,
}
impl<'a, 'de> EnumAccess<'de> for EnumObjectAccess<'a, 'de> {
type Error = Error;
type Variant = Self;
fn variant_seed<V: DeserializeSeed<'de>>(self, seed: V) -> Result<(V::Value, Self)> {
let variant = seed.deserialize(MapKey { de: &mut *self.de })?;
self.de.expect_byte(b':', "after enum variant name")?;
self.de.skip_whitespace();
Ok((variant, self))
}
}
impl<'a, 'de> VariantAccess<'de> for EnumObjectAccess<'a, 'de> {
type Error = Error;
fn unit_variant(self) -> Result<()> {
Err(self
.de
.error("expected a string for a unit enum variant"))
}
fn newtype_variant_seed<T: DeserializeSeed<'de>>(self, seed: T) -> Result<T::Value> {
seed.deserialize(&mut *self.de)
}
fn tuple_variant<V: Visitor<'de>>(self, _len: usize, visitor: V) -> Result<V::Value> {
de::Deserializer::deserialize_seq(&mut *self.de, visitor)
}
fn struct_variant<V: Visitor<'de>>(
self,
_fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value> {
de::Deserializer::deserialize_map(&mut *self.de, visitor)
}
}