use std::borrow::Cow;
use std::error::Error as StdError;
use std::fmt::Display;
use std::num::ParseIntError;
use quick_xml::{events::Event, Reader};
use crate::types::InvalidEndPoint;
#[cfg(feature = "core")]
use crate::{
errors::OssError,
types::object::{InvalidObjectDir, InvalidObjectPath},
};
#[cfg(test)]
mod test;
const PREFIX: &[u8] = b"Prefix";
const COMMON_PREFIX: &[u8] = b"CommonPrefixes";
const NAME: &[u8] = b"Name";
const MAX_KEYS: &[u8] = b"MaxKeys";
const KEY_COUNT: &[u8] = b"KeyCount";
const IS_TRUNCATED: &[u8] = b"IsTruncated";
const NEXT_CONTINUATION_TOKEN: &[u8] = b"NextContinuationToken";
const KEY: &[u8] = b"Key";
const LAST_MODIFIED: &[u8] = b"LastModified";
const E_TAG: &[u8] = b"ETag";
const TYPE: &[u8] = b"Type";
const SIZE: &[u8] = b"Size";
const STORAGE_CLASS: &[u8] = b"StorageClass";
const BUCKET: &[u8] = b"Bucket";
const CREATION_DATE: &[u8] = b"CreationDate";
const EXTRANET_ENDPOINT: &[u8] = b"ExtranetEndpoint";
const INTRANET_ENDPOINT: &[u8] = b"IntranetEndpoint";
const LOCATION: &[u8] = b"Location";
const MARKER: &[u8] = b"Marker";
const NEXT_MARKER: &[u8] = b"NextMarker";
const ID: &[u8] = b"ID";
const DISPLAY_NAME: &[u8] = b"DisplayName";
const CONTENTS: &[u8] = b"Contents";
const TRUE: &str = "true";
pub trait RefineObject<Error: StdError + 'static> {
fn set_key(&mut self, _key: &str) -> Result<(), Error> {
Ok(())
}
fn set_last_modified(&mut self, _last_modified: &str) -> Result<(), Error> {
Ok(())
}
fn set_etag(&mut self, _etag: &str) -> Result<(), Error> {
Ok(())
}
fn set_type(&mut self, _type: &str) -> Result<(), Error> {
Ok(())
}
fn set_size(&mut self, _size: &str) -> Result<(), Error> {
Ok(())
}
fn set_storage_class(&mut self, _storage_class: &str) -> Result<(), Error> {
Ok(())
}
fn decode(&mut self, xml: &str) -> Result<(), InnerItemError> {
let mut reader = Reader::from_str(xml);
let mut buf = Vec::with_capacity(xml.len());
loop {
match reader.read_event_into(&mut buf) {
Ok(Event::Start(e)) => match e.name().as_ref() {
KEY => self.set_key(&reader.read_text(e.to_end().name())?)?,
LAST_MODIFIED => {
self.set_last_modified(&reader.read_text(e.to_end().name())?)?
}
E_TAG => {
let tag = reader.read_text(e.to_end().name())?;
self.set_etag(tag.trim_matches('"'))?;
}
TYPE => self.set_type(&reader.read_text(e.to_end().name())?)?,
SIZE => {
self.set_size(&reader.read_text(e.to_end().name())?)?;
}
STORAGE_CLASS => {
self.set_storage_class(&reader.read_text(e.to_end().name())?)?;
}
_ => (),
},
Ok(Event::Eof) => {
break;
} Err(e) => {
return Err(InnerItemError::from(e));
}
_ => (), }
buf.clear();
}
Ok(())
}
}
pub trait RefineObjectList<T, Error, ItemErr = Error>
where
T: RefineObject<ItemErr>,
Error: ListError,
ItemErr: StdError + 'static,
{
fn set_name(&mut self, _name: &str) -> Result<(), Error> {
Ok(())
}
fn set_prefix(&mut self, _prefix: &str) -> Result<(), Error> {
Ok(())
}
fn set_common_prefix(&mut self, _list: &[Cow<'_, str>]) -> Result<(), Error> {
Ok(())
}
fn set_max_keys(&mut self, _max_keys: &str) -> Result<(), Error> {
Ok(())
}
fn set_key_count(&mut self, _key_count: &str) -> Result<(), Error> {
Ok(())
}
fn set_next_continuation_token_str(&mut self, _token: &str) -> Result<(), Error> {
Ok(())
}
fn set_list(&mut self, _list: Vec<T>) -> Result<(), Error> {
Ok(())
}
fn decode_common_prefix(&mut self, xml: &str) -> Result<(), InnerListError> {
let mut reader = Reader::from_str(xml);
let mut buf = Vec::with_capacity(xml.len());
let mut prefix_vec = Vec::new();
loop {
match reader.read_event_into(&mut buf) {
Ok(Event::Start(e)) => {
if e.name().as_ref() == PREFIX {
prefix_vec.push(reader.read_text(e.to_end().name())?);
}
}
Ok(Event::Eof) => {
break;
} Err(e) => {
return Err(InnerListError::from(e));
}
_ => (), }
buf.clear();
}
self.set_common_prefix(&prefix_vec)?;
Ok(())
}
fn decode<F>(&mut self, xml: &str, mut init_object: F) -> Result<(), InnerListError>
where
F: FnMut() -> T,
{
let mut result = Vec::new();
let mut reader = Reader::from_str(xml);
reader.trim_text(true);
let mut buf = Vec::with_capacity(xml.len());
loop {
match reader.read_event_into(&mut buf) {
Ok(Event::Start(e)) => {
match e.name().as_ref() {
COMMON_PREFIX => {
self.decode_common_prefix(&reader.read_text(e.to_end().name())?)?;
}
PREFIX => {
self.set_prefix(&reader.read_text(e.to_end().name())?)?;
}
NAME => self.set_name(&reader.read_text(e.to_end().name())?)?,
MAX_KEYS => self.set_max_keys(&reader.read_text(e.to_end().name())?)?,
KEY_COUNT => self.set_key_count(&reader.read_text(e.to_end().name())?)?,
IS_TRUNCATED => {
}
NEXT_CONTINUATION_TOKEN => {
self.set_next_continuation_token_str(
&reader.read_text(e.to_end().name())?,
)?;
}
CONTENTS => {
let mut object = init_object();
object.decode(&reader.read_text(e.to_end().name())?)?;
result.push(object);
}
_ => (),
}
}
Ok(Event::Eof) => {
self.set_list(result)?;
break;
} Err(e) => {
return Err(InnerListError::from(e));
}
_ => (), }
buf.clear();
}
Ok(())
}
}
pub trait RefineBucket<Error: StdError + 'static> {
fn set_name(&mut self, _name: &str) -> Result<(), Error> {
Ok(())
}
fn set_creation_date(&mut self, _creation_date: &str) -> Result<(), Error> {
Ok(())
}
fn set_location(&mut self, _location: &str) -> Result<(), Error> {
Ok(())
}
fn set_extranet_endpoint(&mut self, _extranet_endpoint: &str) -> Result<(), Error> {
Ok(())
}
fn set_intranet_endpoint(&mut self, _intranet_endpoint: &str) -> Result<(), Error> {
Ok(())
}
fn set_storage_class(&mut self, _storage_class: &str) -> Result<(), Error> {
Ok(())
}
fn decode(&mut self, xml: &str) -> Result<(), InnerItemError> {
let mut reader = Reader::from_str(xml);
reader.trim_text(true);
let mut buf = Vec::with_capacity(xml.len());
loop {
match reader.read_event_into(&mut buf) {
Ok(Event::Start(e)) => match e.name().as_ref() {
NAME => self.set_name(&reader.read_text(e.to_end().name())?)?,
CREATION_DATE => {
self.set_creation_date(&reader.read_text(e.to_end().name())?)?
}
EXTRANET_ENDPOINT => {
self.set_extranet_endpoint(&reader.read_text(e.to_end().name())?)?
}
INTRANET_ENDPOINT => {
self.set_intranet_endpoint(&reader.read_text(e.to_end().name())?)?
}
LOCATION => self.set_location(&reader.read_text(e.to_end().name())?)?,
STORAGE_CLASS => {
self.set_storage_class(&reader.read_text(e.to_end().name())?)?
}
_ => (),
},
Ok(Event::Eof) => {
break;
} Err(e) => {
return Err(InnerItemError::from(e));
}
_ => (), }
buf.clear();
}
Ok(())
}
}
pub trait RefineBucketList<T: RefineBucket<ItemErr>, Error, ItemErr = Error>
where
Error: ListError,
ItemErr: StdError + 'static,
{
fn set_prefix(&mut self, _prefix: &str) -> Result<(), Error> {
Ok(())
}
fn set_marker(&mut self, _marker: &str) -> Result<(), Error> {
Ok(())
}
fn set_max_keys(&mut self, _max_keys: &str) -> Result<(), Error> {
Ok(())
}
fn set_is_truncated(&mut self, _is_truncated: bool) -> Result<(), Error> {
Ok(())
}
fn set_next_marker(&mut self, _next_marker: &str) -> Result<(), Error> {
Ok(())
}
fn set_id(&mut self, _id: &str) -> Result<(), Error> {
Ok(())
}
fn set_display_name(&mut self, _display_name: &str) -> Result<(), Error> {
Ok(())
}
fn set_list(&mut self, _list: Vec<T>) -> Result<(), Error> {
Ok(())
}
fn decode<F>(&mut self, xml: &str, mut init_bucket: F) -> Result<(), InnerListError>
where
F: FnMut() -> T,
{
let mut result = Vec::new();
let mut reader = Reader::from_str(xml);
reader.trim_text(true);
let mut buf = Vec::with_capacity(xml.len());
loop {
match reader.read_event_into(&mut buf) {
Ok(Event::Start(e)) => match e.name().as_ref() {
PREFIX => self.set_prefix(&reader.read_text(e.to_end().name())?)?,
MARKER => self.set_marker(&reader.read_text(e.to_end().name())?)?,
MAX_KEYS => self.set_max_keys(&reader.read_text(e.to_end().name())?)?,
IS_TRUNCATED => {
self.set_is_truncated(reader.read_text(e.to_end().name())? == TRUE)?;
}
NEXT_MARKER => self.set_next_marker(&reader.read_text(e.to_end().name())?)?,
ID => self.set_id(&reader.read_text(e.to_end().name())?)?,
DISPLAY_NAME => self.set_display_name(&reader.read_text(e.to_end().name())?)?,
BUCKET => {
let mut bucket = init_bucket();
bucket.decode(&reader.read_text(e.to_end().name())?)?;
result.push(bucket);
}
_ => (),
},
Ok(Event::Eof) => {
self.set_list(result)?;
break;
} Err(e) => {
return Err(InnerListError::from(e));
}
_ => (), }
buf.clear();
}
Ok(())
}
}
#[derive(Debug)]
#[doc(hidden)]
#[non_exhaustive]
pub struct InnerItemError(Box<dyn StdError + 'static>);
impl<T: StdError + 'static> From<T> for InnerItemError {
fn from(err: T) -> Self {
Self(Box::new(err))
}
}
impl Display for InnerItemError {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(fmt, "{}", self.0)
}
}
impl InnerItemError {
#[cfg(test)]
pub(crate) fn new() -> Self {
#[derive(Debug)]
struct MyError;
impl Display for MyError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
"demo".fmt(f)
}
}
impl StdError for MyError {}
Self(Box::new(MyError {}))
}
pub fn get_source(&self) -> Option<&(dyn StdError + 'static)> {
Some(self.0.as_ref())
}
}
pub trait ListError: StdError + 'static {}
impl ListError for ParseIntError {}
impl ListError for InvalidEndPoint {}
#[cfg(feature = "core")]
impl ListError for InvalidObjectPath {}
#[cfg(feature = "core")]
impl ListError for InvalidObjectDir {}
#[cfg(feature = "core")]
impl ListError for chrono::ParseError {}
#[cfg(feature = "core")]
impl ListError for OssError {}
impl<T: ListError> From<T> for InnerListError {
fn from(err: T) -> InnerListError {
Self {
kind: ListErrorKind::Custom(Box::new(err)),
}
}
}
#[derive(Debug)]
#[non_exhaustive]
pub struct InnerListError {
kind: ListErrorKind,
}
impl Display for InnerListError {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
use ListErrorKind::*;
match &self.kind {
Item(item) => write!(fmt, "{}", item.0),
Xml(xml) => write!(fmt, "{xml}"),
Custom(out) => write!(fmt, "{out}"),
}
}
}
impl InnerListError {
#[cfg(test)]
#[allow(dead_code)]
pub(crate) fn from_xml() -> Self {
Self {
kind: ListErrorKind::Xml(Box::new(quick_xml::Error::TextNotFound)),
}
}
#[cfg(test)]
#[allow(dead_code)]
pub(crate) fn from_custom() -> Self {
#[derive(Debug)]
struct MyError;
impl Display for MyError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
"custom".fmt(f)
}
}
impl StdError for MyError {}
Self {
kind: ListErrorKind::Custom(Box::new(MyError {})),
}
}
pub fn get_source(&self) -> Option<&(dyn StdError + 'static)> {
use ListErrorKind::*;
match &self.kind {
Item(item) => item.get_source(),
Xml(xml) => Some(xml),
Custom(out) => Some(out.as_ref()),
}
}
}
impl From<InnerItemError> for InnerListError {
fn from(value: InnerItemError) -> Self {
Self {
kind: ListErrorKind::Item(value),
}
}
}
impl From<quick_xml::Error> for InnerListError {
fn from(value: quick_xml::Error) -> Self {
Self {
kind: ListErrorKind::Xml(Box::new(value)),
}
}
}
#[doc(hidden)]
#[derive(Debug)]
#[non_exhaustive]
enum ListErrorKind {
#[non_exhaustive]
Item(InnerItemError),
#[non_exhaustive]
Xml(Box<quick_xml::Error>),
#[non_exhaustive]
Custom(Box<dyn StdError + 'static>),
}