google / google/zerocopy

Support private impls of zerocopy traits

Open
#1,855 2 comments 1 reaction 0 assignees View on GitHub
Dominant language
Rust
Stars
2.6k
Forks
179
Avg merge
1d 19h
Merged PRs (30d)
29

Description

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.

```rust
#[derive(FromBytes)]
#[zerocopy(private)]
struct Foo { ... }
```

- https://jack.wrenn.fyi/blog/private-trait-impls/

```rust=
pub unsafe trait FromBytes {

}

// 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>(x: &[u8]) -> &T {
...
}
```

```rust
#[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) }
}
}

```

```rust
// Input
#[derive(FromBytes)]
#[zerocopy(private)]
pub struct Foo(...);

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

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

impl Foo {

}
```

```rust
// 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
}
}
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.