use core::marker::PhantomData;
use rt_map::BorrowFail;
use crate::Resources;
pub struct FnResource<Fun, Ret, Args> {
pub func: Fun,
marker: PhantomData<(Fun, Ret, Args)>,
}
#[cfg(feature = "fn_res_once")]
impl<Fun, Ret> FnResource<Fun, Ret, ()>
where
Fun: FnOnce() -> Ret + 'static,
Ret: 'static,
{
pub fn call_once(self, _resources: &Resources) -> Ret {
(self.func)()
}
pub fn try_call_once(self, _resources: &Resources) -> Result<Ret, BorrowFail> {
let ret_value = (self.func)();
Ok(ret_value)
}
}
#[cfg(feature = "fn_res_mut")]
impl<Fun, Ret> FnResource<Fun, Ret, ()>
where
Fun: FnMut() -> Ret + 'static,
Ret: 'static,
{
pub fn call_mut(&mut self, _resources: &Resources) -> Ret {
(self.func)()
}
pub fn try_call_mut(&mut self, _resources: &Resources) -> Result<Ret, BorrowFail> {
let ret_value = (self.func)();
Ok(ret_value)
}
}
impl<Fun, Ret> FnResource<Fun, Ret, ()>
where
Fun: Fn() -> Ret + 'static,
Ret: 'static,
{
pub fn call(&self, _resources: &Resources) -> Ret {
(self.func)()
}
pub fn try_call(&self, _resources: &Resources) -> Result<Ret, BorrowFail> {
let ret_value = (self.func)();
Ok(ret_value)
}
}
#[cfg(feature = "fn_meta")]
impl<Fun, Ret> fn_meta::FnMeta for FnResource<Fun, Ret, ()>
where
Fun: FnOnce() -> Ret + 'static,
Ret: 'static,
{
fn borrows() -> fn_meta::TypeIds {
<fn_meta::FnMetadata<Fun, Ret, ()> as fn_meta::FnMeta>::borrows()
}
fn borrow_muts() -> fn_meta::TypeIds {
<fn_meta::FnMetadata<Fun, Ret, ()> as fn_meta::FnMeta>::borrow_muts()
}
}
#[cfg(feature = "fn_meta")]
impl<Fun, Ret> fn_meta::FnMetaDyn for FnResource<Fun, Ret, ()>
where
Fun: FnOnce() -> Ret + 'static,
Ret: 'static,
{
fn borrows(&self) -> fn_meta::TypeIds {
fn_meta::FnMetaExt::meta(&self.func).borrows()
}
fn borrow_muts(&self) -> fn_meta::TypeIds {
fn_meta::FnMetaExt::meta(&self.func).borrow_muts()
}
}
pub trait IntoFnResource<Fun, Ret, Args> {
fn into_fn_resource(self) -> FnResource<Fun, Ret, Args>;
}
impl<Fun, Ret> IntoFnResource<Fun, Ret, ()> for Fun
where
Fun: FnOnce() -> Ret + 'static,
Ret: 'static,
{
fn into_fn_resource(self) -> FnResource<Fun, Ret, ()> {
FnResource {
func: self,
marker: PhantomData,
}
}
}
impl<Fun, Ret, A> IntoFnResource<Fun, Ret, (A,)> for Fun
where
Fun: FnOnce(A) -> Ret + 'static,
Ret: 'static,
{
fn into_fn_resource(self) -> FnResource<Fun, Ret, (A,)> {
FnResource {
func: self,
marker: PhantomData,
}
}
}
impl<Fun, Ret, A, B> IntoFnResource<Fun, Ret, (A, B)> for Fun
where
Fun: FnOnce(A, B) -> Ret + 'static,
Ret: 'static,
{
fn into_fn_resource(self) -> FnResource<Fun, Ret, (A, B)> {
FnResource {
func: self,
marker: PhantomData,
}
}
}
impl<Fun, Ret, A, B, C> IntoFnResource<Fun, Ret, (A, B, C)> for Fun
where
Fun: FnOnce(A, B, C) -> Ret + 'static,
Ret: 'static,
{
fn into_fn_resource(self) -> FnResource<Fun, Ret, (A, B, C)> {
FnResource {
func: self,
marker: PhantomData,
}
}
}
impl<Fun, Ret, A, B, C, D> IntoFnResource<Fun, Ret, (A, B, C, D)> for Fun
where
Fun: FnOnce(A, B, C, D) -> Ret + 'static,
Ret: 'static,
{
fn into_fn_resource(self) -> FnResource<Fun, Ret, (A, B, C, D)> {
FnResource {
func: self,
marker: PhantomData,
}
}
}
impl<Fun, Ret, A, B, C, D, E> IntoFnResource<Fun, Ret, (A, B, C, D, E)> for Fun
where
Fun: FnOnce(A, B, C, D, E) -> Ret + 'static,
Ret: 'static,
{
fn into_fn_resource(self) -> FnResource<Fun, Ret, (A, B, C, D, E)> {
FnResource {
func: self,
marker: PhantomData,
}
}
}
impl<Fun, Ret, A, B, C, D, E, F> IntoFnResource<Fun, Ret, (A, B, C, D, E, F)> for Fun
where
Fun: FnOnce(A, B, C, D, E, F) -> Ret + 'static,
Ret: 'static,
{
fn into_fn_resource(self) -> FnResource<Fun, Ret, (A, B, C, D, E, F)> {
FnResource {
func: self,
marker: PhantomData,
}
}
}
#[cfg(feature = "high_arg_count")]
impl<Fun, Ret, A, B, C, D, E, F, G> IntoFnResource<Fun, Ret, (A, B, C, D, E, F, G)> for Fun
where
Fun: FnOnce(A, B, C, D, E, F, G) -> Ret + 'static,
Ret: 'static,
{
#[allow(clippy::type_complexity)]
fn into_fn_resource(self) -> FnResource<Fun, Ret, (A, B, C, D, E, F, G)> {
FnResource {
func: self,
marker: PhantomData,
}
}
}
#[cfg(feature = "high_arg_count")]
impl<Fun, Ret, A, B, C, D, E, F, G, H> IntoFnResource<Fun, Ret, (A, B, C, D, E, F, G, H)> for Fun
where
Fun: FnOnce(A, B, C, D, E, F, G, H) -> Ret + 'static,
Ret: 'static,
{
#[allow(clippy::type_complexity)]
fn into_fn_resource(self) -> FnResource<Fun, Ret, (A, B, C, D, E, F, G, H)> {
FnResource {
func: self,
marker: PhantomData,
}
}
}
#[cfg(test)]
mod tests {
use crate::{IntoFnResource, Resources};
#[test]
fn read_1() {
let fn_res = f_r1.into_fn_resource();
let mut resources = Resources::new();
resources.insert(S0(1));
let sum = fn_res.call(&resources);
assert_eq!(1, resources.borrow::<S0>().0);
assert_eq!(1, sum);
}
#[test]
fn read_2() {
let fn_res = f_r2.into_fn_resource();
let mut resources = Resources::new();
resources.insert(S0(0));
resources.insert(S1(1));
let sum = fn_res.call(&resources);
assert_eq!(0, resources.borrow::<S0>().0);
assert_eq!(1, resources.borrow::<S1>().0);
assert_eq!(1, sum);
}
#[test]
fn read_3() {
let fn_res = f_r3.into_fn_resource();
let mut resources = Resources::new();
resources.insert(S0(0));
resources.insert(S1(1));
resources.insert(S2(2));
let sum = fn_res.call(&resources);
assert_eq!(0, resources.borrow::<S0>().0);
assert_eq!(1, resources.borrow::<S1>().0);
assert_eq!(2, resources.borrow::<S2>().0);
assert_eq!(3, sum);
}
#[test]
fn read_4() {
let fn_res = f_r4.into_fn_resource();
let mut resources = Resources::new();
resources.insert(S0(0));
resources.insert(S1(1));
resources.insert(S2(2));
resources.insert(S3(3));
let sum = fn_res.call(&resources);
assert_eq!(0, resources.borrow::<S0>().0);
assert_eq!(1, resources.borrow::<S1>().0);
assert_eq!(2, resources.borrow::<S2>().0);
assert_eq!(3, resources.borrow::<S3>().0);
assert_eq!(6, sum);
}
#[test]
fn read_5() {
let fn_res = f_r5.into_fn_resource();
let mut resources = Resources::new();
resources.insert(S0(0));
resources.insert(S1(1));
resources.insert(S2(2));
resources.insert(S3(3));
resources.insert(S4(4));
let sum = fn_res.call(&resources);
assert_eq!(0, resources.borrow::<S0>().0);
assert_eq!(1, resources.borrow::<S1>().0);
assert_eq!(2, resources.borrow::<S2>().0);
assert_eq!(3, resources.borrow::<S3>().0);
assert_eq!(4, resources.borrow::<S4>().0);
assert_eq!(10, sum);
}
#[test]
fn read_6() {
let fn_res = f_r6.into_fn_resource();
let mut resources = Resources::new();
resources.insert(S0(0));
resources.insert(S1(1));
resources.insert(S2(2));
resources.insert(S3(3));
resources.insert(S4(4));
resources.insert(S5(5));
let sum = fn_res.call(&resources);
assert_eq!(0, resources.borrow::<S0>().0);
assert_eq!(1, resources.borrow::<S1>().0);
assert_eq!(2, resources.borrow::<S2>().0);
assert_eq!(3, resources.borrow::<S3>().0);
assert_eq!(4, resources.borrow::<S4>().0);
assert_eq!(5, resources.borrow::<S5>().0);
assert_eq!(15, sum);
}
#[test]
fn write_1() {
let fn_res = f_w1.into_fn_resource();
let mut resources = Resources::new();
resources.insert(S0(1));
let sum = fn_res.call(&resources);
assert_eq!(2, resources.borrow::<S0>().0);
assert_eq!(2, sum);
}
#[test]
fn write_2() {
let fn_res = f_w2.into_fn_resource();
let mut resources = Resources::new();
resources.insert(S0(0));
resources.insert(S1(1));
let sum = fn_res.call(&resources);
assert_eq!(1, resources.borrow::<S0>().0);
assert_eq!(2, resources.borrow::<S1>().0);
assert_eq!(3, sum);
}
#[test]
fn write_3() {
let fn_res = f_w3.into_fn_resource();
let mut resources = Resources::new();
resources.insert(S0(0));
resources.insert(S1(1));
resources.insert(S2(2));
let sum = fn_res.call(&resources);
assert_eq!(1, resources.borrow::<S0>().0);
assert_eq!(2, resources.borrow::<S1>().0);
assert_eq!(3, resources.borrow::<S2>().0);
assert_eq!(6, sum);
}
#[test]
fn write_4() {
let fn_res = f_w4.into_fn_resource();
let mut resources = Resources::new();
resources.insert(S0(0));
resources.insert(S1(1));
resources.insert(S2(2));
resources.insert(S3(3));
let sum = fn_res.call(&resources);
assert_eq!(1, resources.borrow::<S0>().0);
assert_eq!(2, resources.borrow::<S1>().0);
assert_eq!(3, resources.borrow::<S2>().0);
assert_eq!(4, resources.borrow::<S3>().0);
assert_eq!(10, sum);
}
#[test]
fn write_5() {
let fn_res = f_w5.into_fn_resource();
let mut resources = Resources::new();
resources.insert(S0(0));
resources.insert(S1(1));
resources.insert(S2(2));
resources.insert(S3(3));
resources.insert(S4(4));
let sum = fn_res.call(&resources);
assert_eq!(1, resources.borrow::<S0>().0);
assert_eq!(2, resources.borrow::<S1>().0);
assert_eq!(3, resources.borrow::<S2>().0);
assert_eq!(4, resources.borrow::<S3>().0);
assert_eq!(5, resources.borrow::<S4>().0);
assert_eq!(15, sum);
}
#[test]
fn write_6() {
let fn_res = f_w6.into_fn_resource();
let mut resources = Resources::new();
resources.insert(S0(0));
resources.insert(S1(1));
resources.insert(S2(2));
resources.insert(S3(3));
resources.insert(S4(4));
resources.insert(S5(5));
let sum = fn_res.call(&resources);
assert_eq!(1, resources.borrow::<S0>().0);
assert_eq!(2, resources.borrow::<S1>().0);
assert_eq!(3, resources.borrow::<S2>().0);
assert_eq!(4, resources.borrow::<S3>().0);
assert_eq!(5, resources.borrow::<S4>().0);
assert_eq!(6, resources.borrow::<S5>().0);
assert_eq!(21, sum);
}
#[test]
fn read_1_write_1() {
let fn_res = f_r1_w1.into_fn_resource();
let mut resources = Resources::new();
resources.insert(S0(0));
resources.insert(S1(1));
let sum = fn_res.call(&resources);
assert_eq!(0, resources.borrow::<S0>().0);
assert_eq!(2, resources.borrow::<S1>().0);
assert_eq!(2, sum);
}
#[test]
fn read_1_write_1_closure() {
let fn_res = (|s0: &S0, s1: &mut S1| {
s1.0 += 1;
s0.0 + s1.0
})
.into_fn_resource();
let mut resources = Resources::new();
resources.insert(S0(0));
resources.insert(S1(1));
let sum = fn_res.call(&resources);
assert_eq!(2, resources.borrow::<S1>().0);
assert_eq!(2, sum);
}
#[test]
fn write_1_read_1() {
let fn_res = f_w1_r1.into_fn_resource();
let mut resources = Resources::new();
resources.insert(S0(0));
resources.insert(S1(1));
let sum = fn_res.call(&resources);
assert_eq!(1, resources.borrow::<S0>().0);
assert_eq!(1, resources.borrow::<S1>().0);
assert_eq!(2, sum);
}
#[test]
fn write_1_read_1_closure() {
let fn_res = (|s0: &mut S0, s1: &S1| {
s0.0 += 1;
s0.0 + s1.0
})
.into_fn_resource();
let mut resources = Resources::new();
resources.insert(S0(0));
resources.insert(S1(1));
let sum = fn_res.call(&resources);
assert_eq!(1, resources.borrow::<S0>().0);
assert_eq!(1, resources.borrow::<S1>().0);
assert_eq!(2, sum);
}
#[test]
fn read_1_write_1_read_1() {
let fn_res = f_r1_w1_r1.into_fn_resource();
let mut resources = Resources::new();
resources.insert(S0(0));
resources.insert(S1(1));
resources.insert(S2(2));
let sum = fn_res.call(&resources);
assert_eq!(0, resources.borrow::<S0>().0);
assert_eq!(2, resources.borrow::<S1>().0);
assert_eq!(2, resources.borrow::<S2>().0);
assert_eq!(4, sum);
}
#[test]
fn read_1_write_1_read_1_closure() {
let fn_res = (|s0: &S0, s1: &mut S1, s2: &S2| {
s1.0 += 1;
s0.0 + s1.0 + s2.0
})
.into_fn_resource();
let mut resources = Resources::new();
resources.insert(S0(0));
resources.insert(S1(1));
resources.insert(S2(2));
let sum = fn_res.call(&resources);
assert_eq!(0, resources.borrow::<S0>().0);
assert_eq!(2, resources.borrow::<S1>().0);
assert_eq!(2, resources.borrow::<S2>().0);
assert_eq!(4, sum);
}
#[test]
fn write_1_read_1_write_1() {
let fn_res = f_w1_r1_w1.into_fn_resource();
let mut resources = Resources::new();
resources.insert(S0(0));
resources.insert(S1(1));
resources.insert(S2(2));
let sum = fn_res.call(&resources);
assert_eq!(1, resources.borrow::<S0>().0);
assert_eq!(1, resources.borrow::<S1>().0);
assert_eq!(3, resources.borrow::<S2>().0);
assert_eq!(5, sum);
}
#[cfg(feature = "high_arg_count")]
#[test]
fn write_2_read_2_write_2_read_1() {
let fn_res = f_w2_r2_w2_r1.into_fn_resource();
let mut resources = Resources::new();
resources.insert(S0(0));
resources.insert(S1(1));
resources.insert(S2(2));
resources.insert(S3(3));
resources.insert(S4(4));
resources.insert(S5(5));
resources.insert(S6(6));
let sum = fn_res.call(&resources);
assert_eq!(1, resources.borrow::<S0>().0);
assert_eq!(2, resources.borrow::<S1>().0);
assert_eq!(2, resources.borrow::<S2>().0);
assert_eq!(3, resources.borrow::<S3>().0);
assert_eq!(5, resources.borrow::<S4>().0);
assert_eq!(6, resources.borrow::<S5>().0);
assert_eq!(6, resources.borrow::<S6>().0);
assert_eq!(25, sum);
}
#[cfg(all(feature = "fn_meta", feature = "high_arg_count"))]
#[test]
fn fn_meta_integration() {
use std::any::TypeId;
use fn_meta::FnMetaDyn;
let fn_res = f_w2_r2_w2_r1.into_fn_resource();
let borrows = fn_res.borrows();
let borrow_muts = fn_res.borrow_muts();
assert_eq!(
&[TypeId::of::<S2>(), TypeId::of::<S3>(), TypeId::of::<S6>()],
borrows.as_slice()
);
assert_eq!(
&[
TypeId::of::<S0>(),
TypeId::of::<S1>(),
TypeId::of::<S4>(),
TypeId::of::<S5>()
],
borrow_muts.as_slice()
);
}
fn f_r1(s0: &S0) -> usize {
s0.0
}
fn f_r2(s0: &S0, s1: &S1) -> usize {
s0.0 + s1.0
}
fn f_r3(s0: &S0, s1: &S1, s2: &S2) -> usize {
s0.0 + s1.0 + s2.0
}
fn f_r4(s0: &S0, s1: &S1, s2: &S2, s3: &S3) -> usize {
s0.0 + s1.0 + s2.0 + s3.0
}
fn f_r5(s0: &S0, s1: &S1, s2: &S2, s3: &S3, s4: &S4) -> usize {
s0.0 + s1.0 + s2.0 + s3.0 + s4.0
}
fn f_r6(s0: &S0, s1: &S1, s2: &S2, s3: &S3, s4: &S4, s5: &S5) -> usize {
s0.0 + s1.0 + s2.0 + s3.0 + s4.0 + s5.0
}
fn f_w1(s0: &mut S0) -> usize {
s0.0 += 1;
s0.0
}
fn f_w2(s0: &mut S0, s1: &mut S1) -> usize {
s0.0 += 1;
s1.0 += 1;
s0.0 + s1.0
}
fn f_w3(s0: &mut S0, s1: &mut S1, s2: &mut S2) -> usize {
s0.0 += 1;
s1.0 += 1;
s2.0 += 1;
s0.0 + s1.0 + s2.0
}
fn f_w4(s0: &mut S0, s1: &mut S1, s2: &mut S2, s3: &mut S3) -> usize {
s0.0 += 1;
s1.0 += 1;
s2.0 += 1;
s3.0 += 1;
s0.0 + s1.0 + s2.0 + s3.0
}
fn f_w5(s0: &mut S0, s1: &mut S1, s2: &mut S2, s3: &mut S3, s4: &mut S4) -> usize {
s0.0 += 1;
s1.0 += 1;
s2.0 += 1;
s3.0 += 1;
s4.0 += 1;
s0.0 + s1.0 + s2.0 + s3.0 + s4.0
}
fn f_w6(s0: &mut S0, s1: &mut S1, s2: &mut S2, s3: &mut S3, s4: &mut S4, s5: &mut S5) -> usize {
s0.0 += 1;
s1.0 += 1;
s2.0 += 1;
s3.0 += 1;
s4.0 += 1;
s5.0 += 1;
s0.0 + s1.0 + s2.0 + s3.0 + s4.0 + s5.0
}
fn f_r1_w1(s0: &S0, s1: &mut S1) -> usize {
s1.0 += 1;
s0.0 + s1.0
}
fn f_w1_r1(s0: &mut S0, s1: &S1) -> usize {
s0.0 += 1;
s0.0 + s1.0
}
fn f_r1_w1_r1(s0: &S0, s1: &mut S1, s2: &S2) -> usize {
s1.0 += 1;
s0.0 + s1.0 + s2.0
}
fn f_w1_r1_w1(s0: &mut S0, s1: &S1, s2: &mut S2) -> usize {
s0.0 += 1;
s2.0 += 1;
s0.0 + s1.0 + s2.0
}
#[cfg(feature = "high_arg_count")]
fn f_w2_r2_w2_r1(
s0: &mut S0,
s1: &mut S1,
s2: &S2,
s3: &S3,
s4: &mut S4,
s5: &mut S5,
s6: &S6,
) -> usize {
s0.0 += 1;
s1.0 += 1;
s4.0 += 1;
s5.0 += 1;
s0.0 + s1.0 + s2.0 + s3.0 + s4.0 + s5.0 + s6.0
}
#[derive(Debug)]
struct S0(usize);
#[derive(Debug)]
struct S1(usize);
#[derive(Debug)]
struct S2(usize);
#[derive(Debug)]
struct S3(usize);
#[derive(Debug)]
struct S4(usize);
#[derive(Debug)]
struct S5(usize);
#[cfg(feature = "high_arg_count")]
#[derive(Debug)]
struct S6(usize);
}