use core::fmt;
use std::fmt::Display;
use std::io::{self, Read};
use std::path::Path;
use std::sync::Arc;
use ecow::{eco_format, EcoVec};
use tinymist_std::{ImmutBytes, ImmutPath};
use typst::diag::{PackageError, PackageResult};
use typst::syntax::package::{PackageSpec, VersionlessPackageSpec};
#[cfg(feature = "fs-pack")]
mod fs;
#[cfg(feature = "gitcl-pack")]
mod gitcl;
#[cfg(feature = "http-pack")]
mod http;
mod memory;
mod ops;
#[cfg(feature = "release-pack")]
mod release;
mod tarball;
#[cfg(feature = "universe-pack")]
mod universe;
#[cfg(feature = "fs-pack")]
pub use fs::*;
#[cfg(feature = "gitcl-pack")]
pub use gitcl::*;
#[cfg(feature = "http-pack")]
pub use http::*;
pub use memory::*;
pub use ops::*;
#[cfg(feature = "release-pack")]
pub use release::*;
pub use tarball::*;
#[cfg(feature = "universe-pack")]
pub use universe::*;
pub enum PackFile<'a> {
Data(io::Cursor<ImmutBytes>),
Read(Box<dyn Read + 'a>),
}
impl io::Read for PackFile<'_> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
match self {
PackFile::Data(data) => data.read(buf),
PackFile::Read(reader) => reader.read(buf),
}
}
}
pub enum PackEntries<'a> {
Data(EcoVec<ImmutPath>),
Read(Box<dyn Iterator<Item = Path> + 'a>),
}
pub trait PackFs: fmt::Debug {
fn read_all(
&mut self,
f: &mut (dyn FnMut(&str, PackFile) -> PackageResult<()> + Send + Sync),
) -> PackageResult<()>;
fn read(&self, _path: &str) -> io::Result<PackFile> {
Err(unsupported())
}
fn entries(&self) -> io::Result<PackEntries> {
Err(unsupported())
}
}
pub enum PackSpecifier {
Versioned(PackageSpec),
Versionless(VersionlessPackageSpec),
}
pub trait Pack: PackFs {}
pub trait PackExt: Pack {
fn filter(&mut self, f: impl Fn(&str) -> bool + Send + Sync) -> impl Pack
where
Self: std::marker::Sized,
{
FilterPack { src: self, f }
}
}
pub trait CloneIntoPack: fmt::Debug {
fn clone_into_pack(&mut self, pack: &mut impl PackFs) -> std::io::Result<()>;
}
#[derive(Debug, Clone)]
pub struct Package {
pub pack: Arc<dyn Pack + Send + Sync>,
}
fn unsupported() -> io::Error {
io::Error::new(io::ErrorKind::Unsupported, "unsupported operation")
}
fn malform(e: io::Error) -> PackageError {
PackageError::MalformedArchive(Some(eco_format!("{e:?}")))
}
fn other_io(e: impl Display) -> io::Error {
io::Error::new(io::ErrorKind::Other, e.to_string())
}
fn other(e: impl Display) -> PackageError {
PackageError::Other(Some(eco_format!("{e}")))
}