[Solved] Return SharedMutex<ConcreteType> as SharedMutex<Any>


#1

Hi, I’m a bit stuck with this function. I have trait I need to implement that looks something like this:

pub trait MappedSharedMutexGetters {
	fn read_as_any<'mutex>(&self) -> MappedSharedMutexReadGuard<'mutex, Any>;
	fn write_as_any<'mutex>(&self) -> MappedSharedMutexWriteGuard<'mutex, Any>;
}

Just getting the list and returning it doesn’t work, even though the contained type has the Any trait (as does every type right?):

pub struct ListGetters;

// impl CoerceUnsized<ComponentList<Component>> for SharedMutex<ComponentList<Component>> {}

impl components::MappedSharedMutexGetters for ListGetters {
	fn read_as_any<'mutex>(&self) -> MappedSharedMutexReadGuard<'mutex, Any> {
		let list = LIST.read().expect("COMPONENT_LIST corrupted");
		list.into_mapped().map(|v| v)
	}
	fn write_as_any<'mutex>(&self) -> MappedSharedMutexWriteGuard<'mutex, Any> {
		let mut list = LIST.write().expect("COMPONENT_LIST corrupted");
		list.into_mapped().map(|v| v)
	}
}

lazy_static! {
	pub static ref LIST: SharedMutex<ComponentList<Component>> = SharedMutex::new(Vec::new());
}

Gives the error:

<entity_rust macros>:16:1: 16:42 error: mismatched types:
 expected `shared_mutex::MappedSharedMutexWriteGuard<'mutex, core::any::Any + 'static>`,
    found `shared_mutex::MappedSharedMutexWriteGuard<'_, collections::vec::Vec<(usize, test_component::Component)>>`
(expected trait core::any::Any,
    found struct `collections::vec::Vec`) [E0308]
<entity_rust macros>:16 list . into_mapped (  ) . map ( | v | v ) } } lazy_static ! {
                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

So it expected an Any but it got a Vec.

I tried to change it to v as Any but got an error that was something like ‘converting from Sized to unsized’ which someone on IRC told me could be fixed with CoerceUnsized, but that’s an unstable Rust feature so I’d rather not pursue…

What can I do to change this SharedMutex<Vec<…>> into a SharedMutex?


#2

If the author of the type doesn’t provide the conversion, there isn’t any way to do it.

If you’re the author of MappedSharedMutexReadGuard, there’s a couple of ways to implement the conversion. The simplest way is to provide a method like fn to_any(self) -> MappedSharedMutexReadGuard<Any> on the type. If you’re using nightly rustc, you can also implement the CoerceUnsized trait; see https://doc.rust-lang.org/nightly/std/ops/trait.CoerceUnsized.html .

(I’m using “author” here loosely to mean the provider of the crate; obviously, you can fork a crate even if you aren’t the original author.)


#3

Alright, but before I start forking SharedMutex, I thought this would work:

impl components::MappedSharedMutexGetters for ListGetters {
	fn read_as_any<'mutex>(&self) -> MappedSharedMutexReadGuard<'mutex, Any> {
		let list = LIST.read().expect("COMPONENT_LIST corrupted");
		list.into_mapped().map(|v| v as &Any)
	}
	fn write_as_any<'mutex>(&self) -> MappedSharedMutexWriteGuard<'mutex, Any> {
		let mut list = LIST.write().expect("COMPONENT_LIST corrupted");
		list.into_mapped().map(|v| v as &Any)
	}
}

Because the Guard has a function into_mapped that returns a MappedGuard which has a function map that yields a &T to its block and returns a MappedGuard<U>. That sounds a little like what I would need right?

Unfortunately it gives this error.

<entity_rust macros>:13:19: 13:44 error: the trait `core::marker::Sized` is not implemented for the type `core::any::Any` [E0277]
<entity_rust macros>:13 into_mapped (  ) . map ( | v | v as & Any ) } fn write_as_any < 'mutex > (
                                          ^~~~~~~~~~~~~~~~~~~~~~~~~

Could I work around that somehow?


#4

This is https://crates.io/crates/shared-mutex? This is the signature of map():

    pub fn map<U, F>(self, action: F) -> MappedSharedMutexReadGuard<'mutex, U>
            where F: FnOnce(&T) -> &U {
                self.option_map(move |t| Some(action(t))).unwrap()
            }

I think the author intended to support your use-case, but messed up the signature of the function; it needs to be changed to pub fn map<U: ?Sized, F>....


#5

Thanks a lot @eefriedman! I submitted a PR and it was already accepted. That totally solved this issue, which was the last big hurdle in my project so it looks like I’m going to finish it up soon :smiley: