static-regular-grammar 2.0.2

Derive macro for static regular grammar
Documentation
use std::{borrow::Cow, env, path::PathBuf};

use proc_macro2::{Ident, Span};

use crate::{attribute::SizedTypeAttributes, Attribute, Error};

pub struct Options {
	pub file: Option<PathBuf>,
	pub entry_point: Option<String>,
	pub name: Option<String>,
	pub sized: Option<SizedTypeOptions>,
	pub cache_path: PathBuf,
	pub no_deref: bool,
	pub no_borrow: bool,
	pub ascii: bool,
	pub disable: bool,
	pub serde: bool,
}

impl Options {
	pub(crate) fn from_attribute(ident: &Ident, attr: Attribute) -> Result<Self, (Error, Span)> {
		Ok(Self {
			file: attr.file,
			entry_point: attr.entry_point,
			name: attr.name,
			sized: match attr.sized {
				Some(attr) => Some(SizedTypeOptions::from_attribute(attr, ident.span())?),
				None => None,
			},
			cache_path: build_cache_path(ident, attr.cache_path)?,
			no_deref: attr.no_deref,
			no_borrow: attr.no_borrow,
			ascii: attr.ascii,
			disable: attr.disable,
			serde: attr.serde,
		})
	}
}

fn find_target_dir() -> Result<Cow<'static, str>, std::env::VarError> {
	match std::env::var("OUT_DIR") {
		Ok(dir) => Ok(Cow::Owned(dir)),
		Err(std::env::VarError::NotPresent) => match std::env::var("CARGO_TARGET_DIR") {
			Ok(dir) => Ok(Cow::Owned(dir)),
			Err(std::env::VarError::NotPresent) => Ok(Cow::Borrowed("target")),
			Err(e) => Err(e),
		},
		Err(e) => Err(e),
	}
}

fn build_cache_path(ident: &Ident, path: Option<PathBuf>) -> Result<PathBuf, (Error, Span)> {
	match path {
		Some(relative_path) => match env::var("CARGO_MANIFEST_DIR") {
			Ok(manifest_dir) => {
				let mut path: PathBuf = manifest_dir.into();
				path.extend(&relative_path);
				Ok(path)
			}
			Err(e) => Err((Error::Var(e), ident.span())),
		},
		None => {
			let target =
				find_target_dir().map_err(|e| (Error::TargetDirNotFound(e), ident.span()))?;
			Ok(format!("{target}/regular-grammar/{}.automaton.cbor", ident).into())
		}
	}
}

#[derive(Default)]
pub struct Derives {
	pub debug: bool,
	pub display: bool,
	pub partial_eq: bool,
	pub eq: bool,
	pub partial_ord: bool,
	pub ord: bool,
	pub hash: bool,
}

impl Derives {
	pub fn append(&mut self, other: Self) {
		self.debug |= other.debug;
		self.display |= other.display;
		self.partial_eq |= other.partial_eq;
		self.eq |= other.eq;
		self.partial_ord |= other.partial_ord;
		self.ord |= other.ord;
		self.hash |= other.hash
	}
}

pub struct SizedTypeOptions {
	pub ident: Ident,
	pub derives: Derives,
}

impl SizedTypeOptions {
	pub(crate) fn from_attribute(
		attr: SizedTypeAttributes,
		span: Span,
	) -> Result<Self, (Error, Span)> {
		Ok(Self {
			ident: attr
				.ident
				.ok_or_else(|| (Error::MissingSizedTypeIdent, span))?,
			derives: attr.derives,
		})
	}
}