pub mod anonymous;
pub mod prop;
pub mod providers;
use crate::lazy_evaluation::providers::{FlatMap, Flatten, Map, Zip};
use crate::Project;
use crate::__export::{ProjectResult, TaskId};
use crate::project::buildable::Buildable;
pub use prop::*;
use std::collections::HashSet;
use std::fmt::{Debug, Formatter};
pub trait Provider<T: Clone + Send + Sync>: Send + Sync + Buildable {
fn missing_message(&self) -> String {
String::from("Provider has no value set")
}
fn get(&self) -> T {
self.try_get()
.unwrap_or_else(|| panic!("{}", self.missing_message()))
}
fn try_get(&self) -> Option<T>;
fn fallible_get(&self) -> Result<T, ProviderError> {
self.try_get()
.ok_or_else(|| ProviderError::new(self.missing_message()))
}
}
assert_obj_safe!(Provider<()>);
pub trait ProviderExt<T: Clone + Send + Sync>: Provider<T> + Sized {
fn map<R, F>(self, transform: F) -> Map<T, R, F, Self>
where
R: Send + Sync + Clone,
F: Fn(T) -> R + Send + Sync,
Self: 'static,
{
Map::new(self, transform)
}
fn flat_map<R, P, F>(self, transform: F) -> FlatMap<T, R, Self, P, F>
where
R: Send + Sync + Clone,
P: Provider<R>,
F: Fn(T) -> P + Send + Sync,
{
FlatMap::new(self, transform)
}
fn flatten<B>(self) -> Flatten<T, B, Self>
where
Self: Clone + 'static,
T: Provider<B>,
B: Clone + Send + Sync,
{
self.flat_map(|s| s)
}
fn zip<P, B, R, F>(self, other: P, func: F) -> Zip<T, B, R, F>
where
Self: 'static,
P: IntoProvider<B>,
<P as IntoProvider<B>>::Provider: 'static,
B: Send + Sync + Clone,
R: Send + Sync + Clone,
F: Fn(T, B) -> R + Send + Sync,
{
Zip::new(self, other, func)
}
}
impl<P, T> ProviderExt<T> for P
where
T: Clone + Send + Sync,
P: Provider<T> + Send + Sync + 'static,
{
}
pub trait IntoProvider<T: Send + Sync + Clone> {
type Provider: Provider<T>;
fn into_provider(self) -> Self::Provider;
}
impl<P, T> IntoProvider<T> for P
where
T: Clone + Send + Sync,
P: Provider<T> + Send + Sync,
{
type Provider = Self;
fn into_provider(self) -> Self::Provider {
self
}
}
#[derive(Clone)]
struct Wrapper<T: Clone + Send + Sync>(T);
impl<T: Clone + Send + Sync> Buildable for Wrapper<T> {
fn get_dependencies(&self, _: &Project) -> ProjectResult<HashSet<TaskId>> {
Ok(HashSet::new())
}
}
impl<T: Clone + Send + Sync> Debug for Wrapper<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Wrapper").finish_non_exhaustive()
}
}
impl<T: Clone + Send + Sync> Provider<T> for Wrapper<T> {
fn try_get(&self) -> Option<T> {
Some(self.0.clone())
}
}
#[derive(Debug, thiserror::Error)]
#[error("{}", message)]
pub struct ProviderError {
message: String,
}
impl ProviderError {
pub fn new(message: String) -> Self {
Self { message }
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::lazy_evaluation::anonymous::AnonymousProvider;
use crate::provider;
#[test]
fn map() {
let mut provider = Prop::with_value(5);
let mapped = provider.clone().map(|v| v * v);
assert_eq!(mapped.get(), 25);
provider.set(10).unwrap();
assert_eq!(mapped.get(), 100);
}
#[test]
fn flat_map() {
let mut provider = Prop::with_value(5u32);
let flap_map = provider.clone().flat_map(|v| provider!(move || v * v));
assert_eq!(flap_map.get(), 25);
provider.set(10u32).unwrap();
assert_eq!(flap_map.get(), 100);
}
#[test]
fn zip() {
let mut provider_l = Prop::with_value(5);
let mut provider_r = Prop::with_value(6);
let zipped = provider_l.clone().zip(provider_r.clone(), |l, r| l * r);
assert_eq!(zipped.get(), 30);
provider_l.set(10).unwrap();
assert_eq!(zipped.get(), 60);
provider_r.set(15).iter();
assert_eq!(zipped.get(), 150);
}
#[test]
fn flatten() {
let prop1 = provider!(|| provider!(|| 5));
let prop2 = provider!(|| provider!(|| 6));
let value = prop1.flatten().zip(prop2.flatten(), |l, r| l * r);
assert_eq!(value.get(), 30);
let _flattend2 = AnonymousProvider::with_value(|| 0).flat_map(|p| provider!(p));
}
}