zerocopy icon indicating copy to clipboard operation
zerocopy copied to clipboard

Support deriving AsBytes on types with type parameters

Open joshlf opened this issue 3 years ago • 9 comments
trafficstars

Migrated from https://fxbug.dev/100235

In order to accomplish this, we need to be able to emit an impl which is bounded by a const expr, which requires the unstable feature generic_const_exprs. This issue is blocked until that feature is stabilized.

joshlf avatar Sep 19 '22 20:09 joshlf

Would it be possible to have a special case if the type parameter has a bound on ByteOrder and only on ByteOrder by checking all implementations of ByteOrder? ByteOrder is a sealed trait, so all implementations of it are known. This would make it much easier to write code that handles file formats that can be both little and big endian.

bjorn3 avatar Nov 07 '22 13:11 bjorn3

I'm not sure what the relevance of ByteOrder is here? The byteorder-aware types in the byteorder module implement AsBytes, but a type can satisfy the rules of AsBytes even if its type parameters do not implement ByteOrder. What's the connection you're getting at?

joshlf avatar Nov 10 '22 01:11 joshlf

I did like to have types like

#[derive(FromBytes)]
struct Foo<B: ByteOrder> {
    a: U32<B>,
    b: U32<B>,
}

to work with both little endian and big endian using the same type definition. However the restriction of not having any type parameters when deriving FromBytes prevents this. I thought it did be easier to allow FromBytes just for type parameters bound by ByteOrder than implementing the general case.

bjorn3 avatar Nov 10 '22 06:11 bjorn3

That code should work fine. It's just #[derive(AsBytes)] that doesn't currently support generics (actually, on ToT, it supports generics on a struct so long as that struct is also #[repr(transparent)] or #[repr(packed)]).

joshlf avatar Nov 10 '22 06:11 joshlf

(actually, on ToT, it supports generics on a struct so long as that struct is also #[repr(transparent)] or #[repr(packed)]).

I see. Adding #[repr(packed)] would work for my case.

bjorn3 avatar Nov 10 '22 09:11 bjorn3

I wonder if single field #[repr(C)] generic structs can be treated the same way as #[repr(transparent)] for this purpose?

InternetOfTofu avatar Jun 28 '23 19:06 InternetOfTofu

They could, but I'm not sure what the point would be. If you're considering adding #[derive(AsBytes)] to such a type, then:

  • You own the code, and so you can change it
  • You could replace #[repr(C)] with #[repr(transparent)] and not change the behavior
  • You could then use #[derive(AsBytes)] thanks to #[repr(transparent)]

joshlf avatar Aug 01 '23 12:08 joshlf

@joshlf I'm interested in working on this. Would you be interested in seeing an exploration of any of the following?

  • A feature-gated implementation relying on generic_const_exprs.
  • A hacky implementation on stable relying on post-monomorphization errors (rust-lang/rust#99682).
  • An implementation leveraging a type-level representation of the struct padding algorithm (#1316).
  • Any other route I haven't considered.

gio256 avatar Jun 27 '24 20:06 gio256

Thanks for your interest! The type-level representation of size and alignment is what we'd consider. I'll warn you that the design space there is large and there are lots of thorns, and since any traits introduced will be part of our public API, we'll be very nitpicky about the exact design. That said, it would be great to have some experimentation with this at a minimum, and if you're willing to put up with our nitpickiness, then a full implementation would obviously be very welcome!

For inspiration, see: https://github.com/google/zerocopy/issues/1316#issuecomment-2120930160 (although I haven't looked closely at those examples, and I'm not sure whether they address all of our needs).

joshlf avatar Jul 09 '24 17:07 joshlf