use std::path::Path;
use std::sync::OnceLock;
use crate::{
MimeConfig,
MimeDetectionPolicy,
MimeDetector,
MimeDetectorCore,
MimeRepository,
MimeResult,
StreamBasedMimeDetector,
};
const DEFAULT_DATABASE: &str = include_str!("../../resources/freedesktop.org-v2.4.xml");
static DEFAULT_REPOSITORY: OnceLock<MimeRepository> = OnceLock::new();
#[derive(Debug, Clone)]
pub struct RepositoryMimeDetector<'a> {
core: MimeDetectorCore,
repository: &'a MimeRepository,
}
impl RepositoryMimeDetector<'static> {
pub fn new() -> MimeResult<Self> {
Ok(Self::with_repository(default_repository()))
}
pub fn from_mime_config(config: MimeConfig) -> Self {
Self::with_repository_and_config(default_repository(), config)
}
}
impl Default for RepositoryMimeDetector<'static> {
fn default() -> Self {
Self::new().expect("embedded MIME repository should parse")
}
}
impl<'a> RepositoryMimeDetector<'a> {
pub fn with_repository(repository: &'a MimeRepository) -> Self {
Self::with_repository_and_config(repository, MimeConfig::default())
}
pub fn with_repository_and_config(repository: &'a MimeRepository, config: MimeConfig) -> Self {
Self {
core: MimeDetectorCore::from_mime_config(config),
repository,
}
}
pub fn core(&self) -> &MimeDetectorCore {
&self.core
}
pub fn core_mut(&mut self) -> &mut MimeDetectorCore {
&mut self.core
}
pub fn repository(&self) -> &'a MimeRepository {
self.repository
}
pub fn detect_by_filename(&self, filename: &str) -> Option<String> {
<Self as MimeDetector>::detect_by_filename(self, filename)
}
pub fn detect_by_content(&self, bytes: &[u8]) -> Option<String> {
<Self as MimeDetector>::detect_by_content(self, bytes)
}
pub fn detect_bytes(
&self,
bytes: &[u8],
filename: Option<&str>,
policy: MimeDetectionPolicy,
) -> Option<String> {
self.detect(bytes, filename, policy)
}
pub fn detect_reader(
&self,
reader: &mut dyn qubit_io::ReadSeek,
filename: Option<&str>,
policy: MimeDetectionPolicy,
) -> MimeResult<Option<String>> {
<Self as MimeDetector>::detect_reader(self, reader, filename, policy)
}
pub fn detect_file(
&self,
file: &Path,
policy: MimeDetectionPolicy,
) -> MimeResult<Option<String>> {
<Self as MimeDetector>::detect_file(self, file, policy)
}
pub fn guess_from_filename(&self, filename: &str) -> Vec<String> {
self.repository
.detect_by_filename(filename)
.into_iter()
.map(|mime_type| mime_type.name().to_owned())
.collect()
}
pub fn guess_from_content(&self, bytes: &[u8]) -> Vec<String> {
self.repository
.detect_by_content(bytes)
.into_iter()
.map(|mime_type| mime_type.name().to_owned())
.collect()
}
}
pub(crate) fn default_repository() -> &'static MimeRepository {
DEFAULT_REPOSITORY.get_or_init(|| {
MimeRepository::from_xml(DEFAULT_DATABASE)
.expect("embedded freedesktop MIME database should parse")
})
}
impl<'a> StreamBasedMimeDetector for RepositoryMimeDetector<'a> {
fn core(&self) -> &MimeDetectorCore {
&self.core
}
fn max_test_bytes(&self) -> usize {
self.repository.max_test_bytes()
}
fn guess_from_filename(&self, filename: &str) -> Vec<String> {
RepositoryMimeDetector::guess_from_filename(self, filename)
}
fn guess_from_content_bytes(&self, content: &[u8]) -> MimeResult<Vec<String>> {
Ok(RepositoryMimeDetector::guess_from_content(self, content))
}
}