mirror of
https://codeberg.org/icewind/bitbuffer.git
synced 2026-06-04 00:54:07 +02:00
105 lines
3.4 KiB
Rust
105 lines
3.4 KiB
Rust
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 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 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
|
|
}
|
|
}
|
|
}
|
|
}
|