Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow different reprs to still work #687

Merged
merged 13 commits into from
Jan 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ full = []
members = ["derive", "fuzzer"]

[workspace.package]
version = "3.7.1"
version = "3.7.2"
authors = ["Parity Technologies <admin@parity.io>"]
license = "Apache-2.0"
repository = "https://github.com/paritytech/parity-scale-codec"
Expand Down
8 changes: 4 additions & 4 deletions benches/benches.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ fn vec_extend_from_slice(b: &mut Bencher) {

struct NoLimitInput<'a>(&'a [u8]);

impl<'a> Input for NoLimitInput<'a> {
impl Input for NoLimitInput<'_> {
fn remaining_len(&mut self) -> Result<Option<usize>, Error> {
Ok(None)
}
Expand Down Expand Up @@ -121,7 +121,7 @@ where
let mut g = c.benchmark_group("vec_encode");
for vec_size in [1, 2, 5, 32, 1024, 2048, 16384] {
g.bench_with_input(
&format!("{}/{}", type_name::<T>(), vec_size),
format!("{}/{}", type_name::<T>(), vec_size),
&vec_size,
|b, &vec_size| {
let vec: Vec<T> =
Expand All @@ -137,7 +137,7 @@ where
let mut g = c.benchmark_group("vec_decode");
for vec_size in [1, 2, 5, 32, 1024, 2048, 16384] {
g.bench_with_input(
&format!("{}/{}", type_name::<T>(), vec_size),
format!("{}/{}", type_name::<T>(), vec_size),
&vec_size,
|b, &vec_size| {
let vec: Vec<T> =
Expand All @@ -157,7 +157,7 @@ where
let mut g = c.benchmark_group("vec_decode_no_limit");
for vec_size in [16384, 131072] {
g.bench_with_input(
&format!("vec_decode_no_limit_{}/{}", type_name::<T>(), vec_size),
format!("vec_decode_no_limit_{}/{}", type_name::<T>(), vec_size),
&vec_size,
|b, &vec_size| {
let vec: Vec<T> =
Expand Down
45 changes: 37 additions & 8 deletions derive/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ pub fn const_eval_check_variant_indexes(
/// is found, fall back to the discriminant or just the variant index.
pub fn variant_index(v: &Variant, i: usize) -> TokenStream {
// first look for an attribute
let index = find_meta_item(v.attrs.iter(), |meta| {
let mut index = find_meta_item(v.attrs.iter(), |meta| {
if let Meta::NameValue(ref nv) = meta {
if nv.path.is_ident("index") {
if let Expr::Lit(ExprLit { lit: Lit::Int(ref v), .. }) = nv.value {
Expand All @@ -112,13 +112,21 @@ pub fn variant_index(v: &Variant, i: usize) -> TokenStream {
None
});

// then fallback to discriminant or just index
index.map(|i| quote! { #i }).unwrap_or_else(|| {
v.discriminant
.as_ref()
.map(|(_, expr)| quote! { #expr })
.unwrap_or_else(|| quote! { #i })
})
// if no attribute, we fall back to an explicit discriminant (ie 'enum A { Foo = 1u32 }').
if index.is_none() {
if let Some((_, Expr::Lit(ExprLit { lit: Lit::Int(disc_lit), .. }))) = &v.discriminant {
index = disc_lit.base10_parse::<usize>().ok()
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is ignoring the discriminant when defined with an expression.

}

// fall back to the variant index if no attribute or explicit discriminant is found.
let index = index.unwrap_or(i);

// output the index with no suffix (ie 1 rather than 1usize) so that these can be quoted into
// an array of usizes and will work regardless of what type the discriminant values actually
// are.
let s = proc_macro2::Literal::usize_unsuffixed(index);
pkhry marked this conversation as resolved.
Show resolved Hide resolved
quote! { #s }
}

/// Look for a `#[codec(encoded_as = "SomeType")]` outer attribute on the given
Expand Down Expand Up @@ -386,6 +394,12 @@ pub fn check_attributes(input: &DeriveInput) -> syn::Result<()> {
check_field_attribute(attr)?;
}
}
// While we're checking things, also ensure that
// any explicit discriminants are within 0..=255
let discriminant = variant.discriminant.as_ref().map(|(_, d)| d);
if let Some(expr) = discriminant {
check_variant_discriminant(expr)?;
}
},
Data::Union(_) => (),
}
Expand Down Expand Up @@ -465,6 +479,21 @@ fn check_variant_attribute(attr: &Attribute) -> syn::Result<()> {
}
}

// Ensure a variant discriminant, if provided, can be parsed into
// something in the range 0..255.
fn check_variant_discriminant(discriminant: &Expr) -> syn::Result<()> {
if let Expr::Lit(ExprLit { lit: Lit::Int(lit_int), .. }) = discriminant {
lit_int.base10_parse::<u8>().map(|_| ()).map_err(|_| {
syn::Error::new(lit_int.span(), "Discriminant index must be in the range 0..255")
})
} else {
Err(syn::Error::new(
discriminant.span(),
"Discriminant must be an integer literal in the range 0..255",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forcing this to be an integer is a breaking change.

Potential fix: #695

))
}
}

// Only `#[codec(dumb_trait_bound)]` is accepted as top attribute
fn check_top_attribute(attr: &Attribute) -> syn::Result<()> {
let top_error = "Invalid attribute: only `#[codec(dumb_trait_bound)]`, \
Expand Down
16 changes: 8 additions & 8 deletions src/codec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ pub trait Input {
}
}

impl<'a> Input for &'a [u8] {
impl Input for &[u8] {
fn remaining_len(&mut self) -> Result<Option<usize>, Error> {
Ok(Some(self.len()))
}
Expand Down Expand Up @@ -383,10 +383,10 @@ impl<T: ?Sized + Encode> EncodeLike for &mut T {}
impl<T: Encode> EncodeLike<T> for &mut T {}
impl<T: Encode> EncodeLike<&mut T> for T {}

impl<'a, T: ToOwned + ?Sized> WrapperTypeEncode for Cow<'a, T> {}
impl<'a, T: ToOwned + Encode + ?Sized> EncodeLike for Cow<'a, T> {}
impl<'a, T: ToOwned + Encode> EncodeLike<T> for Cow<'a, T> {}
impl<'a, T: ToOwned + Encode> EncodeLike<Cow<'a, T>> for T {}
impl<T: ToOwned + ?Sized> WrapperTypeEncode for Cow<'_, T> {}
impl<T: ToOwned + Encode + ?Sized> EncodeLike for Cow<'_, T> {}
impl<T: ToOwned + Encode> EncodeLike<T> for Cow<'_, T> {}
impl<T: ToOwned + Encode> EncodeLike<Cow<'_, T>> for T {}

impl<T: ?Sized> WrapperTypeEncode for Rc<T> {}
impl<T: ?Sized + Encode> EncodeLike for Rc<T> {}
Expand Down Expand Up @@ -973,7 +973,7 @@ impl<T: Decode, const N: usize> Decode for [T; N] {
slice: &'a mut [MaybeUninit<T>; N],
}

impl<'a, T, const N: usize> Drop for State<'a, T, N> {
impl<T, const N: usize> Drop for State<'_, T, N> {
fn drop(&mut self) {
if !mem::needs_drop::<T>() {
// If the types don't actually need to be dropped then don't even
Expand Down Expand Up @@ -1050,7 +1050,7 @@ impl Encode for str {
}
}

impl<'a, T: ToOwned + ?Sized> Decode for Cow<'a, T>
impl<T: ToOwned + ?Sized> Decode for Cow<'_, T>
where
<T as ToOwned>::Owned: Decode,
{
Expand Down Expand Up @@ -1979,7 +1979,7 @@ mod tests {

struct NoLimit<'a>(&'a [u8]);

impl<'a> Input for NoLimit<'a> {
impl Input for NoLimit<'_> {
fn remaining_len(&mut self) -> Result<Option<usize>, Error> {
Ok(None)
}
Expand Down
16 changes: 8 additions & 8 deletions src/compact.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,14 +134,14 @@ where
}
}

impl<'a, T> EncodeLike for CompactRef<'a, T>
impl<T> EncodeLike for CompactRef<'_, T>
where
T: CompactAs,
for<'b> CompactRef<'b, T::As>: Encode,
{
}

impl<'a, T> Encode for CompactRef<'a, T>
impl<T> Encode for CompactRef<'_, T>
where
T: CompactAs,
for<'b> CompactRef<'b, T::As>: Encode,
Expand Down Expand Up @@ -258,7 +258,7 @@ where
type Type = Compact<T>;
}

impl<'a> Encode for CompactRef<'a, ()> {
impl Encode for CompactRef<'_, ()> {
fn encode_to<W: Output + ?Sized>(&self, _dest: &mut W) {}

fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
Expand All @@ -270,7 +270,7 @@ impl<'a> Encode for CompactRef<'a, ()> {
}
}

impl<'a> Encode for CompactRef<'a, u8> {
impl Encode for CompactRef<'_, u8> {
fn size_hint(&self) -> usize {
Compact::compact_len(self.0)
}
Expand Down Expand Up @@ -298,7 +298,7 @@ impl CompactLen<u8> for Compact<u8> {
}
}

impl<'a> Encode for CompactRef<'a, u16> {
impl Encode for CompactRef<'_, u16> {
fn size_hint(&self) -> usize {
Compact::compact_len(self.0)
}
Expand Down Expand Up @@ -328,7 +328,7 @@ impl CompactLen<u16> for Compact<u16> {
}
}

impl<'a> Encode for CompactRef<'a, u32> {
impl Encode for CompactRef<'_, u32> {
fn size_hint(&self) -> usize {
Compact::compact_len(self.0)
}
Expand Down Expand Up @@ -364,7 +364,7 @@ impl CompactLen<u32> for Compact<u32> {
}
}

impl<'a> Encode for CompactRef<'a, u64> {
impl Encode for CompactRef<'_, u64> {
fn size_hint(&self) -> usize {
Compact::compact_len(self.0)
}
Expand Down Expand Up @@ -410,7 +410,7 @@ impl CompactLen<u64> for Compact<u64> {
}
}

impl<'a> Encode for CompactRef<'a, u128> {
impl Encode for CompactRef<'_, u128> {
fn size_hint(&self) -> usize {
Compact::compact_len(self.0)
}
Expand Down
2 changes: 1 addition & 1 deletion src/depth_limit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ struct DepthTrackingInput<'a, I> {
max_depth: u32,
}

impl<'a, I: Input> Input for DepthTrackingInput<'a, I> {
impl<I: Input> Input for DepthTrackingInput<'_, I> {
fn remaining_len(&mut self) -> Result<Option<usize>, Error> {
self.input.remaining_len()
}
Expand Down
8 changes: 4 additions & 4 deletions src/encode_like.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ pub trait EncodeLike<T: Encode = Self>: Sized + Encode {}
/// }
/// ```
pub struct Ref<'a, T: EncodeLike<U>, U: Encode>(&'a T, core::marker::PhantomData<U>);
impl<'a, T: EncodeLike<U>, U: Encode> core::ops::Deref for Ref<'a, T, U> {
impl<T: EncodeLike<U>, U: Encode> core::ops::Deref for Ref<'_, T, U> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.0
Expand All @@ -99,9 +99,9 @@ impl<'a, T: EncodeLike<U>, U: Encode> From<&'a T> for Ref<'a, T, U> {
Ref(x, Default::default())
}
}
impl<'a, T: EncodeLike<U>, U: Encode> crate::WrapperTypeEncode for Ref<'a, T, U> {}
impl<'a, T: EncodeLike<U>, U: Encode> EncodeLike<U> for Ref<'a, T, U> {}
impl<'a, T: EncodeLike<U>, U: Encode> EncodeLike<U> for &Ref<'a, T, U> {}
impl<T: EncodeLike<U>, U: Encode> crate::WrapperTypeEncode for Ref<'_, T, U> {}
impl<T: EncodeLike<U>, U: Encode> EncodeLike<U> for Ref<'_, T, U> {}
impl<T: EncodeLike<U>, U: Encode> EncodeLike<U> for &Ref<'_, T, U> {}

#[cfg(test)]
mod tests {
Expand Down
2 changes: 1 addition & 1 deletion src/mem_tracking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ impl<'a, I: Input> MemTrackingInput<'a, I> {
}
}

impl<'a, I: Input> Input for MemTrackingInput<'a, I> {
impl<I: Input> Input for MemTrackingInput<'_, I> {
fn remaining_len(&mut self) -> Result<Option<usize>, Error> {
self.input.remaining_len()
}
Expand Down
8 changes: 4 additions & 4 deletions tests/max_encoded_len_ui/crate_str.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ error[E0277]: the trait bound `Example: Encode` is not satisfied
&mut T
Arc<T>
Box<T>
Cow<'a, T>
Cow<'_, T>
Rc<T>
String
Vec<T>
parity_scale_codec::Ref<'a, T, U>
parity_scale_codec::Ref<'_, T, U>
= note: required for `Example` to implement `Encode`
note: required by a bound in `MaxEncodedLen`
--> src/max_encoded_len.rs
Expand All @@ -38,11 +38,11 @@ error[E0277]: the trait bound `Example: Encode` is not satisfied
&mut T
Arc<T>
Box<T>
Cow<'a, T>
Cow<'_, T>
Rc<T>
String
Vec<T>
parity_scale_codec::Ref<'a, T, U>
parity_scale_codec::Ref<'_, T, U>
= note: required for `Example` to implement `Encode`
note: required by a bound in `max_encoded_len`
--> src/max_encoded_len.rs
Expand Down
8 changes: 4 additions & 4 deletions tests/max_encoded_len_ui/incomplete_attr.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ error[E0277]: the trait bound `Example: Encode` is not satisfied
&mut T
Arc<T>
Box<T>
Cow<'a, T>
Cow<'_, T>
Rc<T>
String
Vec<T>
parity_scale_codec::Ref<'a, T, U>
parity_scale_codec::Ref<'_, T, U>
= note: required for `Example` to implement `Encode`
note: required by a bound in `MaxEncodedLen`
--> src/max_encoded_len.rs
Expand All @@ -38,11 +38,11 @@ error[E0277]: the trait bound `Example: Encode` is not satisfied
&mut T
Arc<T>
Box<T>
Cow<'a, T>
Cow<'_, T>
Rc<T>
String
Vec<T>
parity_scale_codec::Ref<'a, T, U>
parity_scale_codec::Ref<'_, T, U>
= note: required for `Example` to implement `Encode`
note: required by a bound in `max_encoded_len`
--> src/max_encoded_len.rs
Expand Down
8 changes: 4 additions & 4 deletions tests/max_encoded_len_ui/missing_crate_specifier.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ error[E0277]: the trait bound `Example: Encode` is not satisfied
&mut T
Arc<T>
Box<T>
Cow<'a, T>
Cow<'_, T>
Rc<T>
String
Vec<T>
parity_scale_codec::Ref<'a, T, U>
parity_scale_codec::Ref<'_, T, U>
= note: required for `Example` to implement `Encode`
note: required by a bound in `MaxEncodedLen`
--> src/max_encoded_len.rs
Expand All @@ -38,11 +38,11 @@ error[E0277]: the trait bound `Example: Encode` is not satisfied
&mut T
Arc<T>
Box<T>
Cow<'a, T>
Cow<'_, T>
Rc<T>
String
Vec<T>
parity_scale_codec::Ref<'a, T, U>
parity_scale_codec::Ref<'_, T, U>
= note: required for `Example` to implement `Encode`
note: required by a bound in `max_encoded_len`
--> src/max_encoded_len.rs
Expand Down
4 changes: 2 additions & 2 deletions tests/max_encoded_len_ui/not_encode.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ error[E0277]: the trait bound `NotEncode: Encode` is not satisfied
&mut T
Arc<T>
Box<T>
Cow<'a, T>
Cow<'_, T>
Rc<T>
String
Vec<T>
parity_scale_codec::Ref<'a, T, U>
parity_scale_codec::Ref<'_, T, U>
= note: required for `NotEncode` to implement `Encode`
note: required by a bound in `MaxEncodedLen`
--> src/max_encoded_len.rs
Expand Down
Loading
Loading