]> git.lizzy.rs Git - rust.git/commitdiff
std: add option type directly to serialize::{En,De}code
authorErick Tryzelaar <erick.tryzelaar@gmail.com>
Tue, 26 Mar 2013 22:26:05 +0000 (15:26 -0700)
committerErick Tryzelaar <erick.tryzelaar@gmail.com>
Wed, 27 Mar 2013 14:04:12 +0000 (07:04 -0700)
src/libstd/ebml.rs
src/libstd/json.rs
src/libstd/prettyprint.rs
src/libstd/serialize.rs
src/libsyntax/ext/auto_encode.rs

index 92898af2993deb29dbb6d764a92b1f9a8c53f125..90389602bc4a24b5a5533b8ce806c5e7be8118bf 100644 (file)
@@ -399,8 +399,20 @@ fn read_tup_elt<T>(&self, idx: uint, f: &fn() -> T) -> T {
             debug!("read_tup_elt(idx=%u)", idx);
             f()
         }
-    }
 
+        fn read_option<T>(&self, f: &fn() -> T) -> Option<T> {
+            debug!("read_option()");
+            do self.read_enum("Option") || {
+                do self.read_enum_variant |idx| {
+                    match idx {
+                        0 => None,
+                        1 => Some(f()),
+                        _ => fail!(),
+                    }
+                }
+            }
+        }
+    }
 }
 
 pub mod writer {
@@ -666,9 +678,19 @@ fn emit_field(&self, name: &str, _idx: uint, f: &fn()) {
 
         fn emit_tup(&self, _len: uint, f: &fn()) { f() }
         fn emit_tup_elt(&self, _idx: uint, f: &fn()) { f() }
-    }
 
+        fn emit_option(&self, f: &fn()) {
+            self.emit_enum("Option", f);
+        }
+        fn emit_option_none(&self) {
+            self.emit_enum_variant("None", 0, 0, || ())
+        }
+        fn emit_option_some(&self, f: &fn()) {
+            self.emit_enum_variant("Some", 1, 1, f)
+        }
+    }
 }
+
 // ___________________________________________________________________________
 // Testing
 
index d69917c9affbe8f21144e7db58197b999915e642..bb1102be9f7401d7f7b9c64135e92677689dfffe 100644 (file)
@@ -120,24 +120,11 @@ fn emit_enum(&self, _name: &str, f: &fn()) {
     }
 
     fn emit_enum_variant(&self, name: &str, _id: uint, cnt: uint, f: &fn()) {
-        // encoding of enums is special-cased for Option. Specifically:
-        // Some(34) => 34
-        // None => null
-
-        // other enums are encoded as strings or vectors:
+        // enums are encoded as strings or vectors:
         // Bunny => "Bunny"
         // Kangaroo(34,"William") => ["Kangaroo",[34,"William"]]
 
-        // FIXME #4872: this would be more precise and less frightening
-        // with fully-qualified option names. To get that information,
-        // we'd have to change the expansion of auto-encode to pass
-        // those along.
-
-        if name == ~"Some" {
-            f();
-        } else if name == ~"None" {
-            self.wr.write_str(~"null");
-        } else if cnt == 0 {
+        if cnt == 0 {
             self.wr.write_str(escape_str(name));
         } else {
             self.wr.write_char('[');
@@ -193,6 +180,10 @@ fn emit_tup(&self, len: uint, f: &fn()) {
     fn emit_tup_elt(&self, idx: uint, f: &fn()) {
         self.emit_vec_elt(idx, f)
     }
+
+    fn emit_option(&self, f: &fn()) { f(); }
+    fn emit_option_none(&self) { self.emit_nil(); }
+    fn emit_option_some(&self, f: &fn()) { f(); }
 }
 
 pub struct PrettyEncoder {
@@ -245,11 +236,7 @@ fn emit_managed(&self, f: &fn()) { f() }
 
     fn emit_enum(&self, _name: &str, f: &fn()) { f() }
     fn emit_enum_variant(&self, name: &str, _id: uint, cnt: uint, f: &fn()) {
-        if name == ~"Some" {
-            f();
-        } else if name == ~"None" {
-            self.emit_nil();
-        } else if cnt == 0 {
+        if cnt == 0 {
             self.wr.write_str(escape_str(name));
         } else {
             self.wr.write_char('[');
@@ -335,6 +322,10 @@ fn emit_tup(&self, sz: uint, f: &fn()) {
     fn emit_tup_elt(&self, idx: uint, f: &fn()) {
         self.emit_vec_elt(idx, f)
     }
+
+    fn emit_option(&self, f: &fn()) { f(); }
+    fn emit_option_none(&self) { self.emit_nil(); }
+    fn emit_option_some(&self, f: &fn()) { f(); }
 }
 
 impl<S:serialize::Encoder> serialize::Encodable<S> for Json {
@@ -966,6 +957,13 @@ fn read_tup_elt<T>(&self, idx: uint, f: &fn() -> T) -> T {
             _ => fail!(~"not a list")
         }
     }
+
+    fn read_option<T>(&self, f: &fn() -> T) -> Option<T> {
+        match *self.peek() {
+            Null => { self.pop(); None }
+            _ => Some(f()),
+        }
+    }
 }
 
 impl Eq for Json {
index f823d73cf0bfffed435a4b296d7747ff6da600cf..ed4f3e957c02af8258f6762569a0039730ec3420 100644 (file)
@@ -182,4 +182,18 @@ fn emit_tup_elt(&self, idx: uint, f: &fn()) {
         if idx > 0u { self.wr.write_str(~", "); }
         f();
     }
+
+    fn emit_option(&self, f: &fn()) {
+        f();
+    }
+
+    fn emit_option_none(&self) {
+        self.wr.write_str("None");
+    }
+
+    fn emit_option_some(&self, f: &fn()) {
+        self.wr.write_str("Some(");
+        f();
+        self.wr.write_char(')');
+    }
 }
index 8e4bbc87b087f1789e84cb35dd86cb420469a9dd..69977c6e4fe0181cc4a3528a0f06ed75adf16419 100644 (file)
@@ -62,6 +62,11 @@ pub trait Encoder {
 
     fn emit_tup(&self, len: uint, f: &fn());
     fn emit_tup_elt(&self, idx: uint, f: &fn());
+
+    // Specialized types:
+    fn emit_option(&self, f: &fn());
+    fn emit_option_none(&self);
+    fn emit_option_some(&self, f: &fn());
 }
 
 pub trait Decoder {
@@ -103,6 +108,9 @@ pub trait Decoder {
 
     fn read_tup<T>(&self, sz: uint, f: &fn() -> T) -> T;
     fn read_tup_elt<T>(&self, idx: uint, f: &fn() -> T) -> T;
+
+    // Specialized types:
+    fn read_option<T>(&self, f: &fn() -> T) -> Option<T>;
 }
 
 pub trait Encodable<S:Encoder> {
@@ -368,14 +376,10 @@ fn decode(d: &D) -> @[T] {
 
 impl<S:Encoder,T:Encodable<S>> Encodable<S> for Option<T> {
     fn encode(&self, s: &S) {
-        do s.emit_enum(~"Option") {
+        do s.emit_option {
             match *self {
-              None => do s.emit_enum_variant(~"None", 0u, 0u) {
-              },
-
-              Some(ref v) => do s.emit_enum_variant(~"Some", 1u, 1u) {
-                s.emit_enum_variant_arg(0u, || v.encode(s))
-              }
+                None => s.emit_option_none(),
+                Some(ref v) => s.emit_option_some(|| v.encode(s)),
             }
         }
     }
@@ -383,16 +387,7 @@ fn encode(&self, s: &S) {
 
 impl<D:Decoder,T:Decodable<D>> Decodable<D> for Option<T> {
     fn decode(d: &D) -> Option<T> {
-        do d.read_enum(~"Option") {
-            do d.read_enum_variant |i| {
-                match i {
-                  0 => None,
-                  1 => Some(d.read_enum_variant_arg(
-                      0u, || Decodable::decode(d))),
-                  _ => fail!(fmt!("Bad variant for option: %u", i))
-                }
-            }
-        }
+        d.read_option(|| Decodable::decode(d))
     }
 }
 
index e81e460e832e4a0904605db170a172319e30cf62..bafd2bb6adbcd3181812a2ed28f1364ac473dc4c 100644 (file)
@@ -1177,6 +1177,7 @@ fn mk_enum_deser_body(
 
 #[cfg(test)]
 mod test {
+    use core::option::{None, Some};
     use std::serialize::Encodable;
     use std::serialize::Encoder;
 
@@ -1190,6 +1191,9 @@ pub enum call {
         CallToEmitNil,
         CallToEmitStruct(~str,uint),
         CallToEmitField(~str,uint),
+        CallToEmitOption,
+        CallToEmitOptionNone,
+        CallToEmitOptionSome,
         // all of the ones I was too lazy to handle:
         CallToOther
     }
@@ -1281,6 +1285,18 @@ fn emit_tup(&self, +_len: uint, f: &fn()) {
         fn emit_tup_elt(&self, +_idx: uint, f: &fn()) {
             self.add_unknown_to_log(); f();
         }
+
+        fn emit_option(&self, f: &fn()) {
+            self.add_to_log(CallToEmitOption);
+            f();
+        }
+        fn emit_option_none(&self) {
+            self.add_to_log(CallToEmitOptionNone);
+        }
+        fn emit_option_some(&self, f: &fn()) {
+            self.add_to_log(CallToEmitOptionSome);
+            f();
+        }
     }
 
 
@@ -1296,13 +1312,58 @@ enum Written {
         Magazine(~str)
     }
 
-    #[test] fn encode_enum_test () {
-        assert_eq!(to_call_log(Book(34,44)),
-                     ~[CallToEmitEnum (~"Written"),
-                       CallToEmitEnumVariant (~"Book",0,2),
-                       CallToEmitEnumVariantArg (0),
-                       CallToEmitUint (34),
-                       CallToEmitEnumVariantArg (1),
-                       CallToEmitUint (44)]);
-        }
+    #[test]
+    fn test_encode_enum() {
+        assert_eq!(
+            to_call_log(Book(34,44)),
+            ~[
+                CallToEmitEnum(~"Written"),
+                CallToEmitEnumVariant(~"Book",0,2),
+                CallToEmitEnumVariantArg(0),
+                CallToEmitUint(34),
+                CallToEmitEnumVariantArg(1),
+                CallToEmitUint(44),
+            ]
+        );
+    }
+
+    pub struct BPos(uint);
+
+    #[auto_encode]
+    pub struct HasPos { pos : BPos }
+
+    #[test]
+    fn test_encode_newtype() {
+        assert_eq!(
+            to_call_log(HasPos { pos:BPos(48) }),
+            ~[
+                CallToEmitStruct(~"HasPos",1),
+                CallToEmitField(~"pos",0),
+                CallToEmitUint(48),
+            ]
+        );
+    }
+
+    #[test]
+    fn test_encode_option() {
+        let mut v = None;
+
+        assert_eq!(
+            to_call_log(v),
+            ~[
+                CallToEmitOption,
+                CallToEmitOptionNone,
+            ]
+        );
+
+        v = Some(54u);
+        assert_eq!(
+            to_call_log(v),
+            ~[
+                CallToEmitOption,
+                CallToEmitOptionSome,
+                CallToEmitUint(54)
+            ]
+        );
+    }
 }