Scripting Design for Shipyard ECS?

Is there any type or crate maybe that provides the ability to use dyn Any for a type that has a lifetime parameter? I have to be able to store a vector of trait objects ( Vec<Box<dyn DynamicBorrow<'a> + 'a>> ), but I need to be able to downcast the borrow to its concrete type which is either DynamicView<'a, T> or DynamicViewMut<'a, T>.

You don’t provide much detail about the types in question here. If you know that your DynamicBorrow is either DynamicView or DynamicViewMut, you could consider an enum over a trait. As long as T is static, you could perhaps work with something like

enum DynamicBorrow<'a> {
  View(DynamicView<'a, dyn Any>),
  ViewMut(DynamicViewMut<'a, dyn Any>),
}

Then perhaps working with Vec<DynamicBorrow<'a>> is enough. You would even save the Box.

Whether the above code makes sense or not of course depends heavily on how DynamicView and DynamicViewMut actually are defined, in particular if T can be unsized. If not, then perhaps a DynamicView<'a, Box<dyn Any>> (and similarly for the second enum variant) could make sense.

1 Like

Yeah, wait a second, I think the enum might work. I was thinking it wouldn't for some reason earlier, but now that I think about that again I think that will be fine. I'll try it and come back if it doesn't work ( and provide some more details :wink: ). Thanks. :slight_smile:

So T in my use-case cannot be unsized and is T: 'static + Send + Sync. In fact the current plan is that it will always be an array of bytes, but possibly with a different length. For example: [u8; 16], [u8; 32], [u8; 64], etc. and it needs to be stack allocated for performance reasons ( thus an array and not a vector. DynamicView is defined as :

pub struct DynamicView<'a, T> {
    pub view: Option<View<'a, T>>,
    pub storage_id: StorageId,
}

Where View is:

pub struct View<'a, T> {
    window: Window<'a, T>,
    _borrow: Borrow<'a>,
    _all_borrow: Borrow<'a>,
}

In your example with the enum:

enum DynamicBorrow<'a> {
  View(DynamicView<'a, dyn Any>),
  ViewMut(DynamicViewMut<'a, dyn Any>),
}

Will I be able to do something like:

match my_dynamic_borrow {
  DynamicBorrow::View(view) => {
    // I will know the length of the length because of dynamically obtained data
    // and the goal is to downcast it something like this
    if length == 16 {
        let view = view as DynamicView<[u8; 16]>;
        // Do stuff with view
    } else if length == 32 {
        let view = view as DynamicView<[u8; 32]>;
        // Do stuff with view
    }
    // etc.
  }
  // And the smae for DynamicBorrowMut
}

Is Window a type of yours, too, or does it come from another crate? I would be interested in the whole hierarchy where the parameter T goes. If T cannot be unsized, like you said, then, like I said above, the enum would probably have to look more like

enum DynamicBorrow<'a> {
  View(DynamicView<'a, Box<dyn Any>>),
  ViewMut(DynamicViewMut<'a, Box<dyn Any>>),
}

Oh, OK. So I'm trying to build a scripting system for the shipyard ECS. Things got a little bit hairy with the the type system in ways that I thought were going to be a bit simpler. I'll try to articulate this a bit better and get the real code public and cover the broader topic a bit better as soon as I get the chance.

I'll include the maintainer, too.

I can’t really think of a nice safe approach here, honestly. Maybe a lack of creativity. Using some unsafe code, one could imagine this approach to be reasonable. I personally am not going to guarantee that this kind of interface is actually sound, but I hope it is.

1 Like

Wow, thanks for the example. I'll definitely take a look at it.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.