Crate resman[][src]

Expand description

Runtime managed resource borrowing.

This library provides a map that can store one of any type, as well as mutable borrows to each type at the same time.

Note: This implementation is extracted from shred, with the following differences:

  • Debug implementation prints out the type name instead of type ID for the key.
  • Uses downcast-rs instead of mopa for downcasting types.
  • Adds Debug and PartialEq implementations for borrow types when the resource type implements those traits.
  • Returns Err instead of panicking for try_borrow* functions when the resource is already borrowed.

Usage

Add the following to Cargo.toml

resman = "0.11.0"

resman = { version = "0.11.0", features = ["debug"] }
resman = { version = "0.11.0", features = ["fn_res"] }
resman = { version = "0.11.0", features = ["fn_res", "fn_res_mut"] }
resman = { version = "0.11.0", features = ["fn_res", "fn_meta"] }
resman = { version = "0.11.0", features = ["fn_res", "fn_res_mut", "fn_meta"] }

resman = { version = "0.11.0", features = ["fn_res", "fn_res_mut", "fn_res_once"] }

In code:

use resman::Resources;

#[derive(Debug)]
struct A(u32);
#[derive(Debug)]
struct B(u32);

let mut resources = Resources::default();

resources.insert(A(1));
resources.insert(B(2));

// We can validly have two mutable borrows from the `Resources` map!
let mut a = resources.borrow_mut::<A>();
let mut b = resources.borrow_mut::<B>();
a.0 = 2;
b.0 = 3;

// We need to explicitly drop the A and B borrows, because they are runtime
// managed borrows, and rustc doesn't know to drop them before the immutable
// borrows after this.
drop(a);
drop(b);

// Multiple immutable borrows to the same resource are valid.
let a_0 = resources.borrow::<A>();
let _a_1 = resources.borrow::<A>();
let b = resources.borrow::<B>();

println!("A: {}", a_0.0);
println!("B: {}", b.0);

// Trying to mutably borrow a resource that is already borrowed (immutably
// or mutably) returns `Err`.
let a_try_borrow_mut = resources.try_borrow_mut::<A>();
let exists = if a_try_borrow_mut.is_ok() {
    "Ok(..)"
} else {
    "Err"
};
println!("a_try_borrow_mut: {}", exists); // prints "Err"

Features

"debug":

The Debug implementation for Resources will use the Debug implementation for the values when printed. This requires that all Resources to also implement Debug.

Example:

let mut resources = Resources::default();
resources.insert(1u32);
println!("{:?}", resources);

// Without `"debug"` feature:
// {u32: ".."}

// With `"debug"` feature:
// {u32: 1}
"fn_res":

Enables the FnRes trait, allowing dynamic functions invocation under a generic function type.

Usage of this API is as follows:

  1. Define regular functions or closures to run.

    • The functions should take &T or &mut T as parameters.
    • The return type of all functions should be the same.

    Currently there is a limit of 7 parameters.

  2. Call my_function.into_fn_res() to obtain a Box<dyn FnRes>.

  3. Call fn_res.call(&resources) to automatically borrow T from resources and invoke the function.

Example:

use resman::{FnRes, IntoFnRes, Resources};

/// Borrows `u32` mutably, and `u64` immutably.
fn f1(a: &mut u32, b: &u64) -> u64 {
    *a += 1;
    *a as u64 + *b
}

/// Borrows `u32` immutably, and `u64` mutably.
fn f2(a: &u32, b: &mut u64) -> u64 {
    *b += 1;
    *a as u64 + *b
}

let functions = [
    f1.into_fn_res(),
    f2.into_fn_res(),
    (|a: &u32, b: &u64| *a as u64 + *b).into_fn_res(),
];

let mut resources = Resources::default();
resources.insert(0u32);
resources.insert(0u64);

let sum = functions
    .iter()
    .fold(0, |sum, fn_res| sum + fn_res.call(&resources));

assert_eq!(5, sum); // 1 + 2 + 2

let debug_str = format!("{:?}", resources);
assert!(debug_str.contains("u32: 1"));
assert!(debug_str.contains("u64: 1"));

Since Resources has internal mutability, care must be taken to not run multiple functions that borrow the same value mutably from Resources at the same time when using FnRes::call, otherwise it will panic.

Use FnRes::try_call for a non-panicking version, which will return a BorrowFail error if there is an overlapping borrow conflict at runtime.

"fn_res_mut":

Like "fn_res", enables the IntoFnResMut and FnResMut traits.

FnResMut is implemented for functions and closures that impl FnMut, but not Fn.

"fn_res_once":

Requires nightly

Like "fn_res_mut", enables the IntoFnResOnce and FnResOnce traits.

FnResOnce is implemented for functions and closures that impl FnOnce, but not FnMut.

"fn_meta":

Adds FnMeta as an implied trait to FnRes. This means function metadata can be queried for any FnRes.

"high_arg_count":

Raises the number of arguments that FnRes, IntoFnRes, and IntoFnResource are implemented for from 6 to 8.

This is feature gated because compilation time increasing significantly with higher numbers of arguments – as much as from 4 seconds for 6 arguments to 26 seconds for 8 arguments when only "fn_res" is enabled, and up to a minute when "fn_mut" and "fn_once" are enabled.

See Also

  • anymap: Map of any type, without multiple mutable borrows.
  • rt_map: Runtime managed mutable borrowing from a map.
  • shred: Contains Resources type, plus a task dispatcher.

Re-exports

pub use fn_meta;

Structs

Function that gets its arguments / parameters from a Resources map.

Reference to a resource.

Mutable reference to a resource.

Map from TypeId to type.

Enums

Failures to borrow a value.

Traits

Function that gets its arguments / parameters from a Resources map.

Extension to return Box<dyn FnRes> for a function.

Extension to return FnResource for a function.

Trait to represent any type that is Send + Sync + 'static.