From c28df7cb52f537975866b43ca28ea5d1a38f7d17 Mon Sep 17 00:00:00 2001
From: Alex Crichton <alex@alexcrichton.com>
Date: Thu, 26 Jun 2014 22:52:31 -0700
Subject: Leave unused keys in TOML while decoding

---
 src/serialization.rs | 84 ++++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 71 insertions(+), 13 deletions(-)

(limited to 'src')

diff --git a/src/serialization.rs b/src/serialization.rs
index 7011eb6..e5bce42 100644
--- a/src/serialization.rs
+++ b/src/serialization.rs
@@ -48,7 +48,7 @@ pub struct Encoder {
 /// `Decodable` types to be generated by this decoder. The input is any
 /// arbitrary TOML value.
 pub struct Decoder {
-    toml: Option<Value>,
+    pub toml: Option<Value>,
     cur_field: Option<String>,
 }
 
@@ -403,10 +403,12 @@ impl Decoder {
 impl serialize::Decoder<DecodeError> for Decoder {
     fn read_nil(&mut self) -> Result<(), DecodeError> {
         match self.toml {
-            Some(String(ref s)) if s.len() == 0 => Ok(()),
-            Some(String(..)) => Err(self.err(NilTooLong)),
-            ref found => Err(self.mismatch("string", found)),
+            Some(String(ref s)) if s.len() == 0 => {}
+            Some(String(..)) => return Err(self.err(NilTooLong)),
+            ref found => return Err(self.mismatch("string", found)),
         }
+        self.toml.take();
+        Ok(())
     }
     fn read_uint(&mut self) -> Result<uint, DecodeError> {
         self.read_i64().map(|i| i as uint)
@@ -428,7 +430,7 @@ impl serialize::Decoder<DecodeError> for Decoder {
     }
     fn read_i64(&mut self) -> Result<i64, DecodeError> {
         match self.toml {
-            Some(Integer(i)) => Ok(i),
+            Some(Integer(i)) => { self.toml.take(); Ok(i) }
             ref found => Err(self.mismatch("integer", found)),
         }
     }
@@ -443,7 +445,7 @@ impl serialize::Decoder<DecodeError> for Decoder {
     }
     fn read_bool(&mut self) -> Result<bool, DecodeError> {
         match self.toml {
-            Some(Boolean(b)) => Ok(b),
+            Some(Boolean(b)) => { self.toml.take(); Ok(b) }
             ref found => Err(self.mismatch("bool", found)),
         }
     }
@@ -457,16 +459,22 @@ impl serialize::Decoder<DecodeError> for Decoder {
         self.read_f64().map(|f| f as f32)
     }
     fn read_char(&mut self) -> Result<char, DecodeError> {
-        match self.toml {
+        let ch = match self.toml {
             Some(String(ref s)) if s.as_slice().char_len() == 1 =>
-                Ok(s.as_slice().char_at(0)),
-            ref found => Err(self.mismatch("string", found)),
-        }
+                s.as_slice().char_at(0),
+            ref found => return Err(self.mismatch("string", found)),
+        };
+        self.toml.take();
+        Ok(ch)
     }
     fn read_str(&mut self) -> Result<String, DecodeError> {
         match self.toml.take() {
             Some(String(s)) => Ok(s),
-            ref found => Err(self.mismatch("string", found)),
+            found => {
+                let err = Err(self.mismatch("string", &found));
+                self.toml = found;
+                err
+            }
         }
     }
 
@@ -535,11 +543,21 @@ impl serialize::Decoder<DecodeError> for Decoder {
                             _f_idx: uint,
                             f: |&mut Decoder| -> Result<T, DecodeError>)
                             -> Result<T, DecodeError> {
+        let field = f_name.to_string();
         let toml = match self.toml {
-            Some(Table(ref mut table)) => table.pop(&f_name.to_string()),
+            Some(Table(ref mut table)) => table.pop(&field),
             ref found => return Err(self.mismatch("table", found)),
         };
-        f(&mut self.sub_decoder(toml, f_name))
+        let mut d = self.sub_decoder(toml, f_name);
+        let ret = try!(f(&mut d));
+        match d.toml {
+            Some(value) => match self.toml {
+                Some(Table(ref mut table)) => { table.insert(field, value); }
+                _ => {}
+            },
+            None => {}
+        }
+        Ok(ret)
     }
 
     fn read_tuple<T>(&mut self,
@@ -957,4 +975,44 @@ mod tests {
         );
         assert_eq!(v, decode!(Table(encode!(v))));
     }
+
+    #[test]
+    fn unused_fields() {
+        #[deriving(Encodable, Decodable, PartialEq, Show)]
+        struct Foo { a: int }
+
+        let v = Foo { a: 2 };
+        let mut d = Decoder::new(Table(map! {
+            a: Integer(2),
+            b: Integer(5)
+        }));
+        assert_eq!(v, Decodable::decode(&mut d).unwrap());
+
+        assert_eq!(d.toml, Some(Table(map! {
+            b: Integer(5)
+        })));
+    }
+
+    #[test]
+    fn unused_fields2() {
+        #[deriving(Encodable, Decodable, PartialEq, Show)]
+        struct Foo { a: Bar }
+        #[deriving(Encodable, Decodable, PartialEq, Show)]
+        struct Bar { a: int }
+
+        let v = Foo { a: Bar { a: 2 } };
+        let mut d = Decoder::new(Table(map! {
+            a: Table(map! {
+                a: Integer(2),
+                b: Integer(5)
+            })
+        }));
+        assert_eq!(v, Decodable::decode(&mut d).unwrap());
+
+        assert_eq!(d.toml, Some(Table(map! {
+            a: Table(map! {
+                b: Integer(5)
+            })
+        })));
+    }
 }
-- 
cgit v1.2.3