use super::*; #[derive( EnumDiscriminants, PartialEq, Debug, Clone, Serialize, Ord, PartialOrd, Eq, IntoStaticStr, )] #[strum(serialize_all = "kebab-case")] #[serde(rename_all = "kebab-case")] #[strum_discriminants(name(AttributeDiscriminant))] #[strum_discriminants(derive(EnumString))] #[strum_discriminants(strum(serialize_all = "kebab-case"))] pub(crate) enum Attribute<'src> { Confirm(Option>), Group(StringLiteral<'src>), Linux, Macos, NoCd, NoExitMessage, NoQuiet, Private, Unix, Windows, } impl AttributeDiscriminant { fn argument_range(self) -> RangeInclusive { match self { Self::Confirm => 0..=1, Self::Group => 1..=1, Self::Linux | Self::Macos | Self::NoCd | Self::NoExitMessage | Self::NoQuiet | Self::Private | Self::Unix | Self::Windows => 0..=0, } } } impl<'src> Attribute<'src> { pub(crate) fn new( name: Name<'src>, argument: Option>, ) -> CompileResult<'src, Self> { use AttributeDiscriminant::*; let discriminant = name .lexeme() .parse::() .ok() .ok_or_else(|| { name.error(CompileErrorKind::UnknownAttribute { attribute: name.lexeme(), }) })?; let found = argument.as_ref().iter().count(); let range = discriminant.argument_range(); if !range.contains(&found) { return Err( name.error(CompileErrorKind::AttributeArgumentCountMismatch { attribute: name.lexeme(), found, min: *range.start(), max: *range.end(), }), ); } Ok(match discriminant { Confirm => Self::Confirm(argument), Group => Self::Group(argument.unwrap()), Linux => Self::Linux, Macos => Self::Macos, NoCd => Self::NoCd, NoExitMessage => Self::NoExitMessage, NoQuiet => Self::NoQuiet, Private => Self::Private, Unix => Self::Unix, Windows => Self::Windows, }) } pub(crate) fn name(&self) -> &'static str { self.into() } fn argument(&self) -> Option<&StringLiteral> { match self { Self::Confirm(prompt) => prompt.as_ref(), Self::Group(name) => Some(name), Self::Linux | Self::Macos | Self::NoCd | Self::NoExitMessage | Self::NoQuiet | Self::Private | Self::Unix | Self::Windows => None, } } } impl<'src> Display for Attribute<'src> { fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { write!(f, "{}", self.name())?; if let Some(argument) = self.argument() { write!(f, "({argument})")?; } Ok(()) } } #[cfg(test)] mod tests { use super::*; #[test] fn name() { assert_eq!(Attribute::NoExitMessage.name(), "no-exit-message"); } }