rustobserver-patternweak-references

How can I create a Weak<dyn T> via Weak::new()?


I am working on a pub/sub model that looks like this:

trait EventObserver { ... }

struct Publisher {
    observer: Mutex<Weak<dyn EventObserver + Send + Sync>>,
}

How do I initialize the Publisher with a Weak set to nothing?

If I write it like this:

impl Publisher {
    pub fn new() -> Publisher {
        Publisher {
            observer: Mutex::new(Weak::new()),
        }
    }
}

The compiler says:

error[E0283]: type annotations needed
  --> src/lib.rs:12:34
   |
12 |             observer: Mutex::new(Weak::new()),
   |                                  ^^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `Weak`
   |
   = note: cannot satisfy `_: Unsize<dyn EventObserver + Send + Sync>`
   = note: required for the cast from `std::sync::Weak<_>` to `std::sync::Weak<(dyn EventObserver + Send + Sync + 'static)>`
help: consider specifying the generic argument
   |
12 |             observer: Mutex::new(Weak::<T>::new()),
   |                                      +++++

And if I specify the type is dyn EventObserver + Send + Sync, the compiler says:

error[E0599]: the function or associated item `new` exists for struct `Weak<dyn EventObserver + Send + Sync>`, but its trait bounds were not satisfied
  --> src/lib.rs:12:75
   |
3  | trait EventObserver {}
   | ------------------- doesn't satisfy `dyn EventObserver + Send + Sync: Sized`
...
12 |             observer: Mutex::new(Weak::<dyn EventObserver + Send + Sync>::new()),
   |                                                                           ^^^ function or associated item cannot be called on `Weak<dyn EventObserver + Send + Sync>` due to unsatisfied trait bounds
   |
   = note: the following trait bounds were not satisfied:
           `dyn EventObserver + Send + Sync: Sized`

I am just looking for a way to initialize the Weak to nothing, so it's expected that any upgrade of the observer will fail to find a valid pointer. After subscribe() is called, then the later upgrade of the Weak can succeed.

I do know two workarounds, one is to use Option to wrap the Weak, another is to create a struct that impl the trait. Is there a clean way just to initialize the Weak<dyn T + Send + Sync> to nothing compared to these workarounds?


Solution

  • Weak::new() doesn't have a ?Sized bound, so this cannot be done naturally. The fix is to create a Weak of a type that implement the trait. If you don't have such type accessible, you can create such type that just panics in all methods (since they'll never be called anyway).

    For example:

    impl Publisher {
        pub fn new() -> Publisher {
            let publisher = Publisher {
                observer: Mutex::new(Weak::<SomeTypeImplementingEventObserver>::new()),
            };
            publisher
        }
    }