1
Fork 0

std: add option type directly to serialize::{En,De}code

This commit is contained in:
Erick Tryzelaar 2013-03-26 15:26:05 -07:00
parent 4d995e66a2
commit 478e4498b7
5 changed files with 138 additions and 48 deletions

View file

@ -399,8 +399,20 @@ pub mod reader {
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 @@ 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

View file

@ -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<S:serialize::Encoder> serialize::Encodable<S> for Json {
@ -966,6 +957,13 @@ impl<'self> serialize::Decoder for Decoder<'self> {
_ => 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 {

View file

@ -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(')');
}
}

View 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 @@ impl<D:Decoder,T:Decodable<D>> Decodable<D> for @[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 @@ impl<S:Encoder,T:Encodable<S>> Encodable<S> for Option<T> {
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))
}
}

View 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 @@ 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)
]
);
}
}