#[cfg(feature = "docx")]
use std::io::Cursor;
use std::io::{Read, Seek};
use docspec_core::{Event, EventSource, Result};
#[cfg(feature = "docx")]
use docspec_docx_reader::DocxReader;
#[cfg(feature = "html")]
use docspec_html_reader::HtmlReader;
#[cfg(feature = "markdown")]
use docspec_markdown_reader::MarkdownReader;
use crate::format::InputFormat;
#[non_exhaustive]
pub enum AnyReader {
#[cfg(feature = "html")]
Html(HtmlReader),
#[cfg(feature = "markdown")]
Markdown(MarkdownReader),
#[cfg(feature = "docx")]
Docx(DocxReader),
}
impl AnyReader {
#[inline]
pub fn from_path<P: AsRef<std::path::Path>>(format: InputFormat, path: P) -> Result<Self> {
let file = std::fs::File::open(path.as_ref())
.map_err(|source| docspec_core::Error::Io { source })?;
Self::from_reader(format, file)
}
#[inline]
pub fn from_reader<R: Read + Seek + Send + 'static>(
format: InputFormat,
reader: R,
) -> Result<Self> {
#[cfg(not(any(feature = "markdown", feature = "html", feature = "docx")))]
{
let _ = reader;
match format {}
}
#[cfg(any(feature = "markdown", feature = "html", feature = "docx"))]
match format {
#[cfg(feature = "html")]
InputFormat::Html => {
let stripped =
crate::factory::bom_stripping_reader::BomStrippingReader::new(reader)?;
Ok(Self::Html(HtmlReader::from_reader(stripped)?))
}
#[cfg(feature = "markdown")]
InputFormat::Markdown => {
let stripped =
crate::factory::bom_stripping_reader::BomStrippingReader::new(reader)?;
Ok(Self::Markdown(MarkdownReader::from_reader(stripped)?))
}
#[cfg(feature = "docx")]
InputFormat::Docx => Ok(Self::Docx(DocxReader::from_reader(reader)?)),
}
}
#[inline]
pub fn from_str(format: InputFormat, input: &str) -> Result<Self> {
#[cfg(not(any(feature = "markdown", feature = "html", feature = "docx")))]
{
let _ = input;
match format {}
}
#[cfg(any(feature = "markdown", feature = "html", feature = "docx"))]
match format {
#[cfg(feature = "html")]
InputFormat::Html => {
let stripped = crate::format::strip_bom(input);
Ok(Self::Html(HtmlReader::from_str(stripped)))
}
#[cfg(feature = "markdown")]
InputFormat::Markdown => {
let stripped = crate::format::strip_bom(input);
Ok(Self::Markdown(MarkdownReader::from_str(stripped)))
}
#[cfg(feature = "docx")]
InputFormat::Docx => {
Self::from_reader(format, Cursor::new(input.as_bytes().to_vec()))
}
}
}
}
impl EventSource for AnyReader {
#[inline]
fn next_event(&mut self) -> Result<Option<Event>> {
#[cfg(not(any(feature = "markdown", feature = "html", feature = "docx")))]
{
match *self {}
}
#[cfg(any(feature = "markdown", feature = "html", feature = "docx"))]
match self {
#[cfg(feature = "html")]
Self::Html(r) => r.next_event(),
#[cfg(feature = "markdown")]
Self::Markdown(r) => r.next_event(),
#[cfg(feature = "docx")]
Self::Docx(r) => r.next_event(),
}
}
}
#[cfg(test)]
mod send_static_assertions {
fn assert_send_static<T: Send + 'static>() {}
#[test]
fn any_reader_is_send_static() {
#[cfg(any(feature = "markdown", feature = "html", feature = "docx"))]
assert_send_static::<crate::AnyReader>();
}
#[cfg(feature = "docx")]
#[test]
fn docx_variant_is_send_static() {
assert_send_static::<crate::AnyReader>();
}
}