use std::borrow::Cow;
use std::fmt::Debug;
use std::io::{Read, Write};
use std::path::Path;
use serde::{Deserialize, Serialize};
use crate::ocfl::error::Result;
use crate::ocfl::inventory::Inventory;
use crate::ocfl::store::layout::LayoutExtensionName;
use crate::ocfl::validate::{IncrementalValidator, ObjectValidationResult};
use crate::ocfl::{
ContentPath, Knowable, LogicalPath, ObjectInfo, RepoInfo, SpecVersion, VersionRef,
};
pub mod fs;
pub mod layout;
#[cfg(feature = "s3")]
pub mod s3;
pub trait OcflStore {
fn repo_spec_version(&self) -> Result<Option<Knowable<SpecVersion, String>>>;
fn get_inventory(&self, object_id: &str) -> Result<Inventory>;
fn iter_inventories<'a>(
&'a self,
filter_glob: Option<&str>,
) -> Result<Box<dyn Iterator<Item = Result<Inventory>> + 'a>>;
fn get_object_file(
&self,
object_id: &str,
path: &LogicalPath,
version_num: VersionRef,
sink: &mut dyn Write,
) -> Result<()>;
fn write_new_object(
&self,
inventory: &mut Inventory,
src_object_path: &Path,
object_root: Option<&str>,
) -> Result<()>;
fn write_new_version(&self, inventory: &mut Inventory, version_path: &Path) -> Result<()>;
fn purge_object(&self, object_id: &str) -> Result<()>;
fn list_object_extensions(&self, object_id: &str) -> Result<Vec<String>>;
fn validate_object(
&self,
object_id: &str,
fixity_check: bool,
) -> Result<ObjectValidationResult>;
fn validate_object_at(
&self,
object_root: &str,
fixity_check: bool,
) -> Result<ObjectValidationResult>;
fn validate_repo<'a>(
&'a self,
fixity_check: bool,
) -> Result<Box<dyn IncrementalValidator + 'a>>;
fn describe_repo(&self) -> Result<RepoInfo>;
fn describe_object(&self, object_id: &str) -> Result<ObjectInfo>;
fn upgrade_repo(&self, version: SpecVersion) -> Result<()>;
fn close(&self);
}
pub trait StagingStore: OcflStore {
fn stage_object(&self, inventory: &mut Inventory) -> Result<()>;
fn stage_file_copy(
&self,
inventory: &Inventory,
source: &mut impl Read,
logical_path: &LogicalPath,
) -> Result<()>;
fn copy_staged_file(
&self,
inventory: &Inventory,
src_content: &ContentPath,
dst_logical: &LogicalPath,
) -> Result<()>;
fn stage_file_move(
&self,
inventory: &Inventory,
source: &impl AsRef<Path>,
logical_path: &LogicalPath,
) -> Result<()>;
fn move_staged_file(
&self,
inventory: &Inventory,
src_content: &ContentPath,
dst_logical: &LogicalPath,
) -> Result<()>;
fn rm_staged_files(&self, inventory: &Inventory, paths: &[&ContentPath]) -> Result<()>;
fn rm_orphaned_files(&self, inventory: &Inventory) -> Result<()>;
fn stage_inventory(
&self,
inventory: &Inventory,
finalize: bool,
pretty_print: bool,
) -> Result<()>;
}
#[derive(Deserialize, Serialize, Debug)]
pub struct OcflLayout {
extension: LayoutExtensionName,
description: String,
}
#[derive(Deserialize, Serialize, Debug)]
pub(crate) struct OcflLayoutLenient {
extension: String,
description: String,
}
pub trait Storage {
fn read<W: Write>(&self, path: &str, sink: &mut W) -> Result<()>;
fn list(&self, path: &str, recursive: bool) -> Result<Vec<Listing>>;
fn path_separator(&self) -> char;
}
#[derive(Debug, Hash, Eq, PartialEq)]
pub enum Listing<'a> {
File(Cow<'a, str>),
Directory(Cow<'a, str>),
Other(Cow<'a, str>),
}
impl<'a> Listing<'a> {
pub fn file(path: &str) -> Listing {
Listing::File(Cow::Borrowed(path))
}
pub fn dir(path: &str) -> Listing {
Listing::Directory(Cow::Borrowed(path))
}
pub fn file_owned(path: String) -> Listing<'a> {
Listing::File(Cow::Owned(path))
}
pub fn dir_owned(path: String) -> Listing<'a> {
Listing::Directory(Cow::Owned(path))
}
pub fn path(&self) -> &str {
match self {
Listing::File(path) => path,
Listing::Directory(path) => path,
Listing::Other(path) => path,
}
}
}