use compact_str::CompactString;
use crate::{prefix_parser::AcceptsPrefix, span::Span, unit::CanonicalName};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Decorator<'a> {
MetricPrefixes,
BinaryPrefixes,
Abbreviation,
Aliases(Vec<(&'a str, Option<AcceptsPrefix>, Span)>),
Url(CompactString),
Name(CompactString),
Description(CompactString),
Example(CompactString, Option<CompactString>),
}
fn name_and_aliases_inner<'a, T: 'a>(
name: &'a str,
decorators: &'a [Decorator],
f: impl 'a + Fn(&'a str, AcceptsPrefix, Option<Span>) -> T,
) -> impl 'a + Iterator<Item = T> {
let mut aliases_vec = vec![f(name, AcceptsPrefix::only_long(), None)];
for decorator in decorators {
if let Decorator::Aliases(aliases) = decorator {
for (n, ap, span) in aliases {
let ap = ap.unwrap_or(AcceptsPrefix::only_long());
if *n == name {
aliases_vec[0] = f(n, ap, None);
} else {
aliases_vec.push(f(n, ap, Some(*span)));
}
}
}
}
aliases_vec.into_iter()
}
pub fn name_and_aliases<'a>(
name: &'a str,
decorators: &'a [Decorator],
) -> impl 'a + Iterator<Item = (&'a str, AcceptsPrefix)> {
name_and_aliases_inner(name, decorators, |n, accepts_prefix, _| (n, accepts_prefix))
}
pub fn name_and_aliases_spans<'a>(
name: &'a str,
name_span: Span,
decorators: &'a [Decorator],
) -> impl 'a + Iterator<Item = (&'a str, AcceptsPrefix, Span)> {
name_and_aliases_inner(name, decorators, move |n, accepts_prefix, span| {
(n, accepts_prefix, span.unwrap_or(name_span))
})
}
pub fn get_canonical_unit_name(unit_name: &str, decorators: &[Decorator]) -> CanonicalName {
for decorator in decorators {
if let Decorator::Aliases(aliases) = decorator {
for (alias, accepts_prefix, _) in aliases {
match accepts_prefix {
&Some(ap) if ap.short => {
return CanonicalName::new(alias, ap);
}
_ => {}
}
}
}
}
CanonicalName {
name: unit_name.into(),
accepts_prefix: AcceptsPrefix::only_long(),
}
}
pub fn name<'a>(decorators: &'a [Decorator<'a>]) -> Option<&'a str> {
for decorator in decorators {
if let Decorator::Name(name) = decorator {
return Some(name);
}
}
None
}
pub fn url<'a>(decorators: &'a [Decorator<'a>]) -> Option<&'a str> {
for decorator in decorators {
if let Decorator::Url(url) = decorator {
return Some(url);
}
}
None
}
pub fn description(decorators: &[Decorator]) -> Option<CompactString> {
let mut description = CompactString::with_capacity(decorators.len());
for decorator in decorators {
if let Decorator::Description(d) = decorator {
description += d;
description += "\n";
}
}
if !description.is_empty() {
Some(description)
} else {
None
}
}
pub fn examples(decorators: &[Decorator]) -> Vec<(CompactString, Option<CompactString>)> {
let mut examples = Vec::new();
for decorator in decorators {
if let Decorator::Example(example_code, example_description) = decorator {
examples.push((example_code.clone(), example_description.clone()));
}
}
examples
}
pub fn contains_aliases_with_prefixes(decorates: &[Decorator]) -> bool {
for decorator in decorates {
if let Decorator::Aliases(aliases) = decorator
&& aliases.iter().any(|(_, prefixes, _)| prefixes.is_some())
{
return true;
}
}
false
}
pub fn contains_aliases(decorators: &[Decorator]) -> bool {
for decorator in decorators {
if let Decorator::Aliases(_) = decorator {
return true;
}
}
false
}
pub fn contains_examples(decorators: &[Decorator]) -> bool {
for decorator in decorators {
if let Decorator::Example(_, _) = decorator {
return true;
}
}
false
}
pub fn contains_abbreviation(decorators: &[Decorator]) -> bool {
for decorator in decorators {
if let Decorator::Abbreviation = decorator {
return true;
}
}
false
}