use std::num::NonZeroUsize;
use crate::Version;
mod kind;
pub use kind::Kind;
use serde::Deserialize;
use serde::Serialize;
#[derive(Debug)]
pub enum Error {
InvalidIndex(usize),
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Error::InvalidIndex(index) => write!(f, "invalid index: {index}"),
}
}
}
impl std::error::Error for Error {}
type Result<T> = std::result::Result<T, Error>;
#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct Code {
kind: Kind,
grammar: Version,
index: NonZeroUsize,
}
impl Code {
pub fn try_new(kind: Kind, grammar: Version, index: usize) -> Result<Self> {
let index = NonZeroUsize::try_from(index).map_err(|_| Error::InvalidIndex(index))?;
Ok(Self {
kind,
grammar,
index,
})
}
pub fn kind(&self) -> &Kind {
&self.kind
}
pub fn grammar(&self) -> &Version {
&self.grammar
}
pub fn index(&self) -> NonZeroUsize {
self.index
}
}
impl std::fmt::Display for Code {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}::{}{:03}",
self.grammar.short_name(),
self.kind.prefix(),
self.index
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn zero_index() {
let err = Code::try_new(Kind::Error, Version::V1, 0).unwrap_err();
assert!(matches!(err, Error::InvalidIndex(0)));
}
#[test]
fn display() {
let identity = Code::try_new(Kind::Error, Version::V1, 1).unwrap();
assert_eq!(identity.to_string(), String::from("v1::E001"));
let identity = Code::try_new(Kind::Warning, Version::V1, 1).unwrap();
assert_eq!(identity.to_string(), String::from("v1::W001"));
}
}