Emit the enum discriminant separately for the Encodable macro
This commit is contained in:
parent
07c993eba8
commit
7de205ea3a
2 changed files with 30 additions and 29 deletions
|
@ -42,6 +42,12 @@ fn decodable_body(
|
||||||
}
|
}
|
||||||
let ty_name = s.ast().ident.to_string();
|
let ty_name = s.ast().ident.to_string();
|
||||||
let decode_body = match s.variants() {
|
let decode_body = match s.variants() {
|
||||||
|
[] => {
|
||||||
|
let message = format!("`{}` has no variants to decode", ty_name);
|
||||||
|
quote! {
|
||||||
|
panic!(#message)
|
||||||
|
}
|
||||||
|
}
|
||||||
[vi] => vi.construct(|field, _index| decode_field(field)),
|
[vi] => vi.construct(|field, _index| decode_field(field)),
|
||||||
variants => {
|
variants => {
|
||||||
let match_inner: TokenStream = variants
|
let match_inner: TokenStream = variants
|
||||||
|
@ -139,6 +145,11 @@ fn encodable_body(
|
||||||
});
|
});
|
||||||
|
|
||||||
let encode_body = match s.variants() {
|
let encode_body = match s.variants() {
|
||||||
|
[] => {
|
||||||
|
quote! {
|
||||||
|
match *self {}
|
||||||
|
}
|
||||||
|
}
|
||||||
[_] => {
|
[_] => {
|
||||||
let encode_inner = s.each_variant(|vi| {
|
let encode_inner = s.each_variant(|vi| {
|
||||||
vi.bindings()
|
vi.bindings()
|
||||||
|
@ -160,6 +171,23 @@ fn encodable_body(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
let disc = {
|
||||||
|
let mut variant_idx = 0usize;
|
||||||
|
let encode_inner = s.each_variant(|_| {
|
||||||
|
let result = quote! {
|
||||||
|
#variant_idx
|
||||||
|
};
|
||||||
|
variant_idx += 1;
|
||||||
|
result
|
||||||
|
});
|
||||||
|
quote! {
|
||||||
|
let disc = match *self {
|
||||||
|
#encode_inner
|
||||||
|
};
|
||||||
|
::rustc_serialize::Encoder::emit_usize(__encoder, disc);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let mut variant_idx = 0usize;
|
let mut variant_idx = 0usize;
|
||||||
let encode_inner = s.each_variant(|vi| {
|
let encode_inner = s.each_variant(|vi| {
|
||||||
let encode_fields: TokenStream = vi
|
let encode_fields: TokenStream = vi
|
||||||
|
@ -176,26 +204,11 @@ fn encodable_body(
|
||||||
result
|
result
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let result = if !vi.bindings().is_empty() {
|
|
||||||
quote! {
|
|
||||||
::rustc_serialize::Encoder::emit_enum_variant(
|
|
||||||
__encoder,
|
|
||||||
#variant_idx,
|
|
||||||
|__encoder| { #encode_fields }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
quote! {
|
|
||||||
::rustc_serialize::Encoder::emit_fieldless_enum_variant::<#variant_idx>(
|
|
||||||
__encoder,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
variant_idx += 1;
|
variant_idx += 1;
|
||||||
result
|
encode_fields
|
||||||
});
|
});
|
||||||
quote! {
|
quote! {
|
||||||
|
#disc
|
||||||
match *self {
|
match *self {
|
||||||
#encode_inner
|
#encode_inner
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,6 @@ pub trait Encoder {
|
||||||
fn emit_str(&mut self, v: &str);
|
fn emit_str(&mut self, v: &str);
|
||||||
fn emit_raw_bytes(&mut self, s: &[u8]);
|
fn emit_raw_bytes(&mut self, s: &[u8]);
|
||||||
|
|
||||||
// Convenience for the derive macro:
|
|
||||||
fn emit_enum_variant<F>(&mut self, v_id: usize, f: F)
|
fn emit_enum_variant<F>(&mut self, v_id: usize, f: F)
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut Self),
|
F: FnOnce(&mut Self),
|
||||||
|
@ -51,17 +50,6 @@ pub trait Encoder {
|
||||||
self.emit_usize(v_id);
|
self.emit_usize(v_id);
|
||||||
f(self);
|
f(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We put the field index in a const generic to allow the emit_usize to be
|
|
||||||
// compiled into a more efficient form. In practice, the variant index is
|
|
||||||
// known at compile-time, and that knowledge allows much more efficient
|
|
||||||
// codegen than we'd otherwise get. LLVM isn't always able to make the
|
|
||||||
// optimization that would otherwise be necessary here, likely due to the
|
|
||||||
// multiple levels of inlining and const-prop that are needed.
|
|
||||||
#[inline]
|
|
||||||
fn emit_fieldless_enum_variant<const ID: usize>(&mut self) {
|
|
||||||
self.emit_usize(ID)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: all the methods in this trait are infallible, which may be surprising.
|
// Note: all the methods in this trait are infallible, which may be surprising.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue