Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implementation of RefType is not general enough #1

Closed
peter-kehl opened this issue Aug 29, 2022 · 3 comments
Closed

implementation of RefType is not general enough #1

peter-kehl opened this issue Aug 29, 2022 · 3 comments

Comments

@peter-kehl
Copy link

peter-kehl commented Aug 29, 2022

Salut Adrien,

Thank you for selfie.

This, I believe, is not an issue with selfie, but rather my understanding of Pin, or a difficulty with Rust types/lifetimes. Instead of having a selfie-based type only used for a local variable (and hence inferred), I'd like to use it as a part of a larger struct (or enum with data field(s)). Is that possible, and how?

I understand that the whole struct/enum could not be moved. Would the whole struct/enum have to be used inside Pin, or could it be an ordinary struct (or enum) but not a Copy and with custom clone()?

use selfie::{SelfieMut, refs::Ref, refs::RefType};

type Inner<'a> where Ref<&'a str>: for<'this> RefType<'this> = SelfieMut<'a, [u8; 8], Ref<&'a str>>;

// same error when I add this bound - probably redundant, based on https://github.com/rust-lang/rust/issues/70263 (which is not Pin-specific, however)
// type Inner<'a> where Ref<&'a str>: for<'this> RefType<'this> = SelfieMut<'a, [u8; 8], Ref<&'a str>>;

pub struct Outer<'a> {
    inner: Inner<'a>,
}

which fails with: implementation of RefType is not general enough

@peter-kehl
Copy link
Author

I'm reading https://doc.rust-lang.org/nightly/core/pin/index.html, it will take me a while.

My goal was: Something like https://doc.rust-lang.org/nightly/core/pin/index.html#example-self-referential-struct, but not in a Box (to be no_std & heapless). But I may see a way; if I need more help, I'll ask.

@prokopyl
Copy link
Owner

Hi, and thanks for your interest in Selfie!

Even though you closed the issue I'm still going to answer your initial question, I think this will help, and also I believe it highlights weaknesses in the documentation.

For the part about putting a Selfie in a struct, here is how it would look like (using a Box for simplicity):

pub struct Outer {
    inner: Selfie<'static, Box<[u8; 8]>, Ref<[u8]>>,
}

The generic lifetime of a Selfie (or SelfieMut) is actually the lifetime of the "owned" pointer P. If you actually own what's behind P, then it's just a 'static lifetime.

You can also move that struct (both Outer and the inner selfie field) freely: the Box here is what's guaranteeing that your data isn't moving (or any pinned pointer).

As for a no_std & heapless solution, Selfie is not actually the one that provides the non-movable guarantee of the data, that's the role of the pointer type P. Many pointer types provide this capability (behind the StableDeref trait), but if you're comfortable with your Selfie being non-static, a simple & reference will also work as a stable pointer:

pub struct Outer<'a> {
    inner: Selfie<'a, &'a [u8; 8], Ref<[u8]>>,
}

fn do_thing_with_outer(outer: Outer) { todo!() }

fn main() {
    let not_moving_data = [0; 8];
    let outer = Outer {
        inner: Selfie::new(Pin::new(&not_moving_data), |data| &data[4..])
    };

    // Outer can be moved here, no problem as long as not_moving_data is still alive
    do_thing_with_outer(outer);
}

Hope this helps! 🙂

@peter-kehl
Copy link
Author

Thank you. I realized that I don't need lazy/interior mutability for now. But I'll remember Selfie.

Thank you also for MIRI GitHub actions config. I'm using it with my project to check unsafe.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants