remove duplicate code, open from any Read sources

This commit is contained in:
Breval Ferrari 2025-04-30 17:07:44 -04:00
parent 130a75d0ca
commit 53bdd265b3
Signed by: breval
GPG key ID: A2EEBF62257FF960
3 changed files with 94 additions and 164 deletions

View file

@ -1,6 +1,6 @@
[package] [package]
name = "bingus" name = "bingus"
version = "0.4.1" version = "0.5.0"
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true
description.workspace = true description.workspace = true

View file

@ -19,7 +19,7 @@ mod dynamic {
use std::{ use std::{
borrow::Cow, borrow::Cow,
fs::File, fs::File,
io::{self, Read, Write}, io::{self, Cursor, Read, Write},
path::Path, path::Path,
}; };
@ -34,6 +34,8 @@ mod dynamic {
#[cfg(feature = "text")] #[cfg(feature = "text")]
use super::txt::Text; use super::txt::Text;
use super::{Bendable, Bytes, IntoDataBytes, TryFromDataBytes}; use super::{Bendable, Bytes, IntoDataBytes, TryFromDataBytes};
#[cfg(not(feature = "text"))]
use std::marker::PhantomData;
use cfg_if::cfg_if; use cfg_if::cfg_if;
#[cfg(feature = "fonts")] #[cfg(feature = "fonts")]
@ -46,8 +48,6 @@ mod dynamic {
use strum::EnumDiscriminants; use strum::EnumDiscriminants;
use thiserror::Error; use thiserror::Error;
cfg_if! {
if #[cfg(feature = "text")] {
#[derive(EnumDiscriminants)] #[derive(EnumDiscriminants)]
#[strum_discriminants(name(Format))] #[strum_discriminants(name(Format))]
pub enum DynamicBendable<'a> { pub enum DynamicBendable<'a> {
@ -59,23 +59,8 @@ mod dynamic {
Sound(Audio), Sound(Audio),
#[cfg(feature = "text")] #[cfg(feature = "text")]
Text(Text<'a>), Text(Text<'a>),
#[cfg(feature = "documents")] #[cfg(not(feature = "text"))]
Doc(ShivaDocument), Phantom(PhantomData<&'a ()>),
#[cfg(feature = "documents")]
Archive(PdfDocument),
Meta,
#[cfg(feature = "fonts")]
Font(FontKitFont),
}} else {
#[derive(EnumDiscriminants)]
#[strum_discriminants(name(Format))]
pub enum DynamicBendable {
#[cfg(feature = "pictures")]
Image(DynamicImage),
#[cfg(feature = "binary")]
Binary(Bytes),
#[cfg(feature = "music")]
Sound(Audio),
#[cfg(feature = "documents")] #[cfg(feature = "documents")]
Doc(ShivaDocument), Doc(ShivaDocument),
#[cfg(feature = "documents")] #[cfg(feature = "documents")]
@ -84,7 +69,6 @@ mod dynamic {
#[cfg(feature = "fonts")] #[cfg(feature = "fonts")]
Font(FontKitFont), Font(FontKitFont),
} }
}}
#[cfg(feature = "shiva")] #[cfg(feature = "shiva")]
#[derive(Debug, Error)] #[derive(Debug, Error)]
@ -170,132 +154,75 @@ mod dynamic {
} }
} }
cfg_if! { pub type DynamicResult = Result<Option<DynamicBendable<'static>>, OpenError>;
if #[cfg(feature = "text")] {
pub fn open<P: AsRef<Path>>(path: P) -> Result<Option<DynamicBendable<'static>>, OpenError> { fn guess(t: Option<infer::Type>, bytes: Bytes) -> DynamicResult {
use MatcherType::*; use MatcherType::*;
infer::get_from_path(&path)? t.map(|t| (t.matcher_type(), t.extension()))
.map(|t| (t.matcher_type(), t.extension())) .map(
.map( |(matcher, extension)| -> Result<DynamicBendable, OpenError> {
|(matcher, extension)| -> Result<DynamicBendable, OpenError> { Ok(match matcher {
Ok(match matcher { #[cfg(feature = "pictures")]
#[cfg(feature = "pictures")] Image => DynamicBendable::Image(img::load_from_memory(&bytes)?),
Image => DynamicBendable::Image(img::open(path)?), #[cfg(feature = "music")]
#[cfg(feature = "music")] Audio => DynamicBendable::Sound(crate::snd::Audio::open(Cursor::new(bytes), None)?),
Audio => DynamicBendable::Sound(crate::snd::Audio::open(path)?), #[cfg(feature = "documents")]
#[cfg(feature = "documents")] Archive if extension == "pdf" => DynamicBendable::Archive(
Archive if extension == "pdf" => DynamicBendable::Archive( PdfDocument::try_from_data_bytes(
PdfDocument::try_from_data_bytes( bytes,
File::open(path)? (),
.bytes() Default::default(),
.collect::<Result<Bytes, io::Error>>()?, )
(), .map_err(OpenError::Pdf)?,
Default::default(), ),
) #[cfg(feature = "documents")]
.map_err(OpenError::Pdf)?, Archive | Doc => {
), let document_type = DocumentType::from_extension(extension)
#[cfg(feature = "documents")] .ok_or(ShivaUnknownExtensionError)
Archive | Doc => { .map_err(ShivaError::UnknownExtension)?;
let document_type = DocumentType::from_extension(extension) DynamicBendable::Doc(ShivaDocument::new(
.ok_or(ShivaUnknownExtensionError) Document::parse(
.map_err(ShivaError::UnknownExtension)?; &bytes::Bytes::from(bytes),
DynamicBendable::Doc(ShivaDocument::new(
Document::parse(
&bytes::Bytes::from(std::fs::read(path)?),
document_type,
)
.map_err(ShivaError::Anyhow)?,
document_type, document_type,
))
}
#[cfg(feature = "fonts")]
Font => DynamicBendable::Font(FontKitFont::try_from_data_bytes(
File::open(path)?
.bytes()
.collect::<Result<Bytes, io::Error>>()?,
(),
Default::default(),
)?),
#[cfg(feature = "text")]
Text => DynamicBendable::Text(crate::txt::Text::try_from_data_bytes(
File::open(path)?
.bytes()
.collect::<Result<Bytes, io::Error>>()?,
(),
Default::default(),
)?),
#[cfg(feature = "binary")]
_ => DynamicBendable::Binary({
let mut buf = Vec::new();
File::open(path)?.read_to_end(&mut buf)?;
buf
}),
#[cfg(not(feature = "binary"))]
_ => unimplemented!("no format reader available to open this thing (turn on the 'binary' feature to default to binary data)"),
})
},
)
.transpose()
}} else {
pub fn open<P: AsRef<Path>>(path: P) -> Result<Option<DynamicBendable>, OpenError> {
use MatcherType::*;
infer::get_from_path(&path)?
.map(|t| (t.matcher_type(), t.extension()))
.map(
|(matcher, extension)| -> Result<DynamicBendable, OpenError> {
Ok(match matcher {
#[cfg(feature = "pictures")]
Image => DynamicBendable::Image(img::open(path)?),
#[cfg(feature = "music")]
Audio => DynamicBendable::Sound(crate::snd::Audio::open(path)?),
#[cfg(feature = "documents")]
Archive if extension == "pdf" => DynamicBendable::Archive(
PdfDocument::try_from_data_bytes(
File::open(path)?
.bytes()
.collect::<Result<Bytes, io::Error>>()?,
(),
Default::default(),
) )
.map_err(OpenError::Pdf)?, .map_err(ShivaError::Anyhow)?,
), document_type,
#[cfg(feature = "documents")] ))
Archive | Doc => { }
let document_type = DocumentType::from_extension(extension) #[cfg(feature = "fonts")]
.ok_or(ShivaUnknownExtensionError) Font => DynamicBendable::Font(FontKitFont::try_from_data_bytes(
.map_err(ShivaError::UnknownExtension)?; bytes,
DynamicBendable::Doc(ShivaDocument::new( (),
Document::parse( Default::default(),
&bytes::Bytes::from(std::fs::read(path)?), )?),
document_type, #[cfg(feature = "text")]
) Text => DynamicBendable::Text(crate::txt::Text::try_from_data_bytes(
.map_err(ShivaError::Anyhow)?, bytes,
document_type, (),
)) Default::default(),
} )?),
#[cfg(feature = "fonts")] #[cfg(feature = "binary")]
Font => todo!(), _ => DynamicBendable::Binary(bytes),
#[cfg(feature = "text")] #[cfg(not(feature = "binary"))]
Text => DynamicBendable::Text(crate::txt::Text::try_from_data_bytes( _ => unimplemented!("no format reader available to open this thing (turn on the 'binary' feature to default to binary data)"),
File::open(path)? })
.bytes() },
.collect::<Result<Bytes, io::Error>>()?, )
(), .transpose()
Default::default(), }
)?),
#[cfg(feature = "binary")] pub fn open_file(path: impl AsRef<Path>) -> DynamicResult {
_ => DynamicBendable::Binary({ open(&mut File::open(path)?)
let mut buf = Vec::new(); }
File::open(path)?.read_to_end(&mut buf)?;
buf pub fn open(source: &mut impl Read) -> DynamicResult {
}), let contents = {
_ => unimplemented!("no format available to open this thing"), let mut c = Vec::new();
}) source.read_to_end(&mut c)?;
}, c
) };
.transpose() guess(infer::get(&contents), contents)
} }
}}
} }
use std::{borrow::Cow, convert::Infallible}; use std::{borrow::Cow, convert::Infallible};

