use std::{
fmt::Debug,
hash::Hash,
};
use serde::{
Deserialize,
Serialize,
};
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(bound = "M: DataLoadMetaDataItem")]
pub struct DataLoadSchedule<M>
where
M: DataLoadMetaDataItem,
{
pub items: Vec<M>,
}
pub trait DataLoadMetaDataItem:
Debug + Clone + Hash + PartialEq + Eq + Send + Sync + Serialize + for<'de> Deserialize<'de>
{
}
impl<T> DataLoadMetaDataItem for T where
T: Debug + Clone + Hash + PartialEq + Eq + Send + Sync + Serialize + for<'de> Deserialize<'de>
{
}
impl<M> Debug for DataLoadSchedule<M>
where
M: DataLoadMetaDataItem,
{
fn fmt(
&self,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
if f.alternate() {
f.write_str("DataLoadSchedule {\n")?;
for (idx, item) in self.items.iter().enumerate() {
f.write_str(&format!("{idx}: {item:?},\n"))?;
}
f.write_str("}")
} else {
f.debug_struct("DataLoadSchedule")
.field("items", &self.items)
.finish()
}
}
}
impl<M> DataLoadSchedule<M>
where
M: DataLoadMetaDataItem,
{
pub fn new() -> Self {
From::from(Vec::new())
}
pub fn len(&self) -> usize {
self.items.len()
}
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
pub fn filter<P>(
&self,
predicate: P,
) -> Self
where
P: FnMut(&M) -> bool,
{
let mut predicate = predicate;
let items: Vec<M> = self
.items
.iter()
.filter(move |item| predicate(*item))
.cloned()
.collect();
items.into()
}
pub fn filter_map<P, R>(
&self,
predicate: P,
) -> DataLoadSchedule<R>
where
P: FnMut(&M) -> Option<R>,
R: DataLoadMetaDataItem,
{
let predicate = predicate;
let items: Vec<R> = self.items.iter().filter_map(predicate).collect();
items.into()
}
}
impl<M> From<Vec<M>> for DataLoadSchedule<M>
where
M: DataLoadMetaDataItem,
{
fn from(items: Vec<M>) -> Self {
Self { items }
}
}
impl<M> Default for DataLoadSchedule<M>
where
M: DataLoadMetaDataItem,
{
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_index_schedule() {
let vec = vec![1, 2, 3];
let mut schedule = DataLoadSchedule::from(vec.clone());
{
let alt: DataLoadSchedule<i32> = vec.clone().into();
assert_eq!(alt, schedule);
}
schedule.items.push(1);
assert_eq!(schedule.len(), 4);
assert_eq!(schedule.items.get(3), Some(&1));
assert_eq!(
format!("{schedule:?}"),
"DataLoadSchedule { items: [1, 2, 3, 1] }"
);
assert_eq!(
format!("{schedule:#?}"),
"\
DataLoadSchedule {
0: 1,
1: 2,
2: 3,
3: 1,
}"
);
{
let json = serde_json::to_string(&schedule).unwrap();
assert_eq!(json, "{\"items\":[1,2,3,1]}");
let obj = serde_json::from_str::<DataLoadSchedule<i32>>(&json).unwrap();
assert_eq!(obj, schedule);
}
}
#[derive(Debug, Clone, Hash, Serialize, Deserialize, PartialEq, Eq)]
pub struct ExampleItem {
path: String,
}
#[test]
fn test_struct_schedule() {
let item = ExampleItem {
path: String::from("/example/path"),
};
let mut schedule = DataLoadSchedule::new();
schedule.items.push(item.clone());
assert_eq!(schedule.len(), 1);
assert_eq!(schedule.items.first(), Some(&item));
assert!(!schedule.is_empty());
assert_eq!(
format!("{schedule:#?}"),
"\
DataLoadSchedule {
0: ExampleItem { path: \"/example/path\" },
}"
);
{
let json = serde_json::to_string(&schedule).unwrap();
assert_eq!(json, "{\"items\":[{\"path\":\"/example/path\"}]}");
let obj = serde_json::from_str::<DataLoadSchedule<ExampleItem>>(&json).unwrap();
assert_eq!(obj, schedule);
}
}
#[test]
fn test_filter_schedule() {
let vec = vec![1, 2, 3, 4];
let schedule = DataLoadSchedule::from(vec.clone());
let schedule = schedule.filter(|item| *item % 2 == 0);
assert_eq!(schedule.len(), 2);
assert_eq!(schedule.items, vec![2, 4]);
}
#[test]
fn test_filter_map_schedule() {
let vec = vec![1, 2, 3, 4];
let schedule = DataLoadSchedule::from(vec.clone());
let schedule = schedule.filter_map(|item| {
if *item % 2 == 0 {
Some(format!("i:{item}"))
} else {
None
}
});
assert_eq!(schedule.len(), 2);
assert_eq!(schedule.items, vec!["i:2", "i:4"]);
}
}