I would like to replicate this type in C:
struct IFoo *FooTable[256];
Right now, I have something like this:
struct MyThing<'a> {
foo_table: [Option<Rc<&'a dyn FooTrait>>; 256],
}
However, I'm getting just a ton of errors when attempting to manipulate this field. Too many to list here, which indicates that after years of working with Rust, I still don't understand how to make an entity that can have several pointers to it.
What am I doing wrong? To me the above type makes perfect sense:
- Optional<>, because it's potentially NULLable.
- Rc<>, because it's reference counted.
- &'a dyn FooTrait because it's a Trait Object (yes, by intention).
I don't understand what else I could possibly need here? Any elucidation would be very helpful, thanks!
EDIT: I forgot to mention that I've also been searching the web for help on this and trying my best to RTFM, but to no avail. Despite there being a ton of sites that cover things like Rc vs Arc, etc, I'm still not able to find a site that clearly illustrates the simple use-case of having a structure with n pointers to it from different places/scopes.
A struct containing a reference is only useful in very limited ways, and I assume this is the cause of most/some of the errors you're seeing.
What you may be missing is that Rc
is already a pointer, so you don't need another reference inside the Rc
. I suggest trying:
struct MyThing {
foo_table: [Option<Rc<dyn FooTrait>>; 256],
}
This more directly maps to your C struct.
You may run into additional problems because the Option is the outermost wrapper, but one step at a time.
3 Likes
I don't think you ever want Rc<&T>
as a field.
If you can make a data structure work with Rc<&T>
, it's almost certain you could make it work with &T
. Shared references (&T
) implement Copy
and have no-op destructors; the Rc<_>
doesn't add anything useful. You could have many independent Rc<&T>
's pointing to the same place.
@jumpnbrownweasel's suggestion is probably what you want. The only thing I'll add is that it's possible you'll get borrow checker errors if your FooTrait
implementors are not 'static
, in which case you could attempt one of these:
struct MyThing<'a> {
foo_table: [Option<Rc<dyn FooTrait + 'a>>; 256],
}
// N.b. `&'a dyn FooTrait` is shorthand for `&'a (dyn FooTrait + 'a)`
struct MyThing<'a> {
foo_table: [Option<&'a dyn FooTrait>; 256],
}
If none of these suggestions work, you may be dealing with general borrow checker errors (that we don't have enough context to comment on).
2 Likes
There isn't a day that goes by when Rust doesn't somehow teach me something new. (Or, at least, something that feels new to me.)
I don't normally need to deal with these kinds of types because the default collections are just too convenient. Alas, in this context, I'm writing code that is intended to resemble no_std/alloc-less code, so I'm trying to dig a little deeper than what I normally do. Eventually, I'm hoping I can more easily port this code to an STM32 microcontroller.
I also completely forgot about RefCell as well, which is something else I'll be needing. 
Thanks for the replies; I'll try to apply your collective wisdom as soon as my lunch break is over.
It looks like the final type that ended up working for my needs is:
Option<Rc<RefCell<dyn FooTrait>>>
That is a real mouthful; and, simply accessing the field involves more match statements than I'd prefer; but, it finally works, and I'm able to move on with my project.
Many thanks to everyone who helped!
1 Like