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 {
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
}
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('[');
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 {
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('[');
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 {
_ => 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 {
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(')');
+ }
}
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 {
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> {
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)),
}
}
}
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))
}
}
#[cfg(test)]
mod test {
+ use core::option::{None, Some};
use std::serialize::Encodable;
use std::serialize::Encoder;
CallToEmitNil,
CallToEmitStruct(~str,uint),
CallToEmitField(~str,uint),
+ CallToEmitOption,
+ CallToEmitOptionNone,
+ CallToEmitOptionSome,
// all of the ones I was too lazy to handle:
CallToOther
}
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();
+ }
}
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)
+ ]
+ );
+ }
}