mirror of
https://codeberg.org/icewind/bitbuffer.git
synced 2026-06-04 00:54:07 +02:00
rewrite derive macro
This commit is contained in:
parent
0701318120
commit
3852f09dd5
21 changed files with 1548 additions and 840 deletions
|
|
@ -1,36 +1,105 @@
|
|||
use syn::{Expr, Lit, Variant};
|
||||
use syn_util::get_attribute_value;
|
||||
use crate::err;
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::{quote, quote_spanned};
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use syn::spanned::Spanned;
|
||||
use syn::{Error, Expr, ExprLit, Lit, LitInt};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum Discriminant {
|
||||
Int(usize),
|
||||
Default,
|
||||
Wildcard,
|
||||
}
|
||||
|
||||
impl From<Lit> for Discriminant {
|
||||
fn from(lit: Lit) -> Self {
|
||||
match lit {
|
||||
Lit::Int(lit) => Discriminant::Int(lit.base10_parse::<usize>().unwrap()),
|
||||
Lit::Str(lit) => match lit.value().as_str() {
|
||||
"_" => Discriminant::Wildcard,
|
||||
_ => panic!("discriminant is required to be an integer literal or \"_\""),
|
||||
},
|
||||
_ => panic!("discriminant is required to be an integer literal or \"_\""),
|
||||
impl TryFrom<Expr> for Discriminant {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: Expr) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
Expr::Lit(ExprLit { lit, .. }) => lit.try_into(),
|
||||
_ => err("non literal discriminant", value.span())?,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Variant> for Discriminant {
|
||||
fn from(variant: &Variant) -> Self {
|
||||
variant
|
||||
.discriminant
|
||||
.as_ref()
|
||||
.map(|(_, expr)| match expr {
|
||||
Expr::Lit(expr_lit) => expr_lit.lit.clone(),
|
||||
_ => panic!("discriminant is required to be an integer literal"),
|
||||
})
|
||||
.or_else(|| get_attribute_value(&variant.attrs, &["discriminant"]))
|
||||
.map(Discriminant::from)
|
||||
.unwrap_or(Discriminant::Default)
|
||||
impl TryFrom<Lit> for Discriminant {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: Lit) -> Result<Self, Self::Error> {
|
||||
let span = value.span();
|
||||
match value {
|
||||
Lit::Int(lit) => Ok(Discriminant::Int(lit.base10_parse()?)),
|
||||
Lit::Str(lit) => match lit.value().as_str() {
|
||||
"_" => Ok(Discriminant::Wildcard),
|
||||
_ => err(
|
||||
"discriminant is required to be an integer literal or \"_\"",
|
||||
span,
|
||||
),
|
||||
},
|
||||
_ => err(
|
||||
"discriminant is required to be an integer literal or \"_\"",
|
||||
span,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Discriminant {
|
||||
pub fn read_token(&self, last_discriminant: &mut isize, span: Span) -> TokenStream {
|
||||
match self {
|
||||
Discriminant::Int(discriminant) => {
|
||||
let lit = LitInt::new(&format!("{}", discriminant), span);
|
||||
*last_discriminant = *discriminant as isize;
|
||||
quote! { #lit }
|
||||
}
|
||||
Discriminant::Wildcard => quote! { _ },
|
||||
Discriminant::Default => {
|
||||
let new_discriminant = (*last_discriminant + 1) as usize;
|
||||
let lit = LitInt::new(&format!("{}", new_discriminant), span);
|
||||
*last_discriminant += 1;
|
||||
quote! { #lit }
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn write_token(
|
||||
&self,
|
||||
last_discriminant: &mut isize,
|
||||
max_discriminant: usize,
|
||||
span: Span,
|
||||
) -> TokenStream {
|
||||
match self {
|
||||
Discriminant::Int(discriminant) => {
|
||||
let lit = LitInt::new(&format!("{}", discriminant), span);
|
||||
*last_discriminant = *discriminant as isize;
|
||||
quote_spanned! { span => #lit }
|
||||
}
|
||||
Discriminant::Wildcard => {
|
||||
let free_discriminant = max_discriminant + 1;
|
||||
let lit = LitInt::new(&format!("{}", free_discriminant), span);
|
||||
quote_spanned! { span => #lit }
|
||||
}
|
||||
Discriminant::Default => {
|
||||
let new_discriminant = (*last_discriminant + 1) as usize;
|
||||
let lit = LitInt::new(&format!("{}", new_discriminant), span);
|
||||
*last_discriminant += 1;
|
||||
quote_spanned! { span => #lit }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn max_value(&self, last_discriminant: &mut isize) -> usize {
|
||||
match self {
|
||||
Discriminant::Int(discriminant) => {
|
||||
*last_discriminant = *discriminant as isize;
|
||||
*discriminant
|
||||
}
|
||||
Discriminant::Wildcard => 0,
|
||||
Discriminant::Default => {
|
||||
let new_discriminant = (*last_discriminant + 1) as usize;
|
||||
*last_discriminant += 1;
|
||||
new_discriminant
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue