[][src]Trait warmy::context::Inspect

pub trait Inspect<'a, Ctx, Inspected, Method = ()> {
    fn inspect(ctx: &'a mut Ctx) -> Inspected;
}

The inspect context trait.

This trait is very similar to the BorrowMut trait but is specific to the need of this crate and how resources inspect contexts. In order to get why such a trait is needed, you must be introduced to the semantics borrowing problem.

The semantics borrowing problem

So imagine we have a Foo type. We would like to implement Load for Foo and use a u32 as mutable context as counter to increment every time a Foo gets loaded. However, imagine that this is a library type. It would be a pity to stick to a Storage<u32>, because then we couldn’t load our Foo with a more complex context type (for instance, provided by a binary’s code). The typical trick to fix that problem is to use a polymorphic Storage<C> and instead use something like C: BorrowMut<u32> as context type. That enables us to use any type of context and still access the variable we need for counting foos. Neat.

However, consider another type, Bar, that also needs a u32 to be incremented every time a Bar resource gets loaded. It’s obvious that you cannot use the same u32. So there are a few possibilities here:

  • Use type wrappers to encode FooCounter and BarCounter but this is just additional type safety and is orthogonal to our design.
  • Use two distinct u32 and wrap them in a (u32, u32), at least.

The second option is the right way to go, but we now have a problem. As you can see, BorrowMut<u32> for (u32, u32) is ambiguous (which u32 pick?) and doesn’t allow you to pick one and the other.

Even though the borrowed types are the same, the two possible implementations have different semantics (one targets a counter for Foo, the other a counter for Bar). The Inspect trait encodes this situation as a tuple of types:

  • The borrower type — which is the same as Self in the BorrowMut trait.
  • The inspected type – which is the same one as in the BorrowMut trait if you inspect as a mutable reference to something.
  • The inspector type – which doesn’t exist in the BorrowMut trait.
  • The method type – i.e. doesn’t exist in BorrowMut and only serves to have different kind of inspection regarding the method you use.

The inspector type gives the missing semantics to the borrow to decide how the data should be inspected. The example above can then be rewritten correctly with the following:

use warmy::Inspect;

struct Foo;
struct Bar;

struct Context {
  foos: u32,
  bars: u32
}

impl<'a> Inspect<'a, Context, &'a mut u32> for Foo {
  fn inspect(ctx: &mut Context) -> &mut u32 {
    &mut ctx.foos
  }
}

impl<'a> Inspect<'a, Context, &'a mut u32> for Bar {
  fn inspect(ctx: &mut Context) -> &mut u32 {
    &mut ctx.bars
  }
}

And here you have it: borrowing two different objects with the same type from the same object, something impossible with the standard BorrowMut trait.

Universal implementors

Some implementations are provided by default so that you don’t have to write them.

First, if you target no context (i.e. ()), the implementation is already there for you.

Then, two borrowing flavours are provided by default for you:

  • Immutable full-context: you want to immutably borrow the whole context.
  • Mutable full-context: you want to mutably borrow the whole context.

Those two might be useful in end libraries or binaries.

A note on the lifetime

Because of being generic over the borrow lifetime, you can return any kind of borrow (not only references). This is a huge advancement over the current BorrowMut trait as it’s still possible to encode mutable references with &'a mut _ but you can also returns any kind of type, even with a lifetime outliving the borrow. This enables returning () or other exotic kind of data (for instance, you might want to copy / clone something and not use any reference).

Required methods

fn inspect(ctx: &'a mut Ctx) -> Inspected

Inspect the context.

Loading content...

Implementors

impl<'a, T, C, M> Inspect<'a, C, &'a C, M> for T[src]

Immutable full-context universal implementator.

impl<'a, T, C, M> Inspect<'a, C, &'a mut C, M> for T[src]

Mutable full-context universal implementator.

impl<'a, T, C, M> Inspect<'a, C, (), M> for T[src]

No-context universal implementor.

Loading content...