mod change_id;
mod error;
mod module_id;
mod spec_id;
pub(crate) mod sub_module_id;
pub use change_id::parse_change_id;
pub use change_id::{ChangeId, ParsedChangeId};
pub use error::IdParseError;
pub use module_id::parse_module_id;
pub use module_id::{ModuleId, ParsedModuleId};
pub use spec_id::parse_spec_id;
pub use spec_id::{ParsedSpecId, SpecId};
pub use sub_module_id::parse_sub_module_id;
pub use sub_module_id::{ParsedSubModuleId, SubModuleId};
pub(crate) fn is_all_ascii_digits(s: &str) -> bool {
if s.is_empty() {
return false;
}
for c in s.chars() {
if !c.is_ascii_digit() {
return false;
}
}
true
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ItoIdKind {
ModuleId,
SubModuleId,
ModuleChangeId,
SubModuleChangeId,
}
pub fn classify_id(input: &str) -> ItoIdKind {
let prefix = match input.split_once('_') {
Some((left, _)) => left,
None => input,
};
let has_dot = prefix.contains('.');
let has_hyphen = prefix.contains('-');
if has_dot && has_hyphen {
ItoIdKind::SubModuleChangeId
} else if has_dot {
ItoIdKind::SubModuleId
} else if has_hyphen {
ItoIdKind::ModuleChangeId
} else {
ItoIdKind::ModuleId
}
}
pub fn looks_like_change_id(input: &str) -> bool {
let input = input.trim();
if input.is_empty() {
return false;
}
let mut digit_prefix_len = 0usize;
let mut has_hyphen = false;
let mut has_underscore = false;
for ch in input.chars() {
if ch.is_ascii_digit() && digit_prefix_len == 0 {
digit_prefix_len = 1;
continue;
}
if ch.is_ascii_digit() && digit_prefix_len > 0 {
digit_prefix_len += 1;
continue;
}
if digit_prefix_len == 0 {
break;
}
match ch {
'-' => has_hyphen = true,
'_' => has_underscore = true,
'.' => {}
_ => {}
}
}
digit_prefix_len > 0 && has_hyphen && has_underscore
}
pub fn looks_like_module_id(input: &str) -> bool {
let input = input.trim();
let Some(first) = input.chars().next() else {
return false;
};
first.is_ascii_digit()
}
#[cfg(test)]
mod id_tests;