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); debug!("read_tup_elt(idx=%u)", idx);
f() 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 { pub mod writer {
@ -666,9 +678,19 @@ pub mod writer {
fn emit_tup(&self, _len: uint, f: &fn()) { f() } fn emit_tup(&self, _len: uint, f: &fn()) { f() }
fn emit_tup_elt(&self, _idx: 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 // 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()) { fn emit_enum_variant(&self, name: &str, _id: uint, cnt: uint, f: &fn()) {
// encoding of enums is special-cased for Option. Specifically: // enums are encoded as strings or vectors:
// Some(34) => 34
// None => null
// other enums are encoded as strings or vectors:
// Bunny => "Bunny" // Bunny => "Bunny"
// Kangaroo(34,"William") => ["Kangaroo",[34,"William"]] // Kangaroo(34,"William") => ["Kangaroo",[34,"William"]]
// FIXME #4872: this would be more precise and less frightening if cnt == 0 {
// 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 {
self.wr.write_str(escape_str(name)); self.wr.write_str(escape_str(name));
} else { } else {
self.wr.write_char('['); self.wr.write_char('[');
@ -193,6 +180,10 @@ impl serialize::Encoder for Encoder {
fn emit_tup_elt(&self, idx: uint, f: &fn()) { fn emit_tup_elt(&self, idx: uint, f: &fn()) {
self.emit_vec_elt(idx, f) 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 { pub struct PrettyEncoder {
@ -245,11 +236,7 @@ impl serialize::Encoder for PrettyEncoder {
fn emit_enum(&self, _name: &str, 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()) { fn emit_enum_variant(&self, name: &str, _id: uint, cnt: uint, f: &fn()) {
if name == ~"Some" { if cnt == 0 {
f();
} else if name == ~"None" {
self.emit_nil();
} else if cnt == 0 {
self.wr.write_str(escape_str(name)); self.wr.write_str(escape_str(name));
} else { } else {
self.wr.write_char('['); self.wr.write_char('[');
@ -335,6 +322,10 @@ impl serialize::Encoder for PrettyEncoder {
fn emit_tup_elt(&self, idx: uint, f: &fn()) { fn emit_tup_elt(&self, idx: uint, f: &fn()) {
self.emit_vec_elt(idx, f) 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 { impl<S:serialize::Encoder> serialize::Encodable<S> for Json {
@ -966,6 +957,13 @@ impl<'self> serialize::Decoder for Decoder<'self> {
_ => fail!(~"not a list") _ => 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 { impl Eq for Json {

View file

@ -182,4 +182,18 @@ impl serialize::Encoder for Serializer {
if idx > 0u { self.wr.write_str(~", "); } if idx > 0u { self.wr.write_str(~", "); }
f(); 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(&self, len: uint, f: &fn());
fn emit_tup_elt(&self, idx: 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 { pub trait Decoder {
@ -103,6 +108,9 @@ pub trait Decoder {
fn read_tup<T>(&self, sz: uint, f: &fn() -> T) -> T; fn read_tup<T>(&self, sz: uint, f: &fn() -> T) -> T;
fn read_tup_elt<T>(&self, idx: 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> { 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> { impl<S:Encoder,T:Encodable<S>> Encodable<S> for Option<T> {
fn encode(&self, s: &S) { fn encode(&self, s: &S) {
do s.emit_enum(~"Option") { do s.emit_option {
match *self { match *self {
None => do s.emit_enum_variant(~"None", 0u, 0u) { None => s.emit_option_none(),
}, Some(ref v) => s.emit_option_some(|| v.encode(s)),
Some(ref v) => do s.emit_enum_variant(~"Some", 1u, 1u) {
s.emit_enum_variant_arg(0u, || 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> { impl<D:Decoder,T:Decodable<D>> Decodable<D> for Option<T> {
fn decode(d: &D) -> Option<T> { fn decode(d: &D) -> Option<T> {
do d.read_enum(~"Option") { d.read_option(|| Decodable::decode(d))
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))
}
}
}
} }
} }

View file

@ -1177,6 +1177,7 @@ fn mk_enum_deser_body(
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use core::option::{None, Some};
use std::serialize::Encodable; use std::serialize::Encodable;
use std::serialize::Encoder; use std::serialize::Encoder;
@ -1190,6 +1191,9 @@ mod test {
CallToEmitNil, CallToEmitNil,
CallToEmitStruct(~str,uint), CallToEmitStruct(~str,uint),
CallToEmitField(~str,uint), CallToEmitField(~str,uint),
CallToEmitOption,
CallToEmitOptionNone,
CallToEmitOptionSome,
// all of the ones I was too lazy to handle: // all of the ones I was too lazy to handle:
CallToOther CallToOther
} }
@ -1281,6 +1285,18 @@ mod test {
fn emit_tup_elt(&self, +_idx: uint, f: &fn()) { fn emit_tup_elt(&self, +_idx: uint, f: &fn()) {
self.add_unknown_to_log(); f(); 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) Magazine(~str)
} }
#[test] fn encode_enum_test () { #[test]
assert_eq!(to_call_log(Book(34,44)), fn test_encode_enum() {
~[CallToEmitEnum (~"Written"), assert_eq!(
CallToEmitEnumVariant (~"Book",0,2), to_call_log(Book(34,44)),
CallToEmitEnumVariantArg (0), ~[
CallToEmitUint (34), CallToEmitEnum(~"Written"),
CallToEmitEnumVariantArg (1), CallToEmitEnumVariant(~"Book",0,2),
CallToEmitUint (44)]); 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)
]
);
}
} }