use super::markers::ResourceKind;
use super::sets::{Empty, Has, ResourceSet};
use super::tracked::{ResourceEffect, Tracked};
use crate::effect::trait_def::Effect;
pub trait ResourceEffectExt: Effect + Sized {
fn acquires<R: ResourceKind>(self) -> Tracked<Self, Has<R>, Empty> {
Tracked::new(self)
}
fn releases<R: ResourceKind>(self) -> Tracked<Self, Empty, Has<R>> {
Tracked::new(self)
}
fn neutral(self) -> Tracked<Self, Empty, Empty> {
Tracked::new(self)
}
}
impl<E: Effect> ResourceEffectExt for E {}
pub fn assert_resource_neutral<Eff>(effect: Eff) -> Eff
where
Eff: ResourceEffect<Acquires = Empty, Releases = Empty>,
{
effect
}
pub trait IsResourceNeutral: ResourceEffect<Acquires = Empty, Releases = Empty> {}
impl<E: ResourceEffect<Acquires = Empty, Releases = Empty>> IsResourceNeutral for E {}
pub trait TrackedExt<Eff, Acq: ResourceSet, Rel: ResourceSet>: Sized {
fn also_acquires<R: ResourceKind>(self) -> Tracked<Eff, Has<R, Acq>, Rel>;
fn also_releases<R: ResourceKind>(self) -> Tracked<Eff, Acq, Has<R, Rel>>;
}
impl<Eff: Effect, Acq: ResourceSet, Rel: ResourceSet> TrackedExt<Eff, Acq, Rel>
for Tracked<Eff, Acq, Rel>
{
fn also_acquires<R: ResourceKind>(self) -> Tracked<Eff, Has<R, Acq>, Rel> {
Tracked::new(self.into_inner())
}
fn also_releases<R: ResourceKind>(self) -> Tracked<Eff, Acq, Has<R, Rel>> {
Tracked::new(self.into_inner())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::effect::constructors::pure;
use crate::effect::resource::markers::{DbRes, FileRes};
#[tokio::test]
async fn acquires_marks_resource() {
let effect = pure::<_, String, ()>(42).acquires::<FileRes>();
let result = effect.run(&()).await;
assert_eq!(result, Ok(42));
}
#[tokio::test]
async fn releases_marks_resource() {
let effect = pure::<_, String, ()>(()).releases::<FileRes>();
let result = effect.run(&()).await;
assert_eq!(result, Ok(()));
}
#[tokio::test]
async fn neutral_marks_no_resources() {
let effect = pure::<_, String, ()>(42).neutral();
let result = effect.run(&()).await;
assert_eq!(result, Ok(42));
}
#[tokio::test]
async fn also_acquires_adds_resource() {
let effect = pure::<_, String, ()>(42)
.acquires::<FileRes>()
.also_acquires::<DbRes>();
let result = effect.run(&()).await;
assert_eq!(result, Ok(42));
}
#[tokio::test]
async fn also_releases_adds_resource() {
let effect = pure::<_, String, ()>(())
.releases::<FileRes>()
.also_releases::<DbRes>();
let result = effect.run(&()).await;
assert_eq!(result, Ok(()));
}
fn _assert_acquires<T: ResourceEffect<Acquires = A>, A: ResourceSet>() {}
fn _assert_releases<T: ResourceEffect<Releases = R>, R: ResourceSet>() {}
fn _assert_neutral<T: IsResourceNeutral>() {}
#[test]
fn acquires_type_check() {
type WithFile = Tracked<crate::effect::combinators::Pure<i32, String, ()>, Has<FileRes>>;
_assert_acquires::<WithFile, Has<FileRes>>();
}
#[test]
fn releases_type_check() {
type WithFile =
Tracked<crate::effect::combinators::Pure<(), String, ()>, Empty, Has<FileRes>>;
_assert_releases::<WithFile, Has<FileRes>>();
}
#[test]
fn neutral_type_check() {
type Neutral = Tracked<crate::effect::combinators::Pure<i32, String, ()>, Empty, Empty>;
_assert_neutral::<Neutral>();
}
#[test]
fn assert_resource_neutral_compiles() {
let effect = pure::<_, String, ()>(42).neutral();
let _ = assert_resource_neutral(effect);
}
#[test]
fn also_acquires_type_check() {
type WithBoth =
Tracked<crate::effect::combinators::Pure<i32, String, ()>, Has<DbRes, Has<FileRes>>>;
_assert_acquires::<WithBoth, Has<DbRes, Has<FileRes>>>();
}
}