How to hold pointers to data that holds a reference?

Given the following code:

struct Data<'arg>
{
    object: &'arg usize
}
struct Holder
{
    data: *const ??
}

impl Holder
{
    pub fn new<'arg>(data: &Data<'arg>) -> Self
    {
        Self
        {
            data
        }
    }

    // (This was missing)
    pub unsafe fn get<'arg>(&self) -> &Data<'arg>
    {
        ???
    }
}

How should it be completed so 'data' holds any Data with any lifetime?

If I use a *const dyn Trait it requires that 'arg outlives 'static. If the reference to the dyn Trait is passed to new, it requires that it's reference outlives 'static.

This compiles but is almost surely not what you actually want.

But I'm not sure what you do want. Are you trying to preserve the outer lifetime of the &Data<'_>? If you're not, you're probably going to have a lot of trouble knowing when the Holder is valid.

What are the dyn Trait capabilities you need? Trait objects have a lot of special behavior so you should provide a more representative example of what you're trying to do.

You've apparently got as far as getting errors about it, so sharing that code and the complete output of cargo check is something else you could do.


Without more context, the only other thing I'll note is that dyn Trait always has a lifetime. You've possibly elided it in some context which means you're working with dyn Trait + 'static. You can always mention the lifetime explicitly to override the behavior of eliding it.

2 Likes

lifetime is part of the type system. if you want to erase the lifetime (i.e. be able to "hold any Data with any lifetime"), using raw pointer won't help you much than a regular reference. you must use proper type erasure techniques.

type erasure requires you to use the meet (if you think the type system as a semi-lattice) of all runtime types as your compile time type. to erase a concrete type, you typically want dynamic dispatch at runtime via vtables (trait objects in rust).

but erasing lifetimes is a little different from erasing normal concrete types. the meet of all lifetimes is the 'static lifetime, so your valid options typically includes Box, Rc, etc. if you think about it, the "lifetime information at runtime" concept is actually reified as ownership.

3 Likes

I'm trying to hold "any lifetime" Data inside holder, and then get it back. I edited my post with the missing 'get' function. I don't really need the Trait, but it seemed to be the only option for casting to a generic pointer (since *const() doesn't work for the 'get' function).

The example signatures you show in the first post allow users to break any kind of lifetime rule. For example get has no way to check that the data pointer is still valid, nor it knows the right 'arg lifetime, which instead is set by the caller, which can choose any lifetime, including those that were invalid for the original data reference.

If you don't have a more specific problem to solve I suggest you to consider this not doable soundly.

2 Likes

Smart pointers are too slow for what I want to do, but I got an answer in stackoverflow that does the lifetime erasure: rust - How to hold pointers to data that holds a reference? - Stack Overflow.

The code ends up like this:

That's correct. 'get' is supposed to be unsafe, and the safety is guaranteed outside. I forgot to put the 'unsafe' keyword in the function.

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.