pub use noema_macros::{collection, item};
use std::fmt::Display;
use std::sync::Arc;
use crate::core::Container;
pub trait Collection {
type Value: Display + Eq + Default;
fn name(&self) -> String;
fn describe(&self) -> String {
format!("Collection with name: {}", self.name())
}
fn default_value(&self) -> Self::Value {
<Self::Value as Default>::default()
}
}
pub trait Item: Send + Sync {
type CollectionType: Collection + Default;
fn value(&self) -> <Self::CollectionType as Collection>::Value;
fn name(&self) -> String;
fn description(&self) -> String {
format!("Item {}: {}", self.name(), self.value())
}
fn to_tuple(&self) -> (String, <Self::CollectionType as Collection>::Value, String) {
(self.name(), self.value(), self.description())
}
}
use std::sync::OnceLock;
pub trait ItemsCollectionLock<C: Collection + Default + ?Sized + Send + Sync> {
fn collection(&self) -> &OnceLock<Arc<Vec<Arc<dyn Item<CollectionType = C> + Send + Sync>>>>;
fn set_collection(
&self,
collection: Arc<Vec<Arc<dyn Item<CollectionType = C> + Send + Sync>>>,
) {
if self.collection().get().is_some() {
panic!(
"Collection {} already set",
<C as Default>::default().name()
);
}
self.collection().set(collection).ok();
}
fn values(&self) -> Arc<Vec<Arc<dyn Item<CollectionType = C> + Send + Sync>>> {
self.collection()
.get()
.expect(format!("Collection {} not set", <C as Default>::default().name()).as_str())
.clone()
}
}
pub trait ItemsCollection<C: Collection + Default + ?Sized + Send + Sync> {
fn all(&self) -> Arc<Vec<Arc<dyn Item<CollectionType = C> + Send + Sync>>>;
fn type_properties(&self) -> C {
<C as Default>::default()
}
fn find(
&self,
predicate: &dyn Fn(&Arc<dyn Item<CollectionType = C> + Send + Sync>) -> bool,
) -> Vec<Arc<dyn Item<CollectionType = C> + Send + Sync>> {
let mut result = Vec::new();
for element in self.all().iter() {
if predicate(element) {
result.push(element.clone());
}
}
result
}
fn by_value(&self, value: C::Value) -> Option<Arc<dyn Item<CollectionType = C> + Send + Sync>> {
self.find(&|e| e.value() == value).into_iter().next()
}
fn by_name(&self, name: &str) -> Option<Arc<dyn Item<CollectionType = C> + Send + Sync>> {
self.find(&|e| e.name() == name).into_iter().next()
}
fn to_tuple(&self) -> Vec<(String, C::Value, String)> {
let mut result = Vec::new();
for e in self.all().iter() {
result.push(e.to_tuple());
}
result
}
}
pub fn collection<C: Send + Sync>() -> impl ItemsCollection<C> + Send + Sync
where
C: Collection + Default + 'static,
Container: ItemsCollection<C> + Send + Sync,
{
return Container;
}
pub struct CollectionBuilder<C: ?Sized> {
items: Vec<Arc<dyn Item<CollectionType = C> + Send + Sync>>,
}
impl<C: ?Sized + Collection + Send + Sync + Default> CollectionBuilder<C> {
pub fn new() -> Self {
Self { items: vec![] }
}
pub fn add<I>(mut self) -> Self
where
I: Item<CollectionType = C> + Send + Sync + 'static + Default,
{
self.items.push(Arc::new(I::default()));
self
}
pub fn build(self)
where
Container: ItemsCollectionLock<C>,
{
Container.set_collection(Arc::new(self.items));
}
}
#[cfg(test)]
mod test {
use crate::items::CollectionBuilder;
#[test]
fn test_items_collections() {
println!("Testing items collections...");
use crate::core::*;
use crate::items::{Collection, Item, ItemsCollection, ItemsCollectionLock};
use noema_macros::{collection, item};
#[collection(i32, name = "Steps")]
struct Steps;
#[item(Steps, value = 12)]
struct StepOne;
#[item(Steps, value = 14)]
struct StepTwo;
#[item(Steps, value = 16)]
struct StepThree;
println!("Setting collection...");
CollectionBuilder::<Steps>::new()
.add::<StepOne>()
.add::<StepTwo>()
.add::<StepThree>()
.build();
#[derive(Injectable)]
struct TestPapu {
t: Arc<dyn ItemsCollection<Steps> + Send + Sync>,
}
let steps = TestPapu::inject(&Container).t;
println!("Hola");
println!("{:?}", steps.type_properties().name());
println!("{:?}", steps.to_tuple());
assert!(steps.type_properties().name() == "Steps".to_string());
}
}