aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordaubaris <paulius.daubaris@gmail.com>2019-11-22 18:28:29 +0200
committerAlex Crichton <alex@alexcrichton.com>2019-11-22 10:28:29 -0600
commit60b874308e6792a73cc00517a60bbef60a12e3cc (patch)
tree3fac2b54902d2a40462ece80aff2bdefcfe05558
parent75129040cd041b380f4f1d8f2685928392aa9f55 (diff)
downloadmilf-rs-60b874308e6792a73cc00517a60bbef60a12e3cc.tar.gz
milf-rs-60b874308e6792a73cc00517a60bbef60a12e3cc.zip
Mixed type arrays (#358)
* Added support of mixed-type arrays * Add tests cases * Replaced &'static str type for type_ and created a new enum instead * Restored ArrayMixedType
-rw-r--r--src/de.rs19
-rw-r--r--src/ser.rs68
-rw-r--r--test-suite/tests/invalid.rs15
-rw-r--r--test-suite/tests/valid.rs15
-rw-r--r--test-suite/tests/valid/array-mixed-types-arrays-and-ints.json11
-rw-r--r--test-suite/tests/valid/array-mixed-types-arrays-and-ints.toml (renamed from test-suite/tests/invalid/array-mixed-types-arrays-and-ints.toml)0
-rw-r--r--test-suite/tests/valid/array-mixed-types-ints-and-floats.json9
-rw-r--r--test-suite/tests/valid/array-mixed-types-ints-and-floats.toml (renamed from test-suite/tests/invalid/array-mixed-types-ints-and-floats.toml)0
-rw-r--r--test-suite/tests/valid/array-mixed-types-strings-and-ints.json9
-rw-r--r--test-suite/tests/valid/array-mixed-types-strings-and-ints.toml (renamed from test-suite/tests/invalid/array-mixed-types-strings-and-ints.toml)0
-rw-r--r--test-suite/tests/valid/example-v0.4.0.toml3
11 files changed, 81 insertions, 68 deletions
diff --git a/src/de.rs b/src/de.rs
index ae44f20..5a0d0c7 100644
--- a/src/de.rs
+++ b/src/de.rs
@@ -11,7 +11,6 @@ use std::f64;
use std::fmt;
use std::iter;
use std::marker::PhantomData;
-use std::mem::discriminant;
use std::str;
use std::vec;
@@ -147,10 +146,6 @@ enum ErrorKind {
found: &'static str,
},
- /// An array was decoded but the types inside of it were mixed, which is
- /// disallowed by TOML.
- MixedArrayType,
-
/// A duplicate table definition was found.
DuplicateTable(String),
@@ -1827,13 +1822,7 @@ impl<'a> Deserializer<'a> {
if let Some(span) = self.eat_spanned(Token::RightBracket)? {
return Ok((span, ret));
}
- let at = self.tokens.current();
let value = self.value()?;
- if let Some(last) = ret.last() {
- if !value.same_type(last) {
- return Err(self.error(at, ErrorKind::MixedArrayType));
- }
- }
ret.push(value);
intermediate(self)?;
if !self.eat(Token::Comma)? {
@@ -2118,7 +2107,6 @@ impl fmt::Display for Error {
}
ErrorKind::NumberInvalid => "invalid number".fmt(f)?,
ErrorKind::DateInvalid => "invalid date".fmt(f)?,
- ErrorKind::MixedArrayType => "mixed types in an array".fmt(f)?,
ErrorKind::DuplicateTable(ref s) => {
write!(f, "redefinition of table `{}`", s)?;
}
@@ -2180,7 +2168,6 @@ impl error::Error for Error {
ErrorKind::Wanted { .. } => "expected a token but found another",
ErrorKind::NumberInvalid => "invalid number",
ErrorKind::DateInvalid => "invalid date",
- ErrorKind::MixedArrayType => "mixed types in an array",
ErrorKind::DuplicateTable(_) => "duplicate table",
ErrorKind::RedefineAsArray => "table redefined as array",
ErrorKind::EmptyTableKey => "empty table key found",
@@ -2283,9 +2270,3 @@ impl<'a> E<'a> {
}
}
}
-
-impl<'a> Value<'a> {
- fn same_type(&self, other: &Value<'a>) -> bool {
- discriminant(&self.e) == discriminant(&other.e)
- }
-}
diff --git a/src/ser.rs b/src/ser.rs
index 0734803..d81f75e 100644
--- a/src/ser.rs
+++ b/src/ser.rs
@@ -124,8 +124,8 @@ pub enum Error {
#[doc(hidden)]
KeyNewline,
- /// Arrays in TOML must have a homogenous type, but a heterogeneous array
- /// was emitted.
+ /// An array had to be homogenous, but now it is allowed to be heterogenous.
+ #[doc(hidden)]
ArrayMixedType,
/// All values in a TOML table must be emitted before further tables are
@@ -201,6 +201,12 @@ pub struct Serializer<'a> {
settings: Rc<Settings>,
}
+#[derive(Debug, Copy, Clone)]
+enum ArrayState {
+ Started,
+ StartedAsATable,
+}
+
#[derive(Debug, Clone)]
enum State<'a> {
Table {
@@ -212,7 +218,7 @@ enum State<'a> {
Array {
parent: &'a State<'a>,
first: &'a Cell<bool>,
- type_: &'a Cell<Option<&'static str>>,
+ type_: &'a Cell<Option<ArrayState>>,
len: Option<usize>,
},
End,
@@ -222,7 +228,7 @@ enum State<'a> {
pub struct SerializeSeq<'a, 'b> {
ser: &'b mut Serializer<'a>,
first: Cell<bool>,
- type_: Cell<Option<&'static str>>,
+ type_: Cell<Option<ArrayState>>,
len: Option<usize>,
}
@@ -417,7 +423,7 @@ impl<'a> Serializer<'a> {
self
}
- fn display<T: fmt::Display>(&mut self, t: T, type_: &'static str) -> Result<(), Error> {
+ fn display<T: fmt::Display>(&mut self, t: T, type_: ArrayState) -> Result<(), Error> {
self.emit_key(type_)?;
write!(self.dst, "{}", t).map_err(ser::Error::custom)?;
if let State::Table { .. } = self.state {
@@ -426,7 +432,7 @@ impl<'a> Serializer<'a> {
Ok(())
}
- fn emit_key(&mut self, type_: &'static str) -> Result<(), Error> {
+ fn emit_key(&mut self, type_: ArrayState) -> Result<(), Error> {
self.array_type(type_)?;
let state = self.state.clone();
self._emit_key(&state)
@@ -491,16 +497,12 @@ impl<'a> Serializer<'a> {
Ok(())
}
- fn array_type(&mut self, type_: &'static str) -> Result<(), Error> {
+ fn array_type(&mut self, type_: ArrayState) -> Result<(), Error> {
let prev = match self.state {
State::Array { type_, .. } => type_,
_ => return Ok(()),
};
- if let Some(prev) = prev.get() {
- if prev != type_ {
- return Err(Error::ArrayMixedType);
- }
- } else {
+ if let None = prev.get() {
prev.set(Some(type_));
}
Ok(())
@@ -747,7 +749,7 @@ impl<'a> Serializer<'a> {
macro_rules! serialize_float {
($this:expr, $v:expr) => {{
- $this.emit_key("float")?;
+ $this.emit_key(ArrayState::Started)?;
if ($v.is_nan() || $v == 0.0) && $v.is_sign_negative() {
write!($this.dst, "-").map_err(ser::Error::custom)?;
}
@@ -778,39 +780,39 @@ impl<'a, 'b> ser::Serializer for &'b mut Serializer<'a> {
type SerializeStructVariant = ser::Impossible<(), Error>;
fn serialize_bool(self, v: bool) -> Result<(), Self::Error> {
- self.display(v, "bool")
+ self.display(v, ArrayState::Started)
}
fn serialize_i8(self, v: i8) -> Result<(), Self::Error> {
- self.display(v, "integer")
+ self.display(v, ArrayState::Started)
}
fn serialize_i16(self, v: i16) -> Result<(), Self::Error> {
- self.display(v, "integer")
+ self.display(v, ArrayState::Started)
}
fn serialize_i32(self, v: i32) -> Result<(), Self::Error> {
- self.display(v, "integer")
+ self.display(v, ArrayState::Started)
}
fn serialize_i64(self, v: i64) -> Result<(), Self::Error> {
- self.display(v, "integer")
+ self.display(v, ArrayState::Started)
}
fn serialize_u8(self, v: u8) -> Result<(), Self::Error> {
- self.display(v, "integer")
+ self.display(v, ArrayState::Started)
}
fn serialize_u16(self, v: u16) -> Result<(), Self::Error> {
- self.display(v, "integer")
+ self.display(v, ArrayState::Started)
}
fn serialize_u32(self, v: u32) -> Result<(), Self::Error> {
- self.display(v, "integer")
+ self.display(v, ArrayState::Started)
}
fn serialize_u64(self, v: u64) -> Result<(), Self::Error> {
- self.display(v, "integer")
+ self.display(v, ArrayState::Started)
}
fn serialize_f32(self, v: f32) -> Result<(), Self::Error> {
@@ -827,7 +829,7 @@ impl<'a, 'b> ser::Serializer for &'b mut Serializer<'a> {
}
fn serialize_str(self, value: &str) -> Result<(), Self::Error> {
- self.emit_key("string")?;
+ self.emit_key(ArrayState::Started)?;
self.emit_str(value, false)?;
if let State::Table { .. } = self.state {
self.dst.push_str("\n");
@@ -893,7 +895,7 @@ impl<'a, 'b> ser::Serializer for &'b mut Serializer<'a> {
}
fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
- self.array_type("array")?;
+ self.array_type(ArrayState::Started)?;
Ok(SerializeSeq {
ser: self,
first: Cell::new(true),
@@ -925,7 +927,7 @@ impl<'a, 'b> ser::Serializer for &'b mut Serializer<'a> {
}
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
- self.array_type("table")?;
+ self.array_type(ArrayState::StartedAsATable)?;
Ok(SerializeTable::Table {
ser: self,
key: String::new(),
@@ -940,10 +942,10 @@ impl<'a, 'b> ser::Serializer for &'b mut Serializer<'a> {
_len: usize,
) -> Result<Self::SerializeStruct, Self::Error> {
if name == datetime::NAME {
- self.array_type("datetime")?;
+ self.array_type(ArrayState::Started)?;
Ok(SerializeTable::Datetime(self))
} else {
- self.array_type("table")?;
+ self.array_type(ArrayState::StartedAsATable)?;
Ok(SerializeTable::Table {
ser: self,
key: String::new(),
@@ -988,8 +990,8 @@ impl<'a, 'b> ser::SerializeSeq for SerializeSeq<'a, 'b> {
fn end(self) -> Result<(), Error> {
match self.type_.get() {
- Some("table") => return Ok(()),
- Some(_) => match (self.len, &self.ser.settings.array) {
+ Some(ArrayState::StartedAsATable) => return Ok(()),
+ Some(ArrayState::Started) => match (self.len, &self.ser.settings.array) {
(Some(0..=1), _) | (_, &None) => {
self.ser.dst.push_str("]");
}
@@ -1002,7 +1004,7 @@ impl<'a, 'b> ser::SerializeSeq for SerializeSeq<'a, 'b> {
},
None => {
assert!(self.first.get());
- self.ser.emit_key("array")?;
+ self.ser.emit_key(ArrayState::Started)?;
self.ser.dst.push_str("[]")
}
}
@@ -1244,7 +1246,7 @@ impl<'a, 'b> ser::Serializer for DateStrEmitter<'a, 'b> {
}
fn serialize_str(self, value: &str) -> Result<(), Self::Error> {
- self.0.display(value, "datetime")?;
+ self.0.display(value, ArrayState::Started)?;
Ok(())
}
@@ -1528,13 +1530,13 @@ impl fmt::Display for Error {
match *self {
Error::UnsupportedType => "unsupported Rust type".fmt(f),
Error::KeyNotString => "map key was not a string".fmt(f),
- Error::ArrayMixedType => "arrays cannot have mixed types".fmt(f),
Error::ValueAfterTable => "values must be emitted before tables".fmt(f),
Error::DateInvalid => "a serialized date was invalid".fmt(f),
Error::NumberInvalid => "a serialized number was invalid".fmt(f),
Error::UnsupportedNone => "unsupported None value".fmt(f),
Error::Custom(ref s) => s.fmt(f),
Error::KeyNewline => unreachable!(),
+ Error::ArrayMixedType => unreachable!(),
Error::__Nonexhaustive => panic!(),
}
}
@@ -1545,13 +1547,13 @@ impl error::Error for Error {
match *self {
Error::UnsupportedType => "unsupported Rust type",
Error::KeyNotString => "map key was not a string",
- Error::ArrayMixedType => "arrays cannot have mixed types",
Error::ValueAfterTable => "values must be emitted before tables",
Error::DateInvalid => "a serialized date was invalid",
Error::NumberInvalid => "a serialized number was invalid",
Error::UnsupportedNone => "unsupported None value",
Error::Custom(_) => "custom error",
Error::KeyNewline => unreachable!(),
+ Error::ArrayMixedType => unreachable!(),
Error::__Nonexhaustive => panic!(),
}
}
diff --git a/test-suite/tests/invalid.rs b/test-suite/tests/invalid.rs
index 3312629..ccc9338 100644
--- a/test-suite/tests/invalid.rs
+++ b/test-suite/tests/invalid.rs
@@ -15,21 +15,6 @@ macro_rules! test( ($name:ident, $s:expr, $msg:expr) => (
) );
test!(
- array_mixed_types_arrays_and_ints,
- include_str!("invalid/array-mixed-types-arrays-and-ints.toml"),
- "mixed types in an array at line 1 column 24"
-);
-test!(
- array_mixed_types_ints_and_floats,
- include_str!("invalid/array-mixed-types-ints-and-floats.toml"),
- "mixed types in an array at line 1 column 23"
-);
-test!(
- array_mixed_types_strings_and_ints,
- include_str!("invalid/array-mixed-types-strings-and-ints.toml"),
- "mixed types in an array at line 1 column 27"
-);
-test!(
datetime_malformed_no_leads,
include_str!("invalid/datetime-malformed-no-leads.toml"),
"failed to parse datetime for key `no-leads` at line 1 column 12"
diff --git a/test-suite/tests/valid.rs b/test-suite/tests/valid.rs
index e080958..0bb7caa 100644
--- a/test-suite/tests/valid.rs
+++ b/test-suite/tests/valid.rs
@@ -147,6 +147,21 @@ test!(
include_str!("valid/arrays-nested.json")
);
test!(
+ array_mixed_types_ints_and_floats,
+ include_str!("valid/array-mixed-types-ints-and-floats.toml"),
+ include_str!("valid/array-mixed-types-ints-and-floats.json")
+);
+test!(
+ array_mixed_types_arrays_and_ints,
+ include_str!("valid/array-mixed-types-arrays-and-ints.toml"),
+ include_str!("valid/array-mixed-types-arrays-and-ints.json")
+);
+test!(
+ array_mixed_types_strings_and_ints,
+ include_str!("valid/array-mixed-types-strings-and-ints.toml"),
+ include_str!("valid/array-mixed-types-strings-and-ints.json")
+);
+test!(
empty,
include_str!("valid/empty.toml"),
include_str!("valid/empty.json")
diff --git a/test-suite/tests/valid/array-mixed-types-arrays-and-ints.json b/test-suite/tests/valid/array-mixed-types-arrays-and-ints.json
new file mode 100644
index 0000000..10074ec
--- /dev/null
+++ b/test-suite/tests/valid/array-mixed-types-arrays-and-ints.json
@@ -0,0 +1,11 @@
+{
+ "arrays-and-ints": {
+ "type": "array",
+ "value": [
+ {"type": "integer", "value": "1"},
+ {"type": "array", "value": [
+ { "type": "string", "value":"Arrays are not integers."}
+ ]}
+ ]
+ }
+}
diff --git a/test-suite/tests/invalid/array-mixed-types-arrays-and-ints.toml b/test-suite/tests/valid/array-mixed-types-arrays-and-ints.toml
index 051ec73..051ec73 100644
--- a/test-suite/tests/invalid/array-mixed-types-arrays-and-ints.toml
+++ b/test-suite/tests/valid/array-mixed-types-arrays-and-ints.toml
diff --git a/test-suite/tests/valid/array-mixed-types-ints-and-floats.json b/test-suite/tests/valid/array-mixed-types-ints-and-floats.json
new file mode 100644
index 0000000..c90665e
--- /dev/null
+++ b/test-suite/tests/valid/array-mixed-types-ints-and-floats.json
@@ -0,0 +1,9 @@
+{
+ "ints-and-floats": {
+ "type": "array",
+ "value": [
+ {"type": "integer", "value": "1"},
+ {"type": "float", "value": "1.1"}
+ ]
+ }
+}
diff --git a/test-suite/tests/invalid/array-mixed-types-ints-and-floats.toml b/test-suite/tests/valid/array-mixed-types-ints-and-floats.toml
index a5aa9b7..a5aa9b7 100644
--- a/test-suite/tests/invalid/array-mixed-types-ints-and-floats.toml
+++ b/test-suite/tests/valid/array-mixed-types-ints-and-floats.toml
diff --git a/test-suite/tests/valid/array-mixed-types-strings-and-ints.json b/test-suite/tests/valid/array-mixed-types-strings-and-ints.json
new file mode 100644
index 0000000..8ae322e
--- /dev/null
+++ b/test-suite/tests/valid/array-mixed-types-strings-and-ints.json
@@ -0,0 +1,9 @@
+{
+ "strings-and-ints": {
+ "type": "array",
+ "value": [
+ {"type": "string", "value": "hi"},
+ {"type": "integer", "value": "42"}
+ ]
+ }
+}
diff --git a/test-suite/tests/invalid/array-mixed-types-strings-and-ints.toml b/test-suite/tests/valid/array-mixed-types-strings-and-ints.toml
index f348308..f348308 100644
--- a/test-suite/tests/invalid/array-mixed-types-strings-and-ints.toml
+++ b/test-suite/tests/valid/array-mixed-types-strings-and-ints.toml
diff --git a/test-suite/tests/valid/example-v0.4.0.toml b/test-suite/tests/valid/example-v0.4.0.toml
index ffbcce0..69f1c1b 100644
--- a/test-suite/tests/valid/example-v0.4.0.toml
+++ b/test-suite/tests/valid/example-v0.4.0.toml
@@ -170,7 +170,8 @@ False = false
## Array
# Arrays are square brackets with other primitives inside. Whitespace is
-# ignored. Elements are separated by commas. Data types may not be mixed.
+# ignored. Elements are separated by commas. Since 2019-11-06 data types can be
+# mixed.
[array]