mirror of
https://github.com/Lokathor/bytemuck.git
synced 2024-11-25 00:02:22 +00:00
Cleanup: use a macro for reprs, use syn errors & fix cfg-target-arch (#124)
This commit is contained in:
parent
bbd6a927ad
commit
1ebf7c251d
@ -5,8 +5,8 @@ extern crate proc_macro;
|
|||||||
mod traits;
|
mod traits;
|
||||||
|
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use quote::{quote, quote_spanned};
|
use quote::quote;
|
||||||
use syn::{parse_macro_input, DeriveInput, spanned::Spanned};
|
use syn::{parse_macro_input, DeriveInput, Result};
|
||||||
|
|
||||||
use crate::traits::{
|
use crate::traits::{
|
||||||
AnyBitPattern, Contiguous, Derivable, CheckedBitPattern, NoUninit, Pod, TransparentWrapper, Zeroable,
|
AnyBitPattern, Contiguous, Derivable, CheckedBitPattern, NoUninit, Pod, TransparentWrapper, Zeroable,
|
||||||
@ -223,17 +223,13 @@ pub fn derive_contiguous(
|
|||||||
|
|
||||||
/// Basic wrapper for error handling
|
/// Basic wrapper for error handling
|
||||||
fn derive_marker_trait<Trait: Derivable>(input: DeriveInput) -> TokenStream {
|
fn derive_marker_trait<Trait: Derivable>(input: DeriveInput) -> TokenStream {
|
||||||
let span = input.span();
|
derive_marker_trait_inner::<Trait>(input)
|
||||||
derive_marker_trait_inner::<Trait>(input).unwrap_or_else(|err| {
|
.unwrap_or_else(|err| err.into_compile_error())
|
||||||
quote_spanned! { span =>
|
|
||||||
compile_error!(#err);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn derive_marker_trait_inner<Trait: Derivable>(
|
fn derive_marker_trait_inner<Trait: Derivable>(
|
||||||
input: DeriveInput,
|
input: DeriveInput,
|
||||||
) -> Result<TokenStream, &'static str> {
|
) -> Result<TokenStream> {
|
||||||
let name = &input.ident;
|
let name = &input.ident;
|
||||||
|
|
||||||
let (impl_generics, ty_generics, where_clause) =
|
let (impl_generics, ty_generics, where_clause) =
|
||||||
|
@ -1,30 +1,42 @@
|
|||||||
|
#![allow(unused_imports)]
|
||||||
use proc_macro2::{Ident, Span, TokenStream, TokenTree};
|
use proc_macro2::{Ident, Span, TokenStream, TokenTree};
|
||||||
use quote::{quote, quote_spanned, ToTokens};
|
use quote::{quote, quote_spanned, ToTokens};
|
||||||
use syn::{
|
use syn::{*,
|
||||||
spanned::Spanned, AttrStyle, Attribute, Data, DataEnum, DataStruct,
|
parse::{Parse, Parser, ParseStream},
|
||||||
DataUnion, DeriveInput, Expr, ExprLit, ExprUnary, Fields, Lit, LitInt, Meta,
|
punctuated::Punctuated,
|
||||||
NestedMeta, Type, UnOp, Variant,
|
spanned::Spanned,
|
||||||
|
Result,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
macro_rules! bail {
|
||||||
|
($msg:expr $(,)?) => (
|
||||||
|
return Err(Error::new(Span::call_site(), &$msg[..]))
|
||||||
|
);
|
||||||
|
|
||||||
|
( $msg:expr => $span_to_blame:expr $(,)? ) => (
|
||||||
|
return Err(Error::new_spanned(&$span_to_blame, $msg))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
pub trait Derivable {
|
pub trait Derivable {
|
||||||
fn ident() -> TokenStream;
|
fn ident() -> TokenStream;
|
||||||
fn implies_trait() -> Option<TokenStream> {
|
fn implies_trait() -> Option<TokenStream> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
fn generic_params(_input: &DeriveInput) -> Result<TokenStream, &'static str> {
|
fn generic_params(_input: &DeriveInput) -> Result<TokenStream> {
|
||||||
Ok(quote!())
|
Ok(quote!())
|
||||||
}
|
}
|
||||||
fn asserts(_input: &DeriveInput) -> Result<TokenStream, &'static str> {
|
fn asserts(_input: &DeriveInput) -> Result<TokenStream> {
|
||||||
Ok(quote!())
|
Ok(quote!())
|
||||||
}
|
}
|
||||||
fn check_attributes(
|
fn check_attributes(
|
||||||
_ty: &Data, _attributes: &[Attribute],
|
_ty: &Data, _attributes: &[Attribute],
|
||||||
) -> Result<(), &'static str> {
|
) -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn trait_impl(
|
fn trait_impl(
|
||||||
_input: &DeriveInput,
|
_input: &DeriveInput,
|
||||||
) -> Result<(TokenStream, TokenStream), &'static str> {
|
) -> Result<(TokenStream, TokenStream)> {
|
||||||
Ok((quote!(), quote!()))
|
Ok((quote!(), quote!()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -36,13 +48,17 @@ impl Derivable for Pod {
|
|||||||
quote!(::bytemuck::Pod)
|
quote!(::bytemuck::Pod)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn asserts(input: &DeriveInput) -> Result<TokenStream, &'static str> {
|
fn asserts(input: &DeriveInput) -> Result<TokenStream> {
|
||||||
let repr = get_repr(&input.attrs);
|
let repr = get_repr(&input.attrs)?;
|
||||||
|
|
||||||
let completly_packed = repr.packed == Some(1);
|
let completly_packed = repr.packed == Some(1);
|
||||||
|
|
||||||
if !completly_packed && !input.generics.params.is_empty() {
|
if !completly_packed && !input.generics.params.is_empty() {
|
||||||
return Err("Pod requires cannot be derived for non-packed types containing generic parameters because the padding requirements can't be verified for generic non-packed structs");
|
bail!("\
|
||||||
|
Pod requires cannot be derived for non-packed types containing \
|
||||||
|
generic parameters because the padding requirements can't be verified \
|
||||||
|
for generic non-packed structs\
|
||||||
|
" => input.generics.params.first().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
match &input.data {
|
match &input.data {
|
||||||
@ -60,20 +76,20 @@ impl Derivable for Pod {
|
|||||||
#assert_fields_are_pod
|
#assert_fields_are_pod
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
Data::Enum(_) => Err("Deriving Pod is not supported for enums"),
|
Data::Enum(_) => bail!("Deriving Pod is not supported for enums"),
|
||||||
Data::Union(_) => Err("Deriving Pod is not supported for unions"),
|
Data::Union(_) => bail!("Deriving Pod is not supported for unions"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_attributes(
|
fn check_attributes(
|
||||||
_ty: &Data, attributes: &[Attribute],
|
_ty: &Data, attributes: &[Attribute],
|
||||||
) -> Result<(), &'static str> {
|
) -> Result<()> {
|
||||||
let repr = get_repr(attributes);
|
let repr = get_repr(attributes)?;
|
||||||
match repr.repr {
|
match repr.repr {
|
||||||
Repr::C => Ok(()),
|
Repr::C => Ok(()),
|
||||||
Repr::Transparent => Ok(()),
|
Repr::Transparent => Ok(()),
|
||||||
_ => {
|
_ => {
|
||||||
Err("Pod requires the type to be #[repr(C)] or #[repr(transparent)]")
|
bail!("Pod requires the type to be #[repr(C)] or #[repr(transparent)]")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -90,11 +106,11 @@ impl Derivable for AnyBitPattern {
|
|||||||
Some(quote!(::bytemuck::Zeroable))
|
Some(quote!(::bytemuck::Zeroable))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn asserts(input: &DeriveInput) -> Result<TokenStream, &'static str> {
|
fn asserts(input: &DeriveInput) -> Result<TokenStream> {
|
||||||
match &input.data {
|
match &input.data {
|
||||||
Data::Union(_) => Ok(quote!()), // unions are always `AnyBitPattern`
|
Data::Union(_) => Ok(quote!()), // unions are always `AnyBitPattern`
|
||||||
Data::Struct(_) => generate_fields_are_trait(input, Self::ident()),
|
Data::Struct(_) => generate_fields_are_trait(input, Self::ident()),
|
||||||
Data::Enum(_) => Err("Deriving AnyBitPattern is not supported for enums"),
|
Data::Enum(_) => bail!("Deriving AnyBitPattern is not supported for enums"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -106,11 +122,11 @@ impl Derivable for Zeroable {
|
|||||||
quote!(::bytemuck::Zeroable)
|
quote!(::bytemuck::Zeroable)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn asserts(input: &DeriveInput) -> Result<TokenStream, &'static str> {
|
fn asserts(input: &DeriveInput) -> Result<TokenStream> {
|
||||||
match &input.data {
|
match &input.data {
|
||||||
Data::Union(_) => Ok(quote!()), // unions are always `Zeroable`
|
Data::Union(_) => Ok(quote!()), // unions are always `Zeroable`
|
||||||
Data::Struct(_) => generate_fields_are_trait(input, Self::ident()),
|
Data::Struct(_) => generate_fields_are_trait(input, Self::ident()),
|
||||||
Data::Enum(_) => Err("Deriving Zeroable is not supported for enums"),
|
Data::Enum(_) => bail!("Deriving Zeroable is not supported for enums"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -124,25 +140,25 @@ impl Derivable for NoUninit {
|
|||||||
|
|
||||||
fn check_attributes(
|
fn check_attributes(
|
||||||
ty: &Data, attributes: &[Attribute],
|
ty: &Data, attributes: &[Attribute],
|
||||||
) -> Result<(), &'static str> {
|
) -> Result<()> {
|
||||||
let repr = get_repr(attributes);
|
let repr = get_repr(attributes)?;
|
||||||
match ty {
|
match ty {
|
||||||
Data::Struct(_) => match repr.repr {
|
Data::Struct(_) => match repr.repr {
|
||||||
Repr::C | Repr::Transparent => Ok(()),
|
Repr::C | Repr::Transparent => Ok(()),
|
||||||
_ => Err("NoUninit requires the struct to be #[repr(C)] or #[repr(transparent)]"),
|
_ => bail!("NoUninit requires the struct to be #[repr(C)] or #[repr(transparent)]"),
|
||||||
},
|
},
|
||||||
Data::Enum(_) => if repr.repr.is_integer() {
|
Data::Enum(_) => if repr.repr.is_integer() {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err("NoUninit requires the enum to be an explicit #[repr(Int)]")
|
bail!("NoUninit requires the enum to be an explicit #[repr(Int)]")
|
||||||
},
|
},
|
||||||
Data::Union(_) => Err("NoUninit can only be derived on enums and structs")
|
Data::Union(_) => bail!("NoUninit can only be derived on enums and structs")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn asserts(input: &DeriveInput) -> Result<TokenStream, &'static str> {
|
fn asserts(input: &DeriveInput) -> Result<TokenStream> {
|
||||||
if !input.generics.params.is_empty() {
|
if !input.generics.params.is_empty() {
|
||||||
return Err("NoUninit cannot be derived for structs containing generic parameters because the padding requirements can't be verified for generic structs");
|
bail!("NoUninit cannot be derived for structs containing generic parameters because the padding requirements can't be verified for generic structs");
|
||||||
}
|
}
|
||||||
|
|
||||||
match &input.data {
|
match &input.data {
|
||||||
@ -158,18 +174,18 @@ impl Derivable for NoUninit {
|
|||||||
}
|
}
|
||||||
Data::Enum(DataEnum { variants, .. }) => {
|
Data::Enum(DataEnum { variants, .. }) => {
|
||||||
if variants.iter().any(|variant| !variant.fields.is_empty()) {
|
if variants.iter().any(|variant| !variant.fields.is_empty()) {
|
||||||
Err("Only fieldless enums are supported for NoUninit")
|
bail!("Only fieldless enums are supported for NoUninit")
|
||||||
} else {
|
} else {
|
||||||
Ok(quote!())
|
Ok(quote!())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Data::Union(_) => Err("NoUninit cannot be derived for unions"), // shouldn't be possible since we already error in attribute check for this case
|
Data::Union(_) => bail!("NoUninit cannot be derived for unions"), // shouldn't be possible since we already error in attribute check for this case
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trait_impl(
|
fn trait_impl(
|
||||||
_input: &DeriveInput,
|
_input: &DeriveInput,
|
||||||
) -> Result<(TokenStream, TokenStream), &'static str> {
|
) -> Result<(TokenStream, TokenStream)> {
|
||||||
Ok((quote!(), quote!()))
|
Ok((quote!(), quote!()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -183,25 +199,25 @@ impl Derivable for CheckedBitPattern {
|
|||||||
|
|
||||||
fn check_attributes(
|
fn check_attributes(
|
||||||
ty: &Data, attributes: &[Attribute],
|
ty: &Data, attributes: &[Attribute],
|
||||||
) -> Result<(), &'static str> {
|
) -> Result<()> {
|
||||||
let repr = get_repr(attributes);
|
let repr = get_repr(attributes)?;
|
||||||
match ty {
|
match ty {
|
||||||
Data::Struct(_) => match repr.repr {
|
Data::Struct(_) => match repr.repr {
|
||||||
Repr::C | Repr::Transparent => Ok(()),
|
Repr::C | Repr::Transparent => Ok(()),
|
||||||
_ => Err("CheckedBitPattern derive requires the struct to be #[repr(C)] or #[repr(transparent)]"),
|
_ => bail!("CheckedBitPattern derive requires the struct to be #[repr(C)] or #[repr(transparent)]"),
|
||||||
},
|
},
|
||||||
Data::Enum(_) => if repr.repr.is_integer() {
|
Data::Enum(_) => if repr.repr.is_integer() {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err("CheckedBitPattern requires the enum to be an explicit #[repr(Int)]")
|
bail!("CheckedBitPattern requires the enum to be an explicit #[repr(Int)]")
|
||||||
},
|
},
|
||||||
Data::Union(_) => Err("CheckedBitPattern can only be derived on enums and structs")
|
Data::Union(_) => bail!("CheckedBitPattern can only be derived on enums and structs")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn asserts(input: &DeriveInput) -> Result<TokenStream, &'static str> {
|
fn asserts(input: &DeriveInput) -> Result<TokenStream> {
|
||||||
if !input.generics.params.is_empty() {
|
if !input.generics.params.is_empty() {
|
||||||
return Err("CheckedBitPattern cannot be derived for structs containing generic parameters");
|
bail!("CheckedBitPattern cannot be derived for structs containing generic parameters");
|
||||||
}
|
}
|
||||||
|
|
||||||
match &input.data {
|
match &input.data {
|
||||||
@ -212,19 +228,19 @@ impl Derivable for CheckedBitPattern {
|
|||||||
Ok(assert_fields_are_maybe_pod)
|
Ok(assert_fields_are_maybe_pod)
|
||||||
}
|
}
|
||||||
Data::Enum(_) => Ok(quote!()), // nothing needed, already guaranteed OK by NoUninit
|
Data::Enum(_) => Ok(quote!()), // nothing needed, already guaranteed OK by NoUninit
|
||||||
Data::Union(_) => Err("Internal error in CheckedBitPattern derive"), // shouldn't be possible since we already error in attribute check for this case
|
Data::Union(_) => bail!("Internal error in CheckedBitPattern derive"), // shouldn't be possible since we already error in attribute check for this case
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trait_impl(
|
fn trait_impl(
|
||||||
input: &DeriveInput,
|
input: &DeriveInput,
|
||||||
) -> Result<(TokenStream, TokenStream), &'static str> {
|
) -> Result<(TokenStream, TokenStream)> {
|
||||||
match &input.data {
|
match &input.data {
|
||||||
Data::Struct(DataStruct { fields, .. }) => Ok(
|
Data::Struct(DataStruct { fields, .. }) => {
|
||||||
generate_checked_bit_pattern_struct(&input.ident, fields, &input.attrs),
|
generate_checked_bit_pattern_struct(&input.ident, fields, &input.attrs)
|
||||||
),
|
},
|
||||||
Data::Enum(_) => generate_checked_bit_pattern_enum(input),
|
Data::Enum(_) => generate_checked_bit_pattern_enum(input),
|
||||||
Data::Union(_) => Err("Internal error in CheckedBitPattern derive"), // shouldn't be possible since we already error in attribute check for this case
|
Data::Union(_) => bail!("Internal error in CheckedBitPattern derive"), // shouldn't be possible since we already error in attribute check for this case
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -254,14 +270,19 @@ impl Derivable for TransparentWrapper {
|
|||||||
quote!(::bytemuck::TransparentWrapper)
|
quote!(::bytemuck::TransparentWrapper)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generic_params(input: &DeriveInput) -> Result<TokenStream, &'static str> {
|
fn generic_params(input: &DeriveInput) -> Result<TokenStream> {
|
||||||
let fields = get_struct_fields(input)?;
|
let fields = get_struct_fields(input)?;
|
||||||
|
|
||||||
Self::get_wrapper_type(&input.attrs, &fields).map(|ty| quote!(<#ty>))
|
match Self::get_wrapper_type(&input.attrs, &fields) {
|
||||||
.ok_or("when deriving TransparentWrapper for a struct with more than one field you need to specify the transparent field using #[transparent(T)]")
|
| Some(ty) => Ok(quote!(<#ty>)),
|
||||||
|
| None => bail!("\
|
||||||
|
when deriving TransparentWrapper for a struct with more than one field \
|
||||||
|
you need to specify the transparent field using #[transparent(T)]\
|
||||||
|
"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn asserts(input: &DeriveInput) -> Result<TokenStream, &'static str> {
|
fn asserts(input: &DeriveInput) -> Result<TokenStream> {
|
||||||
let fields = get_struct_fields(input)?;
|
let fields = get_struct_fields(input)?;
|
||||||
let wrapped_type = match Self::get_wrapper_type(&input.attrs, &fields) {
|
let wrapped_type = match Self::get_wrapper_type(&input.attrs, &fields) {
|
||||||
Some(wrapped_type) => wrapped_type.to_string(),
|
Some(wrapped_type) => wrapped_type.to_string(),
|
||||||
@ -271,10 +292,10 @@ impl Derivable for TransparentWrapper {
|
|||||||
.iter()
|
.iter()
|
||||||
.filter(|field| field.ty.to_token_stream().to_string() == wrapped_type);
|
.filter(|field| field.ty.to_token_stream().to_string() == wrapped_type);
|
||||||
if let None = wrapped_fields.next() {
|
if let None = wrapped_fields.next() {
|
||||||
return Err("TransparentWrapper must have one field of the wrapped type");
|
bail!("TransparentWrapper must have one field of the wrapped type");
|
||||||
};
|
};
|
||||||
if let Some(_) = wrapped_fields.next() {
|
if let Some(_) = wrapped_fields.next() {
|
||||||
Err("TransparentWrapper can only have one field of the wrapped type")
|
bail!("TransparentWrapper can only have one field of the wrapped type")
|
||||||
} else {
|
} else {
|
||||||
Ok(quote!())
|
Ok(quote!())
|
||||||
}
|
}
|
||||||
@ -282,13 +303,13 @@ impl Derivable for TransparentWrapper {
|
|||||||
|
|
||||||
fn check_attributes(
|
fn check_attributes(
|
||||||
_ty: &Data, attributes: &[Attribute],
|
_ty: &Data, attributes: &[Attribute],
|
||||||
) -> Result<(), &'static str> {
|
) -> Result<()> {
|
||||||
let repr = get_repr(attributes);
|
let repr = get_repr(attributes)?;
|
||||||
|
|
||||||
match repr.repr {
|
match repr.repr {
|
||||||
Repr::Transparent => Ok(()),
|
Repr::Transparent => Ok(()),
|
||||||
_ => {
|
_ => {
|
||||||
Err("TransparentWrapper requires the struct to be #[repr(transparent)]")
|
bail!("TransparentWrapper requires the struct to be #[repr(transparent)]")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -303,13 +324,13 @@ impl Derivable for Contiguous {
|
|||||||
|
|
||||||
fn trait_impl(
|
fn trait_impl(
|
||||||
input: &DeriveInput,
|
input: &DeriveInput,
|
||||||
) -> Result<(TokenStream, TokenStream), &'static str> {
|
) -> Result<(TokenStream, TokenStream)> {
|
||||||
let repr = get_repr(&input.attrs);
|
let repr = get_repr(&input.attrs)?;
|
||||||
|
|
||||||
let integer_ty = if let Some(integer_ty) = repr.repr.as_integer_type() {
|
let integer_ty = if let Some(integer_ty) = repr.repr.as_integer_type() {
|
||||||
integer_ty
|
integer_ty
|
||||||
} else {
|
} else {
|
||||||
return Err("Contiguous requires the enum to be #[repr(Int)]");
|
bail!("Contiguous requires the enum to be #[repr(Int)]");
|
||||||
};
|
};
|
||||||
|
|
||||||
let variants = get_enum_variants(input)?;
|
let variants = get_enum_variants(input)?;
|
||||||
@ -320,7 +341,7 @@ impl Derivable for Contiguous {
|
|||||||
(i64::max_value(), i64::min_value(), 0),
|
(i64::max_value(), i64::min_value(), 0),
|
||||||
|(min, max, count), res| {
|
|(min, max, count), res| {
|
||||||
let discriminator = res?;
|
let discriminator = res?;
|
||||||
Ok((
|
Ok::<_, Error>((
|
||||||
i64::min(min, discriminator),
|
i64::min(min, discriminator),
|
||||||
i64::max(max, discriminator),
|
i64::max(max, discriminator),
|
||||||
count + 1,
|
count + 1,
|
||||||
@ -329,9 +350,9 @@ impl Derivable for Contiguous {
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
if max - min != count - 1 {
|
if max - min != count - 1 {
|
||||||
return Err(
|
bail! {
|
||||||
"Contiguous requires the enum discriminants to be contiguous",
|
"Contiguous requires the enum discriminants to be contiguous",
|
||||||
);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let min_lit = LitInt::new(&format!("{}", min), input.span());
|
let min_lit = LitInt::new(&format!("{}", min), input.span());
|
||||||
@ -348,29 +369,29 @@ impl Derivable for Contiguous {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_struct_fields(input: &DeriveInput) -> Result<&Fields, &'static str> {
|
fn get_struct_fields(input: &DeriveInput) -> Result<&Fields> {
|
||||||
if let Data::Struct(DataStruct { fields, .. }) = &input.data {
|
if let Data::Struct(DataStruct { fields, .. }) = &input.data {
|
||||||
Ok(fields)
|
Ok(fields)
|
||||||
} else {
|
} else {
|
||||||
Err("deriving this trait is only supported for structs")
|
bail!("deriving this trait is only supported for structs")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_fields(input: &DeriveInput) -> Result<Fields, &'static str> {
|
fn get_fields(input: &DeriveInput) -> Result<Fields> {
|
||||||
match &input.data {
|
match &input.data {
|
||||||
Data::Struct(DataStruct { fields, .. }) => Ok(fields.clone()),
|
Data::Struct(DataStruct { fields, .. }) => Ok(fields.clone()),
|
||||||
Data::Union(DataUnion { fields, .. }) => Ok(Fields::Named(fields.clone())),
|
Data::Union(DataUnion { fields, .. }) => Ok(Fields::Named(fields.clone())),
|
||||||
Data::Enum(_) => Err("deriving this trait is not supported for enums"),
|
Data::Enum(_) => bail!("deriving this trait is not supported for enums"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_enum_variants<'a>(
|
fn get_enum_variants<'a>(
|
||||||
input: &'a DeriveInput,
|
input: &'a DeriveInput,
|
||||||
) -> Result<impl Iterator<Item = &'a Variant> + 'a, &'static str> {
|
) -> Result<impl Iterator<Item = &'a Variant> + 'a> {
|
||||||
if let Data::Enum(DataEnum { variants, .. }) = &input.data {
|
if let Data::Enum(DataEnum { variants, .. }) = &input.data {
|
||||||
Ok(variants.iter())
|
Ok(variants.iter())
|
||||||
} else {
|
} else {
|
||||||
Err("deriving this trait is only supported for enums")
|
bail!("deriving this trait is only supported for enums")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -382,10 +403,10 @@ fn get_field_types<'a>(
|
|||||||
|
|
||||||
fn generate_checked_bit_pattern_struct(
|
fn generate_checked_bit_pattern_struct(
|
||||||
input_ident: &Ident, fields: &Fields, attrs: &[Attribute],
|
input_ident: &Ident, fields: &Fields, attrs: &[Attribute],
|
||||||
) -> (TokenStream, TokenStream) {
|
) -> Result<(TokenStream, TokenStream)> {
|
||||||
let bits_ty = Ident::new(&format!("{}Bits", input_ident), input_ident.span());
|
let bits_ty = Ident::new(&format!("{}Bits", input_ident), input_ident.span());
|
||||||
|
|
||||||
let repr = get_repr(attrs);
|
let repr = get_repr(attrs)?;
|
||||||
|
|
||||||
let field_names = fields
|
let field_names = fields
|
||||||
.iter()
|
.iter()
|
||||||
@ -401,12 +422,9 @@ fn generate_checked_bit_pattern_struct(
|
|||||||
let field_name = &field_names[..];
|
let field_name = &field_names[..];
|
||||||
let field_ty = &field_tys[..];
|
let field_ty = &field_tys[..];
|
||||||
|
|
||||||
#[cfg(not(target_arch = "spirv"))]
|
let derive_dbg = quote!(#[cfg_attr(not(target_arch = "spirv"), derive(Debug))]);
|
||||||
let derive_dbg = quote!(#[derive(Debug)]);
|
|
||||||
#[cfg(target_arch = "spirv")]
|
|
||||||
let derive_dbg = quote!();
|
|
||||||
|
|
||||||
(
|
Ok((
|
||||||
quote! {
|
quote! {
|
||||||
#repr
|
#repr
|
||||||
#[derive(Clone, Copy, ::bytemuck::AnyBitPattern)]
|
#[derive(Clone, Copy, ::bytemuck::AnyBitPattern)]
|
||||||
@ -424,12 +442,12 @@ fn generate_checked_bit_pattern_struct(
|
|||||||
#(<#field_ty as ::bytemuck::CheckedBitPattern>::is_valid_bit_pattern(&bits.#field_name) && )* true
|
#(<#field_ty as ::bytemuck::CheckedBitPattern>::is_valid_bit_pattern(&bits.#field_name) && )* true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_checked_bit_pattern_enum(
|
fn generate_checked_bit_pattern_enum(
|
||||||
input: &DeriveInput,
|
input: &DeriveInput,
|
||||||
) -> Result<(TokenStream, TokenStream), &'static str> {
|
) -> Result<(TokenStream, TokenStream)> {
|
||||||
let span = input.span();
|
let span = input.span();
|
||||||
let mut variants_with_discriminant =
|
let mut variants_with_discriminant =
|
||||||
VariantDiscriminantIterator::new(get_enum_variants(input)?);
|
VariantDiscriminantIterator::new(get_enum_variants(input)?);
|
||||||
@ -438,7 +456,7 @@ fn generate_checked_bit_pattern_enum(
|
|||||||
(i64::max_value(), i64::min_value(), 0),
|
(i64::max_value(), i64::min_value(), 0),
|
||||||
|(min, max, count), res| {
|
|(min, max, count), res| {
|
||||||
let discriminant = res?;
|
let discriminant = res?;
|
||||||
Ok((i64::min(min, discriminant), i64::max(max, discriminant), count + 1))
|
Ok::<_, Error>((i64::min(min, discriminant), i64::max(max, discriminant), count + 1))
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@ -458,7 +476,7 @@ fn generate_checked_bit_pattern_enum(
|
|||||||
let variant = res?;
|
let variant = res?;
|
||||||
Ok(LitInt::new(&format!("{}", variant), span))
|
Ok(LitInt::new(&format!("{}", variant), span))
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Vec<_>>>()?;
|
||||||
|
|
||||||
// count is at least 1
|
// count is at least 1
|
||||||
let first = &variant_lits[0];
|
let first = &variant_lits[0];
|
||||||
@ -467,7 +485,7 @@ fn generate_checked_bit_pattern_enum(
|
|||||||
quote!(matches!(*bits, #first #(| #rest )*))
|
quote!(matches!(*bits, #first #(| #rest )*))
|
||||||
};
|
};
|
||||||
|
|
||||||
let repr = get_repr(&input.attrs);
|
let repr = get_repr(&input.attrs)?;
|
||||||
let integer_ty = repr.repr.as_integer_type().unwrap(); // should be checked in attr check already
|
let integer_ty = repr.repr.as_integer_type().unwrap(); // should be checked in attr check already
|
||||||
Ok((
|
Ok((
|
||||||
quote!(),
|
quote!(),
|
||||||
@ -487,7 +505,7 @@ fn generate_checked_bit_pattern_enum(
|
|||||||
/// is equal to the sum of the size of it's fields
|
/// is equal to the sum of the size of it's fields
|
||||||
fn generate_assert_no_padding(
|
fn generate_assert_no_padding(
|
||||||
input: &DeriveInput,
|
input: &DeriveInput,
|
||||||
) -> Result<TokenStream, &'static str> {
|
) -> Result<TokenStream> {
|
||||||
let struct_type = &input.ident;
|
let struct_type = &input.ident;
|
||||||
let span = input.ident.span();
|
let span = input.ident.span();
|
||||||
let fields = get_fields(input)?;
|
let fields = get_fields(input)?;
|
||||||
@ -512,7 +530,7 @@ fn generate_assert_no_padding(
|
|||||||
/// Check that all fields implement a given trait
|
/// Check that all fields implement a given trait
|
||||||
fn generate_fields_are_trait(
|
fn generate_fields_are_trait(
|
||||||
input: &DeriveInput, trait_: TokenStream,
|
input: &DeriveInput, trait_: TokenStream,
|
||||||
) -> Result<TokenStream, &'static str> {
|
) -> Result<TokenStream> {
|
||||||
let (impl_generics, _ty_generics, where_clause) =
|
let (impl_generics, _ty_generics, where_clause) =
|
||||||
input.generics.split_for_impl();
|
input.generics.split_for_impl();
|
||||||
let fields = get_fields(input)?;
|
let fields = get_fields(input)?;
|
||||||
@ -553,200 +571,143 @@ fn get_simple_attr(attributes: &[Attribute], attr_name: &str) -> Option<Ident> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
fn get_repr(attributes: &[Attribute]) -> Result<Representation> {
|
||||||
struct Representation {
|
attributes
|
||||||
packed: Option<u32>,
|
.iter()
|
||||||
repr: Repr,
|
.filter_map(|attr| if attr.path.is_ident("repr") {
|
||||||
}
|
Some(attr.parse_args::<Representation>())
|
||||||
|
|
||||||
impl ToTokens for Representation {
|
|
||||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
||||||
let repr = match self.repr {
|
|
||||||
Repr::Rust => None,
|
|
||||||
Repr::C => Some("C"),
|
|
||||||
Repr::Transparent => Some("transparent"),
|
|
||||||
Repr::U8 => Some("u8"),
|
|
||||||
Repr::I8 => Some("i8"),
|
|
||||||
Repr::U16 => Some("u16"),
|
|
||||||
Repr::I16 => Some("i16"),
|
|
||||||
Repr::U32 => Some("u32"),
|
|
||||||
Repr::I32 => Some("i32"),
|
|
||||||
Repr::U64 => Some("u64"),
|
|
||||||
Repr::I64 => Some("i64"),
|
|
||||||
Repr::I128 => Some("i128"),
|
|
||||||
Repr::U128 => Some("u128"),
|
|
||||||
};
|
|
||||||
if let Some(repr) = repr {
|
|
||||||
let ident = Ident::new(repr, Span::call_site());
|
|
||||||
tokens.extend(quote! {
|
|
||||||
#[repr(#ident)]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(packed) = self.packed {
|
|
||||||
let lit = LitInt::new(&packed.to_string(), Span::call_site());
|
|
||||||
tokens.extend(quote! {
|
|
||||||
#[repr(packed(#lit))]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
enum Repr {
|
|
||||||
Rust,
|
|
||||||
C,
|
|
||||||
Transparent,
|
|
||||||
U8,
|
|
||||||
I8,
|
|
||||||
U16,
|
|
||||||
I16,
|
|
||||||
U32,
|
|
||||||
I32,
|
|
||||||
U64,
|
|
||||||
I64,
|
|
||||||
I128,
|
|
||||||
U128,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Repr {
|
|
||||||
fn is_integer(&self) -> bool {
|
|
||||||
match *self {
|
|
||||||
Repr::Rust | Repr::C | Repr::Transparent => false,
|
|
||||||
Repr::U8
|
|
||||||
| Repr::I8
|
|
||||||
| Repr::U16
|
|
||||||
| Repr::I16
|
|
||||||
| Repr::U32
|
|
||||||
| Repr::I32
|
|
||||||
| Repr::U64
|
|
||||||
| Repr::I64
|
|
||||||
| Repr::I128
|
|
||||||
| Repr::U128 => true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_integer_type(&self) -> Option<TokenStream> {
|
|
||||||
match self {
|
|
||||||
Repr::Rust | Repr::C | Repr::Transparent => None,
|
|
||||||
Repr::U8 => Some(quote! { ::core::primitive::u8 }),
|
|
||||||
Repr::I8 => Some(quote! { ::core::primitive::i8 }),
|
|
||||||
Repr::U16 => Some(quote! { ::core::primitive::u16 }),
|
|
||||||
Repr::I16 => Some(quote! { ::core::primitive::i16 }),
|
|
||||||
Repr::U32 => Some(quote! { ::core::primitive::u32 }),
|
|
||||||
Repr::I32 => Some(quote! { ::core::primitive::i32 }),
|
|
||||||
Repr::U64 => Some(quote! { ::core::primitive::u64 }),
|
|
||||||
Repr::I64 => Some(quote! { ::core::primitive::i64 }),
|
|
||||||
Repr::I128 => Some(quote! { ::core::primitive::u128 }),
|
|
||||||
Repr::U128 => Some(quote! { ::core::primitive::i128 }),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_repr(attributes: &[Attribute]) -> Representation {
|
|
||||||
let mut repr = Representation { packed: None, repr: Repr::Rust };
|
|
||||||
|
|
||||||
for attr in attributes {
|
|
||||||
let meta = if let Ok(meta) = attr.parse_meta() { meta } else { continue };
|
|
||||||
if !meta.path().is_ident("repr") {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let list = if let Meta::List(list) = meta {
|
|
||||||
list
|
|
||||||
} else {
|
} else {
|
||||||
// The other `Meta` variants are illegal for `repr`.
|
None
|
||||||
continue;
|
})
|
||||||
};
|
.try_fold(Representation::default(), |a, b| {
|
||||||
|
let b = b?;
|
||||||
|
Ok(Representation {
|
||||||
|
repr: match (a.repr, b.repr) {
|
||||||
|
| (a, Repr::Rust) => a,
|
||||||
|
| (Repr::Rust, b) => b,
|
||||||
|
| _ => bail!("conflicting representation hints"),
|
||||||
|
},
|
||||||
|
packed: match (a.packed, b.packed) {
|
||||||
|
| (a, None) => a,
|
||||||
|
| (None, b) => b,
|
||||||
|
| _ => bail!("conflicting representation hints"),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
for item in list.nested {
|
mk_repr! {
|
||||||
let meta = if let NestedMeta::Meta(meta) = item {
|
U8 => u8,
|
||||||
meta
|
I8 => i8,
|
||||||
} else {
|
U16 => u16,
|
||||||
// Other nested items are illegal for `repr`.
|
I16 => i16,
|
||||||
continue;
|
U32 => u32,
|
||||||
};
|
I32 => i32,
|
||||||
|
U64 => u64,
|
||||||
|
I64 => i64,
|
||||||
|
I128 => i128,
|
||||||
|
U128 => u128,
|
||||||
|
}
|
||||||
|
// where
|
||||||
|
macro_rules! mk_repr {(
|
||||||
|
$(
|
||||||
|
$Xn:ident => $xn:ident
|
||||||
|
),* $(,)?
|
||||||
|
) => (
|
||||||
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
|
enum Repr {
|
||||||
|
Rust,
|
||||||
|
C,
|
||||||
|
Transparent,
|
||||||
|
$($Xn),*
|
||||||
|
}
|
||||||
|
|
||||||
match meta.path() {
|
impl Repr {
|
||||||
path if path.is_ident("C") => {
|
fn is_integer(self) -> bool {
|
||||||
repr.repr = Repr::C;
|
match self {
|
||||||
}
|
Repr::Rust | Repr::C | Repr::Transparent => false,
|
||||||
path if path.is_ident("transparent") => {
|
_ => true,
|
||||||
repr.repr = Repr::Transparent;
|
}
|
||||||
}
|
}
|
||||||
path if path.is_ident("u8") => {
|
|
||||||
repr.repr = Repr::U8;
|
|
||||||
}
|
|
||||||
path if path.is_ident("i8") => {
|
|
||||||
repr.repr = Repr::I8;
|
|
||||||
}
|
|
||||||
path if path.is_ident("u16") => {
|
|
||||||
repr.repr = Repr::U16;
|
|
||||||
}
|
|
||||||
path if path.is_ident("i16") => {
|
|
||||||
repr.repr = Repr::I16;
|
|
||||||
}
|
|
||||||
path if path.is_ident("u32") => {
|
|
||||||
repr.repr = Repr::U32;
|
|
||||||
}
|
|
||||||
path if path.is_ident("i32") => {
|
|
||||||
repr.repr = Repr::I32;
|
|
||||||
}
|
|
||||||
path if path.is_ident("u64") => {
|
|
||||||
repr.repr = Repr::U64;
|
|
||||||
}
|
|
||||||
path if path.is_ident("i64") => {
|
|
||||||
repr.repr = Repr::I64;
|
|
||||||
}
|
|
||||||
path if path.is_ident("u128") => {
|
|
||||||
repr.repr = Repr::U128;
|
|
||||||
}
|
|
||||||
path if path.is_ident("i128") => {
|
|
||||||
repr.repr = Repr::I128;
|
|
||||||
}
|
|
||||||
path if path.is_ident("packed") => {
|
|
||||||
let packed_alignment = match meta {
|
|
||||||
Meta::Path(_) => 1,
|
|
||||||
Meta::List(list) => {
|
|
||||||
if list.nested.len() != 1 {
|
|
||||||
// `repr(packed(n))` must have exactly one nested item.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let nested = &list.nested[0];
|
fn as_integer_type(self) -> Option<TokenStream> {
|
||||||
let int_lit = if let NestedMeta::Lit(Lit::Int(int_lit)) = nested {
|
match self {
|
||||||
int_lit
|
Repr::Rust | Repr::C | Repr::Transparent => None,
|
||||||
} else {
|
$(
|
||||||
// The nested item must be an integer literal.
|
Repr::$Xn => Some(quote! { ::core::primitive::$xn }),
|
||||||
continue;
|
)*
|
||||||
};
|
|
||||||
|
|
||||||
let value = if let Ok(value) = int_lit.base10_parse::<u32>() {
|
|
||||||
value
|
|
||||||
} else {
|
|
||||||
// The literal must be positive and less than 2^29.
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
value
|
|
||||||
}
|
|
||||||
Meta::NameValue(_) => {
|
|
||||||
// `repr(packed)` doesn't support name value syntax.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let new_packed_alignment = match repr.packed {
|
|
||||||
Some(prev) => u32::min(prev, packed_alignment),
|
|
||||||
None => packed_alignment,
|
|
||||||
};
|
|
||||||
repr.packed = Some(new_packed_alignment);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
repr
|
#[derive(Clone, Copy)]
|
||||||
}
|
struct Representation {
|
||||||
|
packed: Option<u32>,
|
||||||
|
repr: Repr,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Representation {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self { packed: None, repr: Repr::Rust }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for Representation {
|
||||||
|
fn parse(input: ParseStream<'_>) -> Result<Representation> {
|
||||||
|
let mut ret = Representation::default();
|
||||||
|
while !input.is_empty() {
|
||||||
|
let keyword = input.parse::<Ident>()?;
|
||||||
|
// preëmptively call `.to_string()` *once* (rather than on `is_ident()`)
|
||||||
|
let keyword_str = keyword.to_string();
|
||||||
|
let new_repr = match keyword_str.as_str() {
|
||||||
|
"C" => Repr::C,
|
||||||
|
"transparent" => Repr::Transparent,
|
||||||
|
"packed" => {
|
||||||
|
ret.packed = Some(if input.peek(token::Paren) {
|
||||||
|
let contents; parenthesized!(contents in input);
|
||||||
|
LitInt::base10_parse::<u32>(&contents.parse()?)?
|
||||||
|
} else {
|
||||||
|
1
|
||||||
|
});
|
||||||
|
let _: Option<Token![,]> = input.parse()?;
|
||||||
|
continue;
|
||||||
|
},
|
||||||
|
$(
|
||||||
|
stringify!($xn) => Repr::$Xn,
|
||||||
|
)*
|
||||||
|
_ => return Err(input.error("unrecognized representation hint"))
|
||||||
|
};
|
||||||
|
if ::core::mem::replace(&mut ret.repr, new_repr) != Repr::Rust {
|
||||||
|
input.error("duplicate representation hint");
|
||||||
|
}
|
||||||
|
let _: Option<Token![,]> = input.parse()?;
|
||||||
|
}
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToTokens for Representation {
|
||||||
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
|
let repr = match self.repr {
|
||||||
|
Repr::Rust => None,
|
||||||
|
Repr::C => Some(quote!(C)),
|
||||||
|
Repr::Transparent => Some(quote!(transparent)),
|
||||||
|
$(
|
||||||
|
Repr::$Xn => Some(quote!($xn)),
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
let packed = self.packed.map(|p| quote!(packed(#p)));
|
||||||
|
let comma = if packed.is_some() && repr.is_some() {
|
||||||
|
Some(quote!(,))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
tokens.extend(quote!(
|
||||||
|
#[repr( #repr #comma #packed )]
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)} use mk_repr;
|
||||||
|
|
||||||
struct VariantDiscriminantIterator<'a, I: Iterator<Item = &'a Variant> + 'a> {
|
struct VariantDiscriminantIterator<'a, I: Iterator<Item = &'a Variant> + 'a> {
|
||||||
inner: I,
|
inner: I,
|
||||||
@ -764,12 +725,15 @@ impl<'a, I: Iterator<Item = &'a Variant> + 'a>
|
|||||||
impl<'a, I: Iterator<Item = &'a Variant> + 'a> Iterator
|
impl<'a, I: Iterator<Item = &'a Variant> + 'a> Iterator
|
||||||
for VariantDiscriminantIterator<'a, I>
|
for VariantDiscriminantIterator<'a, I>
|
||||||
{
|
{
|
||||||
type Item = Result<i64, &'static str>;
|
type Item = Result<i64>;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
let variant = self.inner.next()?;
|
let variant = self.inner.next()?;
|
||||||
if !variant.fields.is_empty() {
|
if !variant.fields.is_empty() {
|
||||||
return Some(Err("Only fieldless enums are supported"));
|
return Some(Err(Error::new_spanned(
|
||||||
|
&variant.fields,
|
||||||
|
"Only fieldless enums are supported",
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some((_, discriminant)) = &variant.discriminant {
|
if let Some((_, discriminant)) = &variant.discriminant {
|
||||||
@ -786,14 +750,14 @@ impl<'a, I: Iterator<Item = &'a Variant> + 'a> Iterator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_int_expr(expr: &Expr) -> Result<i64, &'static str> {
|
fn parse_int_expr(expr: &Expr) -> Result<i64> {
|
||||||
match expr {
|
match expr {
|
||||||
Expr::Unary(ExprUnary { op: UnOp::Neg(_), expr, .. }) => {
|
Expr::Unary(ExprUnary { op: UnOp::Neg(_), expr, .. }) => {
|
||||||
parse_int_expr(expr).map(|int| -int)
|
parse_int_expr(expr).map(|int| -int)
|
||||||
}
|
}
|
||||||
Expr::Lit(ExprLit { lit: Lit::Int(int), .. }) => {
|
Expr::Lit(ExprLit { lit: Lit::Int(int), .. }) => {
|
||||||
int.base10_parse().map_err(|_| "Invalid integer expression")
|
int.base10_parse()
|
||||||
}
|
}
|
||||||
_ => Err("Not an integer expression"),
|
_ => bail!("Not an integer expression"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user