Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No examples for interior mutability except for the constant #36

Open
NeveHanter opened this issue Oct 1, 2021 · 2 comments
Open

No examples for interior mutability except for the constant #36

NeveHanter opened this issue Oct 1, 2021 · 2 comments
Labels
enhancement New feature or request

Comments

@NeveHanter
Copy link

Hey, I started playing around with this DI container but I'm unable to achieve interior mutability. Could you provide some examples how that could be achieved with both Svc modes (Rc/Arc) and:

  • Cell,
  • RefCell,
  • Mutex,
  • RwLock,
  • or any other wrapper of any kind?

I've only found the example for constant with the Mutex in one of the docstrings:

builder.provide(constant(Mutex::new(0i32)));

I would like to be able to provide particular component wrapped for example by Mutex and then be able to retrieve this Mutex from the container.

I've created small example with comments what I would like to be able to achieve:

use runtime_injector::*;
use std::cell::{Cell, RefCell};
use std::error::Error;
use std::sync::{Mutex, RwLock};

pub trait Foo: Service {
    fn increase(&mut self);
}

#[derive(Default)]
struct FooImpl(u64);

impl Foo for FooImpl {
    fn increase(&mut self) {
        self.0 += 1;
    }
}

pub trait Bar: Service {
    fn increase(&mut self);
}

struct BarImpl {
    foo: Svc<dyn Foo>,
}

impl BarImpl {
    // Not possible to get Cell/RefCell/Mutex/RwLock
    pub fn new(foo: Svc<dyn Foo>) -> Self {
        Self { foo }
    }
}

impl Bar for BarImpl {
    fn increase(&mut self) {
        self.foo.increase();
    }
}

interface!(
    dyn Foo = [FooImpl],
    dyn Bar = [BarImpl]
);

fn main() -> Result<(), Box<dyn Error>> {
    let mut builder = Injector::builder();

    // No obvious way to allow interior mutability, like auto creation of Cell/RefCell/Mutex/RwLock
    builder.provide(FooImpl::default.singleton().with_interface::<dyn Foo>());
    builder.provide(BarImpl::new.singleton().with_interface::<dyn Bar>());

    // It could be available for example in such way:
    builder.provide(FooImpl::default.wrap_in_mutex().singleton().with_interface::<dyn Foo>());
    // or:
    builder.provide(FooImpl::default.wrap_using(|result| Mutex::new(result)).singleton().with_interface::<dyn Foo>());

    let injector = builder.build();

    // Not able to call these as they require &mut
    injector.get::<Svc<dyn Foo>>()?.increase();
    injector.get::<Svc<dyn Bar>>()?.increase();

    // No Cell/RefCell/Mutex/RwLock availability
    injector.get::<Cell<Svc<dyn Bar>>>()?.increase();
    injector.get::<RefCell<Svc<dyn Bar>>>()?.increase();
    injector.get::<Mutex<Svc<dyn Bar>>>()?.increase();
    injector.get::<RwLock<Svc<dyn Bar>>>()?.increase();

    Ok(())
}
@TehPers TehPers added the enhancement New feature or request label Apr 11, 2022
@TehPers
Copy link
Owner

TehPers commented Apr 11, 2022

Mutex<Svc<dyn Foo>> (or other similar interior mutability types) is probably not what you want. In this case, you'd be guaranteeing mutually exclusive access to the shared pointer to the data, not to the data itself. This wouldn't give you access to call &mut self methods in dyn Foo. Instead, you probably want a Svc<Mutex<dyn Foo>> to be returned by the injector (for example).

I think this should be doable with new providers like you mentioned. An .in_mutex/.in_rc/etc. suite of extensions might be nice to have. Personally I think implementations of the interface should have interior mutability instead (meaning Foo::increase would instead take &self and FooImpl would hold an AtomicU64, for example), but I'm sure there are use cases where having a mutex/refcell/etc provided for you would be nice.

@TehPers
Copy link
Owner

TehPers commented Apr 28, 2022

On second thought, even just a .map function for service factories could be useful and would cover even more situations:

builder.provide(FooImpl::default.map(Mutex::new).singleton());

I'm not sure how this could handle interfaces though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants