use std::collections::HashMap;
use std::fmt;
use crate::{Mesh3DDecoder, Mesh3DEncoder};
pub type DecoderFactory = Box<dyn Fn() -> Box<dyn Mesh3DDecoder> + Send + Sync>;
pub type EncoderFactory = Box<dyn Fn() -> Box<dyn Mesh3DEncoder> + Send + Sync>;
struct DecoderEntry {
factory: DecoderFactory,
extensions: Vec<String>,
}
struct EncoderEntry {
factory: EncoderFactory,
extensions: Vec<String>,
}
pub struct Mesh3DRegistry {
decoders: HashMap<String, DecoderEntry>,
encoders: HashMap<String, EncoderEntry>,
decoder_by_ext: HashMap<String, String>,
encoder_by_ext: HashMap<String, String>,
}
impl fmt::Debug for Mesh3DRegistry {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Mesh3DRegistry")
.field("decoder_formats", &self.decoders.keys().collect::<Vec<_>>())
.field("encoder_formats", &self.encoders.keys().collect::<Vec<_>>())
.finish()
}
}
impl Mesh3DRegistry {
pub fn new() -> Self {
Self {
decoders: HashMap::new(),
encoders: HashMap::new(),
decoder_by_ext: HashMap::new(),
encoder_by_ext: HashMap::new(),
}
}
pub fn register_decoder(&mut self, format: &str, extensions: &[&str], factory: DecoderFactory) {
let lc_format = format.to_ascii_lowercase();
let stored_exts: Vec<String> = extensions.iter().map(|e| e.to_ascii_lowercase()).collect();
for ext in &stored_exts {
self.decoder_by_ext.insert(ext.clone(), lc_format.clone());
}
self.decoders.insert(
lc_format,
DecoderEntry {
factory,
extensions: stored_exts,
},
);
}
pub fn register_encoder(&mut self, format: &str, extensions: &[&str], factory: EncoderFactory) {
let lc_format = format.to_ascii_lowercase();
let stored_exts: Vec<String> = extensions.iter().map(|e| e.to_ascii_lowercase()).collect();
for ext in &stored_exts {
self.encoder_by_ext.insert(ext.clone(), lc_format.clone());
}
self.encoders.insert(
lc_format,
EncoderEntry {
factory,
extensions: stored_exts,
},
);
}
pub fn decoder_for_extension(&self, ext: &str) -> Option<Box<dyn Mesh3DDecoder>> {
let key = ext.to_ascii_lowercase();
let format = self.decoder_by_ext.get(&key)?;
self.decoders.get(format).map(|e| (e.factory)())
}
pub fn encoder_for_extension(&self, ext: &str) -> Option<Box<dyn Mesh3DEncoder>> {
let key = ext.to_ascii_lowercase();
let format = self.encoder_by_ext.get(&key)?;
self.encoders.get(format).map(|e| (e.factory)())
}
pub fn decoder_for_format(&self, format: &str) -> Option<Box<dyn Mesh3DDecoder>> {
let key = format.to_ascii_lowercase();
self.decoders.get(&key).map(|e| (e.factory)())
}
pub fn encoder_for_format(&self, format: &str) -> Option<Box<dyn Mesh3DEncoder>> {
let key = format.to_ascii_lowercase();
self.encoders.get(&key).map(|e| (e.factory)())
}
pub fn decoder_formats(&self) -> impl Iterator<Item = &str> {
self.decoders.keys().map(String::as_str)
}
pub fn encoder_formats(&self) -> impl Iterator<Item = &str> {
self.encoders.keys().map(String::as_str)
}
pub fn decoder_extensions(&self, format: &str) -> Option<&[String]> {
self.decoders
.get(&format.to_ascii_lowercase())
.map(|e| e.extensions.as_slice())
}
pub fn encoder_extensions(&self, format: &str) -> Option<&[String]> {
self.encoders
.get(&format.to_ascii_lowercase())
.map(|e| e.extensions.as_slice())
}
}
impl Default for Mesh3DRegistry {
fn default() -> Self {
Self::new()
}
}