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,25 +154,22 @@ 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::open(path)?), Image => DynamicBendable::Image(img::load_from_memory(&bytes)?),
#[cfg(feature = "music")] #[cfg(feature = "music")]
Audio => DynamicBendable::Sound(crate::snd::Audio::open(path)?), Audio => DynamicBendable::Sound(crate::snd::Audio::open(Cursor::new(bytes), None)?),
#[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(
File::open(path)? bytes,
.bytes()
.collect::<Result<Bytes, io::Error>>()?,
(), (),
Default::default(), Default::default(),
) )
@ -201,7 +182,7 @@ mod dynamic {
.map_err(ShivaError::UnknownExtension)?; .map_err(ShivaError::UnknownExtension)?;
DynamicBendable::Doc(ShivaDocument::new( DynamicBendable::Doc(ShivaDocument::new(
Document::parse( Document::parse(
&bytes::Bytes::from(std::fs::read(path)?), &bytes::Bytes::from(bytes),
document_type, document_type,
) )
.map_err(ShivaError::Anyhow)?, .map_err(ShivaError::Anyhow)?,
@ -210,92 +191,38 @@ mod dynamic {
} }
#[cfg(feature = "fonts")] #[cfg(feature = "fonts")]
Font => DynamicBendable::Font(FontKitFont::try_from_data_bytes( Font => DynamicBendable::Font(FontKitFont::try_from_data_bytes(
File::open(path)? bytes,
.bytes()
.collect::<Result<Bytes, io::Error>>()?,
(), (),
Default::default(), Default::default(),
)?), )?),
#[cfg(feature = "text")] #[cfg(feature = "text")]
Text => DynamicBendable::Text(crate::txt::Text::try_from_data_bytes( Text => DynamicBendable::Text(crate::txt::Text::try_from_data_bytes(
File::open(path)? bytes,
.bytes()
.collect::<Result<Bytes, io::Error>>()?,
(), (),
Default::default(), Default::default(),
)?), )?),
#[cfg(feature = "binary")] #[cfg(feature = "binary")]
_ => DynamicBendable::Binary({ _ => DynamicBendable::Binary(bytes),
let mut buf = Vec::new();
File::open(path)?.read_to_end(&mut buf)?;
buf
}),
#[cfg(not(feature = "binary"))] #[cfg(not(feature = "binary"))]
_ => unimplemented!("no format reader available to open this thing (turn on the 'binary' feature to default to binary data)"), _ => unimplemented!("no format reader available to open this thing (turn on the 'binary' feature to default to binary data)"),
}) })
}, },
) )
.transpose() .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)?,
),
#[cfg(feature = "documents")]
Archive | Doc => {
let document_type = DocumentType::from_extension(extension)
.ok_or(ShivaUnknownExtensionError)
.map_err(ShivaError::UnknownExtension)?;
DynamicBendable::Doc(ShivaDocument::new(
Document::parse(
&bytes::Bytes::from(std::fs::read(path)?),
document_type,
)
.map_err(ShivaError::Anyhow)?,
document_type,
))
} }
#[cfg(feature = "fonts")]
Font => todo!(), pub fn open_file(path: impl AsRef<Path>) -> DynamicResult {
#[cfg(feature = "text")] open(&mut File::open(path)?)
Text => DynamicBendable::Text(crate::txt::Text::try_from_data_bytes( }
File::open(path)?
.bytes() pub fn open(source: &mut impl Read) -> DynamicResult {
.collect::<Result<Bytes, io::Error>>()?, let contents = {
(), let mut c = Vec::new();
Default::default(), source.read_to_end(&mut c)?;
)?), c
#[cfg(feature = "binary")] };
_ => DynamicBendable::Binary({ guess(infer::get(&contents), contents)
let mut buf = Vec::new();
File::open(path)?.read_to_end(&mut buf)?;
buf
}),
_ => unimplemented!("no format available to open this thing"),
})
},
)
.transpose()
} }
}}
} }
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 result = Audio::open( let path = get_project_root()
get_project_root()
.expect("can't find project root!") .expect("can't find project root!")
.join("testing material") .join("testing material")
.join("sound") .join("sound")
.join("sample-3s.mp3"), .join("sample-3s.mp3");
let result = Audio::open(
File::open(&path).expect("can't find test file!"),
path.extension().and_then(|s| s.to_str()),
) )
.map(|audio| audio.into_data_bytes()); .map(|audio| audio.into_data_bytes());
dbg!(original.len()); dbg!(original.len());