use std::collections::HashMap;
use std::fmt;
use std::sync::Arc;
use crate::language_parser::{BuiltInLanguageParser, LanguageParser};
use crate::{LinkNetwork, ParseConfiguration};
#[derive(Clone)]
pub struct ParserRegistry {
parsers: HashMap<String, Arc<dyn LanguageParser>>,
fallback: Arc<dyn LanguageParser>,
}
impl ParserRegistry {
#[must_use]
pub fn new() -> Self {
Self {
parsers: HashMap::new(),
fallback: Arc::new(BuiltInLanguageParser),
}
}
pub fn register(
&mut self,
language: impl Into<String>,
parser: Arc<dyn LanguageParser>,
) -> &mut Self {
let key: String = language.into();
self.parsers.insert(normalize(&key), parser);
self
}
#[must_use]
pub fn with_parser(
mut self,
language: impl Into<String>,
parser: Arc<dyn LanguageParser>,
) -> Self {
self.register(language, parser);
self
}
#[must_use]
pub fn parser_for(&self, language: &str) -> Option<&Arc<dyn LanguageParser>> {
self.parsers.get(&normalize(language))
}
#[must_use]
pub fn is_registered(&self, language: &str) -> bool {
self.parsers.contains_key(&normalize(language))
}
#[must_use]
pub fn len(&self) -> usize {
self.parsers.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.parsers.is_empty()
}
#[must_use]
pub fn parse(
&self,
text: &str,
language: &str,
configuration: ParseConfiguration,
) -> LinkNetwork {
self.parsers.get(&normalize(language)).map_or_else(
|| self.fallback.parse_source(text, language, configuration),
|parser| parser.parse_source(text, language, configuration),
)
}
}
impl Default for ParserRegistry {
fn default() -> Self {
Self::new()
}
}
impl LinkNetwork {
#[must_use]
pub fn parse_with_registry(
registry: &ParserRegistry,
text: &str,
language: &str,
configuration: ParseConfiguration,
) -> Self {
registry.parse(text, language, configuration)
}
}
impl fmt::Debug for ParserRegistry {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut keys: Vec<&str> = self.parsers.keys().map(String::as_str).collect();
keys.sort_unstable();
f.debug_struct("ParserRegistry")
.field("registered", &keys)
.finish_non_exhaustive()
}
}
fn normalize(language: &str) -> String {
language.to_ascii_lowercase()
}