Use custom struct/field naming to deserialize spans
This commit is contained in:
parent
6db43965f9
commit
6b919f8833
|
@ -40,8 +40,8 @@ pub struct DatetimeParseError {
|
||||||
//
|
//
|
||||||
// In general the TOML encoder/decoder will catch this and not literally emit
|
// In general the TOML encoder/decoder will catch this and not literally emit
|
||||||
// these strings but rather emit datetimes as they're intended.
|
// these strings but rather emit datetimes as they're intended.
|
||||||
pub const SERDE_STRUCT_FIELD_NAME: &'static str = "$__toml_private_datetime";
|
pub const FIELD: &'static str = "$__toml_private_datetime";
|
||||||
pub const SERDE_STRUCT_NAME: &'static str = "$__toml_private_Datetime";
|
pub const NAME: &'static str = "$__toml_private_Datetime";
|
||||||
|
|
||||||
#[derive(PartialEq, Clone)]
|
#[derive(PartialEq, Clone)]
|
||||||
struct Date {
|
struct Date {
|
||||||
|
@ -311,8 +311,8 @@ impl ser::Serialize for Datetime {
|
||||||
{
|
{
|
||||||
use serde::ser::SerializeStruct;
|
use serde::ser::SerializeStruct;
|
||||||
|
|
||||||
let mut s = serializer.serialize_struct(SERDE_STRUCT_NAME, 1)?;
|
let mut s = serializer.serialize_struct(NAME, 1)?;
|
||||||
s.serialize_field(SERDE_STRUCT_FIELD_NAME, &self.to_string())?;
|
s.serialize_field(FIELD, &self.to_string())?;
|
||||||
s.end()
|
s.end()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -343,10 +343,8 @@ impl<'de> de::Deserialize<'de> for Datetime {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static FIELDS: [&'static str; 1] = [SERDE_STRUCT_FIELD_NAME];
|
static FIELDS: [&'static str; 1] = [FIELD];
|
||||||
deserializer.deserialize_struct(SERDE_STRUCT_NAME,
|
deserializer.deserialize_struct(NAME, &FIELDS, DatetimeVisitor)
|
||||||
&FIELDS,
|
|
||||||
DatetimeVisitor)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -368,7 +366,7 @@ impl<'de> de::Deserialize<'de> for DatetimeKey {
|
||||||
fn visit_str<E>(self, s: &str) -> Result<(), E>
|
fn visit_str<E>(self, s: &str) -> Result<(), E>
|
||||||
where E: de::Error
|
where E: de::Error
|
||||||
{
|
{
|
||||||
if s == SERDE_STRUCT_FIELD_NAME {
|
if s == FIELD {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(de::Error::custom("expected field with custom name"))
|
Err(de::Error::custom("expected field with custom name"))
|
||||||
|
|
76
src/de.rs
76
src/de.rs
|
@ -14,7 +14,7 @@ use serde::de;
|
||||||
use serde::de::IntoDeserializer;
|
use serde::de::IntoDeserializer;
|
||||||
|
|
||||||
use tokens::{Tokenizer, Token, Error as TokenError, Span};
|
use tokens::{Tokenizer, Token, Error as TokenError, Span};
|
||||||
use datetime::{SERDE_STRUCT_FIELD_NAME, SERDE_STRUCT_NAME};
|
use datetime;
|
||||||
use spanned;
|
use spanned;
|
||||||
|
|
||||||
/// Deserializes a byte slice into a type.
|
/// Deserializes a byte slice into a type.
|
||||||
|
@ -536,7 +536,7 @@ impl<'de> de::Deserializer<'de> for ValueDeserializer<'de> {
|
||||||
visitor: V) -> Result<V::Value, Error>
|
visitor: V) -> Result<V::Value, Error>
|
||||||
where V: de::Visitor<'de>,
|
where V: de::Visitor<'de>,
|
||||||
{
|
{
|
||||||
if name == SERDE_STRUCT_NAME && fields == &[SERDE_STRUCT_FIELD_NAME] {
|
if name == datetime::NAME && fields == &[datetime::FIELD] {
|
||||||
if let E::Datetime(s) = self.value.e {
|
if let E::Datetime(s) = self.value.e {
|
||||||
return visitor.visit_map(DatetimeDeserializer {
|
return visitor.visit_map(DatetimeDeserializer {
|
||||||
date: s,
|
date: s,
|
||||||
|
@ -545,9 +545,10 @@ impl<'de> de::Deserializer<'de> for ValueDeserializer<'de> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if name == spanned::NAME && fields == spanned::FIELDS {
|
if name == spanned::NAME && fields == &[spanned::START, spanned::END, spanned::VALUE] {
|
||||||
let start = self.value.start;
|
let start = self.value.start;
|
||||||
let end = self.value.end;
|
let end = self.value.end;
|
||||||
|
|
||||||
return visitor.visit_map(SpannedDeserializer {
|
return visitor.visit_map(SpannedDeserializer {
|
||||||
start: Some(start),
|
start: Some(start),
|
||||||
value: Some(self.value),
|
value: Some(self.value),
|
||||||
|
@ -607,8 +608,8 @@ impl<'de> de::IntoDeserializer<'de, Error> for Value<'de> {
|
||||||
|
|
||||||
struct SpannedDeserializer<'a> {
|
struct SpannedDeserializer<'a> {
|
||||||
start: Option<usize>,
|
start: Option<usize>,
|
||||||
value: Option<Value<'a>>,
|
|
||||||
end: Option<usize>,
|
end: Option<usize>,
|
||||||
|
value: Option<Value<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de> de::MapAccess<'de> for SpannedDeserializer<'de> {
|
impl<'de> de::MapAccess<'de> for SpannedDeserializer<'de> {
|
||||||
|
@ -619,11 +620,11 @@ impl<'de> de::MapAccess<'de> for SpannedDeserializer<'de> {
|
||||||
K: de::DeserializeSeed<'de>,
|
K: de::DeserializeSeed<'de>,
|
||||||
{
|
{
|
||||||
if self.start.is_some() {
|
if self.start.is_some() {
|
||||||
seed.deserialize("start".into_deserializer()).map(Some)
|
seed.deserialize(spanned::START.into_deserializer()).map(Some)
|
||||||
} else if self.value.is_some() {
|
|
||||||
seed.deserialize("value".into_deserializer()).map(Some)
|
|
||||||
} else if self.end.is_some() {
|
} else if self.end.is_some() {
|
||||||
seed.deserialize("end".into_deserializer()).map(Some)
|
seed.deserialize(spanned::END.into_deserializer()).map(Some)
|
||||||
|
} else if self.value.is_some() {
|
||||||
|
seed.deserialize(spanned::VALUE.into_deserializer()).map(Some)
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
@ -635,10 +636,10 @@ impl<'de> de::MapAccess<'de> for SpannedDeserializer<'de> {
|
||||||
{
|
{
|
||||||
if let Some(start) = self.start.take() {
|
if let Some(start) = self.start.take() {
|
||||||
seed.deserialize(start.into_deserializer())
|
seed.deserialize(start.into_deserializer())
|
||||||
} else if let Some(value) = self.value.take() {
|
|
||||||
seed.deserialize(value.into_deserializer())
|
|
||||||
} else if let Some(end) = self.end.take() {
|
} else if let Some(end) = self.end.take() {
|
||||||
seed.deserialize(end.into_deserializer())
|
seed.deserialize(end.into_deserializer())
|
||||||
|
} else if let Some(value) = self.value.take() {
|
||||||
|
seed.deserialize(value.into_deserializer())
|
||||||
} else {
|
} else {
|
||||||
panic!("next_value_seed called before next_key_seed")
|
panic!("next_value_seed called before next_key_seed")
|
||||||
}
|
}
|
||||||
|
@ -678,7 +679,7 @@ impl<'de> de::Deserializer<'de> for DatetimeFieldDeserializer {
|
||||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error>
|
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error>
|
||||||
where V: de::Visitor<'de>,
|
where V: de::Visitor<'de>,
|
||||||
{
|
{
|
||||||
visitor.visit_borrowed_str(SERDE_STRUCT_FIELD_NAME)
|
visitor.visit_borrowed_str(datetime::FIELD)
|
||||||
}
|
}
|
||||||
|
|
||||||
forward_to_deserialize_any! {
|
forward_to_deserialize_any! {
|
||||||
|
@ -811,21 +812,25 @@ impl<'a> Deserializer<'a> {
|
||||||
let at = self.tokens.current();
|
let at = self.tokens.current();
|
||||||
let value = match self.next()? {
|
let value = match self.next()? {
|
||||||
Some((Span { start, end }, Token::String { val, .. })) => {
|
Some((Span { start, end }, Token::String { val, .. })) => {
|
||||||
Value { e: E::String(val), start, end }
|
Value { e: E::String(val), start: start, end: end }
|
||||||
}
|
}
|
||||||
Some((Span { start, end }, Token::Keylike("true"))) => {
|
Some((Span { start, end }, Token::Keylike("true"))) => {
|
||||||
Value { e: E::Boolean(true), start, end }
|
Value { e: E::Boolean(true), start: start, end: end }
|
||||||
}
|
}
|
||||||
Some((Span { start, end }, Token::Keylike("false"))) => {
|
Some((Span { start, end }, Token::Keylike("false"))) => {
|
||||||
Value { e: E::Boolean(false), start, end }
|
Value { e: E::Boolean(false), start: start, end: end }
|
||||||
}
|
}
|
||||||
Some((_, Token::Keylike(key))) => self.number_or_date(key)?,
|
Some((span, Token::Keylike(key))) => self.number_or_date(span, key)?,
|
||||||
Some((_, Token::Plus)) => self.number_leading_plus()?,
|
Some((_, Token::Plus)) => self.number_leading_plus()?,
|
||||||
Some((Span { start, end }, Token::LeftBrace)) => {
|
Some((Span { start, end }, Token::LeftBrace)) => {
|
||||||
self.inline_table().map(|table| Value { e: E::InlineTable(table), start, end })?
|
self.inline_table().map(|table| Value {
|
||||||
|
e: E::InlineTable(table),
|
||||||
|
start: start,
|
||||||
|
end: end
|
||||||
|
})?
|
||||||
}
|
}
|
||||||
Some((Span { start, end }, Token::LeftBracket)) => {
|
Some((Span { start, end }, Token::LeftBracket)) => {
|
||||||
self.array().map(|array| Value { e: E::Array(array), start, end })?
|
self.array().map(|array| Value { e: E::Array(array), start: start, end: end })?
|
||||||
}
|
}
|
||||||
Some(token) => {
|
Some(token) => {
|
||||||
return Err(self.error(at, ErrorKind::Wanted {
|
return Err(self.error(at, ErrorKind::Wanted {
|
||||||
|
@ -838,42 +843,49 @@ impl<'a> Deserializer<'a> {
|
||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn number_or_date(&mut self, s: &'a str) -> Result<Value<'a>, Error> {
|
fn number_or_date(&mut self, span: Span, s: &'a str)
|
||||||
|
-> Result<Value<'a>, Error>
|
||||||
|
{
|
||||||
if s.contains('T') || (s.len() > 1 && s[1..].contains('-')) &&
|
if s.contains('T') || (s.len() > 1 && s[1..].contains('-')) &&
|
||||||
!s.contains("e-") {
|
!s.contains("e-") {
|
||||||
// FIXME needs span
|
self.datetime(s, false).map(|d| Value {
|
||||||
self.datetime(s, false).map(|d| Value { e: E::Datetime(d), start: 0, end: 0 })
|
e: E::Datetime(d),
|
||||||
|
start: span.start,
|
||||||
|
end: span.end
|
||||||
|
})
|
||||||
} else if self.eat(Token::Colon)? {
|
} else if self.eat(Token::Colon)? {
|
||||||
// FIXME needs span
|
self.datetime(s, true).map(|d| Value {
|
||||||
self.datetime(s, true).map(|d| Value { e: E::Datetime(d), start: 0, end: 0 })
|
e: E::Datetime(d),
|
||||||
|
start: span.start,
|
||||||
|
end: span.end
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
self.number(s)
|
self.number(span, s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn number(&mut self, s: &'a str) -> Result<Value<'a>, Error> {
|
fn number(&mut self, Span { start, end}: Span, s: &'a str) -> Result<Value<'a>, Error> {
|
||||||
if s.contains('e') || s.contains('E') {
|
if s.contains('e') || s.contains('E') {
|
||||||
// FIXME needs span
|
self.float(s, None).map(|f| Value { e: E::Float(f), start: start, end: end })
|
||||||
self.float(s, None).map(|f| Value { e: E::Float(f), start: 0, end: 0 })
|
|
||||||
} else if self.eat(Token::Period)? {
|
} else if self.eat(Token::Period)? {
|
||||||
let at = self.tokens.current();
|
let at = self.tokens.current();
|
||||||
match self.next()? {
|
match self.next()? {
|
||||||
Some((_, Token::Keylike(after))) => {
|
Some((Span { start, end }, Token::Keylike(after))) => {
|
||||||
// FIXME needs span
|
self.float(s, Some(after)).map(|f| Value {
|
||||||
self.float(s, Some(after)).map(|f| Value { e: E::Float(f), start: 0, end: 0 })
|
e: E::Float(f), start: start, end: end
|
||||||
|
})
|
||||||
}
|
}
|
||||||
_ => Err(self.error(at, ErrorKind::NumberInvalid)),
|
_ => Err(self.error(at, ErrorKind::NumberInvalid)),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// FIXME needs span
|
self.integer(s).map(|f| Value { e: E::Integer(f), start: start, end: end })
|
||||||
self.integer(s).map(|f| Value { e: E::Integer(f), start: 0, end: 0 })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn number_leading_plus(&mut self) -> Result<Value<'a>, Error> {
|
fn number_leading_plus(&mut self) -> Result<Value<'a>, Error> {
|
||||||
let start = self.tokens.current();
|
let start = self.tokens.current();
|
||||||
match self.next()? {
|
match self.next()? {
|
||||||
Some((_, Token::Keylike(s))) => self.number(s),
|
Some((span, Token::Keylike(s))) => self.number(span, s),
|
||||||
_ => Err(self.error(start, ErrorKind::NumberInvalid)),
|
_ => Err(self.error(start, ErrorKind::NumberInvalid)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -173,3 +173,4 @@ mod tokens;
|
||||||
pub mod macros;
|
pub mod macros;
|
||||||
|
|
||||||
pub mod spanned;
|
pub mod spanned;
|
||||||
|
pub use spanned::Spanned;
|
||||||
|
|
|
@ -33,7 +33,7 @@ use std::marker;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use serde::ser;
|
use serde::ser;
|
||||||
use datetime::{SERDE_STRUCT_FIELD_NAME, SERDE_STRUCT_NAME};
|
use datetime;
|
||||||
|
|
||||||
/// Serialize the given data structure as a TOML byte vector.
|
/// Serialize the given data structure as a TOML byte vector.
|
||||||
///
|
///
|
||||||
|
@ -924,7 +924,7 @@ impl<'a, 'b> ser::Serializer for &'b mut Serializer<'a> {
|
||||||
|
|
||||||
fn serialize_struct(self, name: &'static str, _len: usize)
|
fn serialize_struct(self, name: &'static str, _len: usize)
|
||||||
-> Result<Self::SerializeStruct, Self::Error> {
|
-> Result<Self::SerializeStruct, Self::Error> {
|
||||||
if name == SERDE_STRUCT_NAME {
|
if name == datetime::NAME {
|
||||||
self.array_type("datetime")?;
|
self.array_type("datetime")?;
|
||||||
Ok(SerializeTable::Datetime(self))
|
Ok(SerializeTable::Datetime(self))
|
||||||
} else {
|
} else {
|
||||||
|
@ -1071,7 +1071,7 @@ impl<'a, 'b> ser::SerializeStruct for SerializeTable<'a, 'b> {
|
||||||
{
|
{
|
||||||
match *self {
|
match *self {
|
||||||
SerializeTable::Datetime(ref mut ser) => {
|
SerializeTable::Datetime(ref mut ser) => {
|
||||||
if key == SERDE_STRUCT_FIELD_NAME {
|
if key == datetime::FIELD {
|
||||||
value.serialize(DateStrEmitter(&mut *ser))?;
|
value.serialize(DateStrEmitter(&mut *ser))?;
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::DateInvalid)
|
return Err(Error::DateInvalid)
|
||||||
|
|
142
src/spanned.rs
142
src/spanned.rs
|
@ -6,43 +6,147 @@
|
||||||
//! use toml::spanned::Spanned;
|
//! use toml::spanned::Spanned;
|
||||||
//!
|
//!
|
||||||
//! #[derive(Deserialize)]
|
//! #[derive(Deserialize)]
|
||||||
//! struct Udoprog {
|
//! struct Value {
|
||||||
//! s: Spanned<String>,
|
//! s: Spanned<String>,
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! fn main() {
|
//! fn main() {
|
||||||
//! let t = "s = \"udoprog\"\n";
|
//! let t = "s = \"value\"\n";
|
||||||
//!
|
//!
|
||||||
//! let u: Udoprog = toml::from_str(t).unwrap();
|
//! let u: Value = toml::from_str(t).unwrap();
|
||||||
//!
|
//!
|
||||||
//! assert_eq!(u.s.start, 4);
|
//! assert_eq!(u.s.start, 4);
|
||||||
//! assert_eq!(u.s.end, 13);
|
//! assert_eq!(u.s.end, 11);
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use serde::{Serialize, Serializer};
|
use serde::{de, ser};
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
// FIXME: use a more unique name like "toml::Spanned".
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub const NAME: &str = "Spanned";
|
pub const NAME: &'static str = "$__toml_private_Spanned";
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub const FIELDS: &[&str] = &["value", "start", "end"];
|
pub const START: &'static str = "$__toml_private_start";
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub const END: &'static str = "$__toml_private_end";
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub const VALUE: &'static str = "$__toml_private_value";
|
||||||
|
|
||||||
///
|
macro_rules! key_deserialize {
|
||||||
#[derive(Deserialize, Debug)]
|
($ident:ident, $field:expr, $name:expr) => {
|
||||||
pub struct Spanned<T> {
|
struct $ident;
|
||||||
///
|
|
||||||
pub value: T,
|
impl<'de> de::Deserialize<'de> for $ident {
|
||||||
///
|
fn deserialize<D>(deserializer: D) -> Result<$ident, D::Error>
|
||||||
pub start: usize,
|
where D: de::Deserializer<'de>
|
||||||
///
|
{
|
||||||
pub end: usize,
|
struct FieldVisitor;
|
||||||
|
|
||||||
|
impl<'de> de::Visitor<'de> for FieldVisitor {
|
||||||
|
type Value = ();
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
formatter.write_str("a valid spanned field")
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Serialize> Serialize for Spanned<T> {
|
fn visit_str<E>(self, s: &str) -> Result<(), E>
|
||||||
|
where E: de::Error
|
||||||
|
{
|
||||||
|
if s == $field {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(de::Error::custom(
|
||||||
|
concat!("expected spanned field `", $name, "`")))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_identifier(FieldVisitor)?;
|
||||||
|
Ok($ident)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// A spanned value, indicating the range at which it is defined in the source.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Spanned<T> {
|
||||||
|
/// The start range.
|
||||||
|
pub start: usize,
|
||||||
|
/// The end range (exclusive).
|
||||||
|
pub end: usize,
|
||||||
|
/// The spanned value.
|
||||||
|
pub value: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de, T> de::Deserialize<'de> for Spanned<T>
|
||||||
|
where T: de::Deserialize<'de>
|
||||||
|
{
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Spanned<T>, D::Error>
|
||||||
|
where D: de::Deserializer<'de>
|
||||||
|
{
|
||||||
|
struct SpannedVisitor<T>(::std::marker::PhantomData<T>);
|
||||||
|
|
||||||
|
impl<'de, T> de::Visitor<'de> for SpannedVisitor<T>
|
||||||
|
where T: de::Deserialize<'de>
|
||||||
|
{
|
||||||
|
type Value = Spanned<T>;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
formatter.write_str("a TOML spanned")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_map<V>(self, mut visitor: V) -> Result<Spanned<T>, V::Error>
|
||||||
|
where V: de::MapAccess<'de>
|
||||||
|
{
|
||||||
|
let start = visitor.next_key::<StartKey>()?;
|
||||||
|
|
||||||
|
if start.is_none() {
|
||||||
|
return Err(de::Error::custom("spanned start key not found"))
|
||||||
|
}
|
||||||
|
|
||||||
|
let start: usize = visitor.next_value()?;
|
||||||
|
|
||||||
|
let end = visitor.next_key::<EndKey>()?;
|
||||||
|
|
||||||
|
if end.is_none() {
|
||||||
|
return Err(de::Error::custom("spanned end key not found"))
|
||||||
|
}
|
||||||
|
|
||||||
|
let end: usize = visitor.next_value()?;
|
||||||
|
|
||||||
|
let value = visitor.next_key::<ValueKey>()?;
|
||||||
|
|
||||||
|
if value.is_none() {
|
||||||
|
return Err(de::Error::custom("spanned value key not found"))
|
||||||
|
}
|
||||||
|
|
||||||
|
let value: T = visitor.next_value()?;
|
||||||
|
|
||||||
|
Ok(Spanned {
|
||||||
|
start: start,
|
||||||
|
end: end,
|
||||||
|
value: value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
key_deserialize!(StartKey, START, "start");
|
||||||
|
key_deserialize!(EndKey, END, "end");
|
||||||
|
key_deserialize!(ValueKey, VALUE, "value");
|
||||||
|
|
||||||
|
let visitor = SpannedVisitor(::std::marker::PhantomData);
|
||||||
|
|
||||||
|
static FIELDS: [&'static str; 3] = [START, END, VALUE];
|
||||||
|
deserializer.deserialize_struct(NAME, &FIELDS, visitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ser::Serialize> ser::Serialize for Spanned<T> {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
S: Serializer,
|
S: ser::Serializer,
|
||||||
{
|
{
|
||||||
self.value.serialize(serializer)
|
self.value.serialize(serializer)
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ use serde::de;
|
||||||
use serde::de::IntoDeserializer;
|
use serde::de::IntoDeserializer;
|
||||||
|
|
||||||
pub use datetime::{Datetime, DatetimeParseError};
|
pub use datetime::{Datetime, DatetimeParseError};
|
||||||
use datetime::{DatetimeFromString, SERDE_STRUCT_FIELD_NAME};
|
use datetime::{self, DatetimeFromString};
|
||||||
|
|
||||||
/// Representation of a TOML value.
|
/// Representation of a TOML value.
|
||||||
#[derive(PartialEq, Clone, Debug)]
|
#[derive(PartialEq, Clone, Debug)]
|
||||||
|
@ -925,7 +925,7 @@ impl<'a, 'de> de::Visitor<'de> for DatetimeOrTable<'a> {
|
||||||
fn visit_str<E>(self, s: &str) -> Result<bool, E>
|
fn visit_str<E>(self, s: &str) -> Result<bool, E>
|
||||||
where E: de::Error,
|
where E: de::Error,
|
||||||
{
|
{
|
||||||
if s == SERDE_STRUCT_FIELD_NAME {
|
if s == datetime::FIELD {
|
||||||
Ok(true)
|
Ok(true)
|
||||||
} else {
|
} else {
|
||||||
self.key.push_str(s);
|
self.key.push_str(s);
|
||||||
|
@ -936,7 +936,7 @@ impl<'a, 'de> de::Visitor<'de> for DatetimeOrTable<'a> {
|
||||||
fn visit_string<E>(self, s: String) -> Result<bool, E>
|
fn visit_string<E>(self, s: String) -> Result<bool, E>
|
||||||
where E: de::Error,
|
where E: de::Error,
|
||||||
{
|
{
|
||||||
if s == SERDE_STRUCT_FIELD_NAME {
|
if s == datetime::FIELD {
|
||||||
Ok(true)
|
Ok(true)
|
||||||
} else {
|
} else {
|
||||||
*self.key = s;
|
*self.key = s;
|
||||||
|
|
30
test-suite/tests/spanned.rs
Normal file
30
test-suite/tests/spanned.rs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
extern crate serde;
|
||||||
|
extern crate toml;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde_derive;
|
||||||
|
|
||||||
|
use toml::Spanned;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_spanned_field() {
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct Foo<T> {
|
||||||
|
foo: Spanned<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn good<'de, T>(s: &'de str, expected: &str) where T: serde::Deserialize<'de> {
|
||||||
|
let foo: Foo<T> = toml::from_str(s).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(6, foo.foo.start);
|
||||||
|
assert_eq!(s.len(), foo.foo.end);
|
||||||
|
assert_eq!(expected, &s[foo.foo.start..foo.foo.end]);
|
||||||
|
}
|
||||||
|
|
||||||
|
good::<String>("foo = \"foo\"", "\"foo\"");
|
||||||
|
good::<u32>("foo = 42", "42");
|
||||||
|
good::<HashMap<String, u32>>(
|
||||||
|
"foo = {\"foo\" = 42, \"bar\" = 42}",
|
||||||
|
"{\"foo\" = 42, \"bar\" = 42}"
|
||||||
|
);
|
||||||
|
}
|
Loading…
Reference in a new issue