View file

@ -1,8 +1,4 @@
use std::{ use std::io::{self, Read};
fs::File,
io::{self, Read},
path::Path,
};
use derive_new::new; use derive_new::new;
use symphonia::{ use symphonia::{
@ -11,7 +7,7 @@ use symphonia::{
codecs::{Decoder, CODEC_TYPE_NULL}, codecs::{Decoder, CODEC_TYPE_NULL},
conv::FromSample, conv::FromSample,
formats::FormatReader, formats::FormatReader,
io::MediaSourceStream, io::{MediaSource, MediaSourceStream},
probe::Hint, probe::Hint,
sample::{i24, u24}, sample::{i24, u24},
}, },
@ -51,19 +47,22 @@ impl PartialEq for AudioOpenError {
} }
impl Audio { impl Audio {
pub fn open<P: AsRef<Path>>(path: P) -> Result<Audio, AudioOpenError> { pub fn open(
source: impl MediaSource + 'static,
extension: Option<&str>,
) -> Result<Audio, AudioOpenError> {
let registry = default::get_codecs(); let registry = default::get_codecs();
let probe = default::get_probe(); let probe = default::get_probe();
let mediasource = File::open(path.as_ref())?; let mss = MediaSourceStream::new(Box::new(source), Default::default());
let mss = MediaSourceStream::new(Box::new(mediasource), Default::default());
let reader = probe let reader = probe
.format( .format(
Hint::new().with_extension( &{
path.as_ref() let mut hint = Hint::new();
.extension() if let Some(e) = extension {
.and_then(|os_str| os_str.to_str()) hint.with_extension(e);
.unwrap_or("mp3"), }
), hint
},
mss, mss,
&Default::default(), &Default::default(),
&Default::default(), &Default::default(),
@ -161,6 +160,8 @@ where
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::fs::File;
use project_root::get_project_root; use project_root::get_project_root;
use crate::IntoDataBytes; use crate::IntoDataBytes;
@ -171,12 +172,14 @@ mod tests {
fn open_sample_file() { fn open_sample_file() {
let original = let original =
&include_bytes!("../../../testing material/sound/sample-3s.mp3")[52079 - 51826..]; &include_bytes!("../../../testing material/sound/sample-3s.mp3")[52079 - 51826..];
let path = get_project_root()
.expect("can't find project root!")
.join("testing material")
.join("sound")
.join("sample-3s.mp3");
let result = Audio::open( let result = Audio::open(
get_project_root() File::open(&path).expect("can't find test file!"),
.expect("can't find project root!") path.extension().and_then(|s| s.to_str()),
.join("testing material")
.join("sound")
.join("sample-3s.mp3"),
) )
.map(|audio| audio.into_data_bytes()); .map(|audio| audio.into_data_bytes());
dbg!(original.len()); dbg!(original.len());