Skip to content

Support private impls of zerocopy traits #1855

@joshlf

Description

@joshlf

Many users ask for the ability to derive a zerocopy trait on their public type without allowing its methods to be called by users outside of the defining module - in other words, for the impl itself to be "private".

Rust doesn't support this natively, but we might be able to emulate it.


Some notes from a conversation with @kupiakos and @jswrenn discussion how to accomplish this.

#[derive(FromBytes)]
#[zerocopy(private)]
struct Foo { ... }
pub unsafe trait FromBytes<Scope = ()> {
    
}

// my crate:

struct Private;

#[derive(FromBytes)]
#[zerocopy(FromBytes(scope = Private))]

// can still access in another crate with a private scope, breaking
// this entirely:
fn transmute<Scope, T: FromBytes<Scope>>(x: &[u8]) -> &T {
    ...
}
#[derive(FromBytes)]
#[derive(...)]
struct FooInner {
    x: i32,
    y: i32,
}

#[repr(transparent)]
struct Foo(FooInner);

transmute!(ref_to_foo_inner) -> &Foo

// assert size and align of Foo equals FooInner?

transmute!(ref_to_foo_inner) -> &Bar

&Foo: TransmuteFrom<&FooInner, Assume::SAFETY>

impl Foo {
    fn from_inner(inner: &FooInner) -> &Foo {
        // SAFETY: We're only assuming safety, and we're the authors
        // of this abstraction, and we know that...
       unsafe { TransmuteFrom::<_, Assume::SAFETY>::transmute(inner) }
    }
}
// Input
#[derive(FromBytes)]
#[zerocopy(private)]
pub struct Foo(...);

// Converted into:
#[derive(FromBytes)]
struct FooInner(...);

#[repr(transparent)]
pub struct Foo(FooInner);

impl Foo {
    
}
// Input
#[derive(FromBytes)]
#[zerocopy(private)]
pub struct Foo(...);

// Converted into:
struct Foo(...);

// impls FromBytes on FooTransmute
#[repr(transparent)]
struct FooTransmute(Foo);

impl FooTransmute {
    fn inner_ref(&self) -> &Foo {
        
    }
}

#[repr(transparent)]
pub struct Foo(FooInner);

impl Foo {
    fn from_bytes(x: &[u8]) -> &Foo {
        &FooTransmute::ref_from(x).0
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions