#![allow(clippy::expect_used, reason = "proc macro okay to panic")]
mod parsers;
pub(crate) use parsers::*;
use quote::ToTokens;
use syn::parse::Parser;
pub(crate) const KLV_ATTR: Symbol = Symbol(crate::ATTR_NAME);
pub(crate) const KEY: Symbol = Symbol("key");
pub(crate) const TYPE: Symbol = Symbol("typ");
pub(crate) const DEBUG: Symbol = Symbol("debug");
pub(crate) const LENGTH: Symbol = Symbol("len");
pub(crate) const ENCODER: Symbol = Symbol("enc");
pub(crate) const DECODER: Symbol = Symbol("dec");
pub(crate) const STREAM: Symbol = Symbol("stream");
pub(crate) const DEFAULT: Symbol = Symbol("default");
pub(crate) const SENTINEL: Symbol = Symbol("sentinel");
pub(crate) const DEFAULT_VALUE: Symbol = Symbol("default");
pub(crate) const VARIABLE_LENGTH: Symbol = Symbol("varlen");
pub(crate) const LATEBIND: Symbol = Symbol("latebind");
pub(crate) const DENY_UNKNOWN_KEYS: Symbol = Symbol("deny_unknown_keys");
pub(crate) const ALLOW_UNIMPLEMENTED_DECODE: Symbol = Symbol("allow_unimplemented_decode");
pub(crate) const ALLOW_UNIMPLEMENTED_ENCODE: Symbol = Symbol("allow_unimplemented_encode");
pub(crate) const TRAIT_FALLBACK: Symbol = Symbol("trait_fallback");
pub(crate) static CONT_SYMBOLS: Symbols = Symbols(&[
KEY,
LENGTH,
STREAM,
DEFAULT,
SENTINEL,
DENY_UNKNOWN_KEYS,
ALLOW_UNIMPLEMENTED_DECODE,
ALLOW_UNIMPLEMENTED_ENCODE,
TRAIT_FALLBACK,
]);
pub(crate) static CONT_LIST_SYMBOLS: Symbols = Symbols(&[KEY, LENGTH, DEFAULT]);
pub(crate) static CONT_DEFAULT_LIST_SYMBOLS: Symbols =
Symbols(&[TYPE, ENCODER, DECODER, VARIABLE_LENGTH]);
pub(crate) static CONT_NV_SYMBOLS: Symbols = Symbols(&[STREAM, SENTINEL]);
pub(crate) static FIELD_SYMBOLS: Symbols = Symbols(&[
KEY,
ENCODER,
DECODER,
VARIABLE_LENGTH,
LATEBIND,
DEFAULT_VALUE,
]);
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub(crate) struct Symbol(pub(crate) &'static str);
impl std::fmt::Display for Symbol {
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str(self.0)
}
}
pub(crate) const UNKNOWN: Symbol = Symbol("<unknown>");
const KNOWN: &[Symbol] = &[
KLV_ATTR,
KEY,
TYPE,
DEBUG,
LENGTH,
ENCODER,
DECODER,
STREAM,
DEFAULT,
SENTINEL,
DEFAULT_VALUE,
VARIABLE_LENGTH,
LATEBIND,
DENY_UNKNOWN_KEYS,
ALLOW_UNIMPLEMENTED_DECODE,
ALLOW_UNIMPLEMENTED_ENCODE,
TRAIT_FALLBACK,
];
impl From<&syn::Path> for Symbol {
fn from(path: &syn::Path) -> Self {
let last = path.segments.last().expect("path has no segments");
for sym in KNOWN {
if last.ident == sym.0 {
return *sym;
}
}
UNKNOWN
}
}
impl From<Symbol> for syn::Path {
fn from(symbol: Symbol) -> Self {
syn::parse_str(symbol.0).expect("?")
}
}
impl ToTokens for Symbol {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
#[allow(clippy::unwrap_used)] let ident: syn::Ident = syn::parse_str(self.0).unwrap();
tokens.extend(quote::quote! { #ident })
}
}
impl PartialEq<Symbol> for syn::Path {
fn eq(&self, word: &Symbol) -> bool {
self.is_ident(word.0)
}
}
impl PartialEq<Symbol> for &syn::Path {
fn eq(&self, word: &Symbol) -> bool {
self.is_ident(word.0)
}
}
pub(crate) struct Symbols<'a>(&'a [Symbol]);
impl std::fmt::Display for Symbols<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut symbols = self.0.to_vec();
symbols.sort_by(|a, b| b.0.cmp(a.0));
symbols
.iter()
.try_for_each(|symbol| write!(f, "`{}` ", symbol.0))
}
}