use std::{collections::{BTreeMap, HashSet}, sync::Arc};
use bytes::Bytes;
use crate::{lang::SError, SDoc, SNodeRef};
#[derive(Default, Clone)]
pub struct SFormats {
pub formats: BTreeMap<String, Arc<dyn Format>>,
}
impl SFormats {
pub fn insert(&mut self, format: Arc<dyn Format>) {
self.formats.insert(format.format(), format);
}
pub fn get(&self, format: &str) -> Option<Arc<dyn Format>> {
self.formats.get(format).cloned()
}
pub fn available(&self) -> HashSet<String> {
let mut formats = HashSet::new();
for (format, _) in &self.formats {
formats.insert(format.clone());
}
formats
}
pub fn content_type(&self, format: &str) -> Option<String> {
if let Some(format) = self.get(format) {
return Some(format.content_type());
}
None
}
pub fn header_import(&self, format: &str, pid: &str, doc: &mut SDoc, content_type: &str, bytes: &mut Bytes, as_name: &str) -> Result<(), SError> {
if let Some(format) = self.get(format) {
return format.header_import(pid, doc, content_type, bytes, as_name);
} else {
let mut fallbacks = Vec::new();
for (fmt, imp) in &self.formats {
let ctt = imp.content_type();
if ctt == content_type {
return imp.header_import(pid, doc, content_type, bytes, as_name);
} else if content_type.contains(&ctt) || content_type.contains(fmt) {
fallbacks.push(imp);
}
}
for fallback in fallbacks {
if let Ok(_) = fallback.header_import(pid, doc, content_type, bytes, as_name) {
return Ok(());
}
}
if format != "bytes" {
return self.header_import("bytes", pid, doc, content_type, bytes, as_name);
}
}
Err(SError::fmt(pid, &doc, format, "header import (bytes) - format not found"))
}
pub fn string_import(&self, format: &str, pid: &str, doc: &mut SDoc, src: &str, as_name: &str) -> Result<(), SError> {
if let Some(format) = self.get(format) {
return format.string_import(pid, doc, src, as_name);
}
Err(SError::fmt(pid, &doc, format, "import string - format not found"))
}
pub fn file_import(&self, format: &str, pid: &str, doc: &mut SDoc, full_path: &str, extension: &str, as_name: &str) -> Result<(), SError> {
if let Some(fmt) = self.get(format) {
return fmt.file_import(pid, doc, format, full_path, extension, as_name);
}
Err(SError::fmt(pid, &doc, format, "import file - format not found"))
}
pub fn export_string(&self, format: &str, pid: &str, doc: &SDoc, node: Option<&SNodeRef>) -> Result<String, SError> {
if let Some(format) = self.get(format) {
return format.export_string(pid, doc, node);
}
Err(SError::fmt(pid, &doc, format, "export string - format not found"))
}
pub fn export_min_string(&self, format: &str, pid: &str, doc: &SDoc, node: Option<&SNodeRef>) -> Result<String, SError> {
if let Some(format) = self.get(format) {
return format.export_min_string(pid, doc, node);
}
Err(SError::fmt(pid, &doc, format, "export min string - format not found"))
}
pub fn export_bytes(&self, format: &str, pid: &str, doc: &SDoc, node: Option<&SNodeRef>) -> Result<Bytes, SError> {
if let Some(format) = self.get(format) {
return format.export_bytes(pid, doc, node);
}
Err(SError::fmt(pid, &doc, format, "export bytes - format not found"))
}
}
pub trait Format: Send + Sync {
#[allow(unused)]
fn format(&self) -> String {
"text".to_string()
}
#[allow(unused)]
fn content_type(&self) -> String {
"text/plain".to_owned()
}
#[allow(unused)]
fn header_import(&self, pid: &str, doc: &mut SDoc, content_type: &str, bytes: &mut Bytes, as_name: &str) -> Result<(), SError> {
Err(SError::fmt(pid, &doc, &self.format(), "header import not implemented"))
}
#[allow(unused)]
fn string_import(&self, pid: &str, doc: &mut SDoc, src: &str, as_name: &str) -> Result<(), SError> {
Err(SError::fmt(pid, &doc, &self.format(), "string import not implemented"))
}
#[allow(unused)]
fn file_import(&self, pid: &str, doc: &mut SDoc, format: &str, full_path: &str, extension: &str, as_name: &str) -> Result<(), SError> {
Err(SError::fmt(pid, &doc, &self.format(), "file import not implemented"))
}
#[allow(unused)]
fn export_string(&self, pid: &str, doc: &SDoc, node: Option<&SNodeRef>) -> Result<String, SError> {
Err(SError::fmt(pid, &doc, &self.format(), "export string not implemented"))
}
#[allow(unused)]
fn export_min_string(&self, pid: &str, doc: &SDoc, node: Option<&SNodeRef>) -> Result<String, SError> {
self.export_string(pid, doc, node)
}
#[allow(unused)]
fn export_bytes(&self, pid: &str, doc: &SDoc, node: Option<&SNodeRef>) -> Result<Bytes, SError> {
if let Ok(res) = self.export_min_string(pid, doc, node) {
return Ok(Bytes::from(res));
}
Err(SError::fmt(pid, &doc, &self.format(), "export bytes not implemented"))
}
}