diff --git a/src/libstd/ebml.rs b/src/libstd/ebml.rs index 92898af2993..90389602bc4 100644 --- a/src/libstd/ebml.rs +++ b/src/libstd/ebml.rs @@ -399,8 +399,20 @@ pub mod reader { debug!("read_tup_elt(idx=%u)", idx); f() } - } + fn read_option(&self, f: &fn() -> T) -> Option { + 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 @@ pub mod writer { 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 diff --git a/src/libstd/json.rs b/src/libstd/json.rs index d69917c9aff..bb1102be9f7 100644 --- a/src/libstd/json.rs +++ b/src/libstd/json.rs @@ -120,24 +120,11 @@ impl serialize::Encoder for Encoder { } 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 @@ impl serialize::Encoder for Encoder { 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 @@ impl serialize::Encoder for PrettyEncoder { 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 @@ impl serialize::Encoder for PrettyEncoder { 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 serialize::Encodable for Json { @@ -966,6 +957,13 @@ impl<'self> serialize::Decoder for Decoder<'self> { _ => fail!(~"not a list") } } + + fn read_option(&self, f: &fn() -> T) -> Option { + match *self.peek() { + Null => { self.pop(); None } + _ => Some(f()), + } + } } impl Eq for Json { diff --git a/src/libstd/prettyprint.rs b/src/libstd/prettyprint.rs index f823d73cf0b..ed4f3e957c0 100644 --- a/src/libstd/prettyprint.rs +++ b/src/libstd/prettyprint.rs @@ -182,4 +182,18 @@ impl serialize::Encoder for Serializer { 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(')'); + } } diff --git a/src/libstd/serialize.rs b/src/libstd/serialize.rs index 8e4bbc87b08..69977c6e4fe 100644 --- a/src/libstd/serialize.rs +++ b/src/libstd/serialize.rs @@ -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(&self, sz: uint, f: &fn() -> T) -> T; fn read_tup_elt(&self, idx: uint, f: &fn() -> T) -> T; + + // Specialized types: + fn read_option(&self, f: &fn() -> T) -> Option; } pub trait Encodable { @@ -368,14 +376,10 @@ impl> Decodable for @[T] { impl> Encodable for Option { 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 @@ impl> Encodable for Option { impl> Decodable for Option { fn decode(d: &D) -> Option { - 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)) } } diff --git a/src/libsyntax/ext/auto_encode.rs b/src/libsyntax/ext/auto_encode.rs index e81e460e832..bafd2bb6adb 100644 --- a/src/libsyntax/ext/auto_encode.rs +++ b/src/libsyntax/ext/auto_encode.rs @@ -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 @@ mod test { 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 @@ mod test { 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 @@ mod test { 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) + ] + ); + } }