mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-21 22:34:05 +00:00
Emit the enum discriminant separately for the Encodable macro
This commit is contained in:
parent
07c993eba8
commit
7de205ea3a
@ -42,6 +42,12 @@ fn decodable_body(
|
||||
}
|
||||
let ty_name = s.ast().ident.to_string();
|
||||
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)),
|
||||
variants => {
|
||||
let match_inner: TokenStream = variants
|
||||
@ -139,6 +145,11 @@ fn encodable_body(
|
||||
});
|
||||
|
||||
let encode_body = match s.variants() {
|
||||
[] => {
|
||||
quote! {
|
||||
match *self {}
|
||||
}
|
||||
}
|
||||
[_] => {
|
||||
let encode_inner = s.each_variant(|vi| {
|
||||
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 encode_inner = s.each_variant(|vi| {
|
||||
let encode_fields: TokenStream = vi
|
||||
@ -176,26 +204,11 @@ fn encodable_body(
|
||||
result
|
||||
})
|
||||
.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;
|
||||
result
|
||||
encode_fields
|
||||
});
|
||||
quote! {
|
||||
#disc
|
||||
match *self {
|
||||
#encode_inner
|
||||
}
|
||||
|
@ -43,7 +43,6 @@ pub trait Encoder {
|
||||
fn emit_str(&mut self, v: &str);
|
||||
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)
|
||||
where
|
||||
F: FnOnce(&mut Self),
|
||||
@ -51,17 +50,6 @@ pub trait Encoder {
|
||||
self.emit_usize(v_id);
|
||||
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.
|
||||
|
Loading…
Reference in New Issue
Block a user