├── .gitignore ├── crates └── macros │ ├── tests │ ├── fail │ │ ├── fixed-layout │ │ │ ├── non-sized-fixed-layout.rs │ │ │ ├── not-repr-c.rs │ │ │ ├── enum.rs │ │ │ ├── union.rs │ │ │ ├── field-not-fixed-layout.rs │ │ │ ├── lifetitme.rs │ │ │ ├── enum.stderr │ │ │ ├── union.stderr │ │ │ ├── lifetitme.stderr │ │ │ ├── not-repr-c.stderr │ │ │ ├── field-not-fixed-layout.stderr │ │ │ └── non-sized-fixed-layout.stderr │ │ ├── no-uninit │ │ │ ├── padding.rs │ │ │ └── padding.stderr │ │ ├── from-bytes │ │ │ ├── not_fixed_layout.rs │ │ │ └── not_fixed_layout.stderr │ │ └── byte-complete │ │ │ ├── field-not-fixed-layout.rs │ │ │ └── field-not-fixed-layout.stderr │ ├── diagnostics.rs │ └── pass │ │ ├── fixed-layout │ │ ├── no_fields.rs │ │ ├── tuple_struct.rs │ │ └── named_fields.rs │ │ ├── no-uninit │ │ └── struct.rs │ │ ├── from_bytes │ │ └── struct.rs │ │ └── as-bytes │ │ └── struct.rs │ ├── Cargo.toml │ └── src │ ├── as_bytes.rs │ ├── from_bytes.rs │ ├── lib.rs │ ├── utils.rs │ ├── no_uninit.rs │ ├── byte_complete.rs │ ├── zeroable.rs │ └── fixed_layout.rs ├── Cargo.toml ├── .github └── workflows │ └── build.yml ├── src ├── lib.rs ├── zeroable.rs ├── from_bytes.rs ├── as_bytes.rs ├── fixed_layout.rs ├── no_uninit.rs └── byte_complete.rs └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /crates/macros/tests/fail/fixed-layout/non-sized-fixed-layout.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | fn ensure() {} 3 | ensure::<&str>(); 4 | } 5 | -------------------------------------------------------------------------------- /crates/macros/tests/fail/fixed-layout/not-repr-c.rs: -------------------------------------------------------------------------------- 1 | use mem_markers::FixedLayout; 2 | 3 | #[derive(FixedLayout)] 4 | struct Foo { 5 | a: u8, 6 | } 7 | 8 | fn main() {} 9 | -------------------------------------------------------------------------------- /crates/macros/tests/fail/fixed-layout/enum.rs: -------------------------------------------------------------------------------- 1 | use mem_markers::FixedLayout; 2 | 3 | #[derive(FixedLayout)] 4 | #[repr(C)] 5 | enum Foo { 6 | A, 7 | } 8 | 9 | fn main() {} 10 | -------------------------------------------------------------------------------- /crates/macros/tests/fail/no-uninit/padding.rs: -------------------------------------------------------------------------------- 1 | use mem_markers::NoUninit; 2 | 3 | #[derive(NoUninit)] 4 | struct Foo { 5 | a: u8, 6 | b: u16, 7 | } 8 | 9 | fn main() {} 10 | -------------------------------------------------------------------------------- /crates/macros/tests/diagnostics.rs: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn ui() { 3 | let t = trybuild::TestCases::new(); 4 | t.compile_fail("tests/fail/**/*.rs"); 5 | t.pass("tests/pass/**/*.rs"); 6 | } 7 | -------------------------------------------------------------------------------- /crates/macros/tests/fail/fixed-layout/union.rs: -------------------------------------------------------------------------------- 1 | use mem_markers::FixedLayout; 2 | 3 | #[derive(FixedLayout)] 4 | #[repr(C)] 5 | union Foo { 6 | a: u8, 7 | b: u8, 8 | } 9 | 10 | fn main() {} 11 | -------------------------------------------------------------------------------- /crates/macros/tests/fail/from-bytes/not_fixed_layout.rs: -------------------------------------------------------------------------------- 1 | use mem_markers::*; 2 | 3 | #[derive(FromBytes, ByteComplete, Zeroable)] 4 | #[repr(C)] 5 | struct Foo { 6 | a: u8, 7 | } 8 | 9 | fn main() {} 10 | -------------------------------------------------------------------------------- /crates/macros/tests/fail/fixed-layout/field-not-fixed-layout.rs: -------------------------------------------------------------------------------- 1 | use mem_markers::FixedLayout; 2 | 3 | #[derive(FixedLayout)] 4 | #[repr(C)] 5 | struct Foo { 6 | a: Other, 7 | } 8 | 9 | struct Other {} 10 | fn main() {} 11 | -------------------------------------------------------------------------------- /crates/macros/tests/pass/fixed-layout/no_fields.rs: -------------------------------------------------------------------------------- 1 | use mem_markers::FixedLayout; 2 | 3 | #[derive(FixedLayout)] 4 | struct Foo {} 5 | 6 | fn main() { 7 | fn ensure() {} 8 | ensure::(); 9 | } 10 | -------------------------------------------------------------------------------- /crates/macros/tests/fail/byte-complete/field-not-fixed-layout.rs: -------------------------------------------------------------------------------- 1 | use mem_markers::{ByteComplete, Zeroable}; 2 | 3 | #[derive(Zeroable, ByteComplete)] 4 | struct Foo { 5 | a: Other, 6 | } 7 | 8 | struct Other {} 9 | fn main() {} 10 | -------------------------------------------------------------------------------- /crates/macros/tests/fail/fixed-layout/lifetitme.rs: -------------------------------------------------------------------------------- 1 | use mem_markers::FixedLayout; 2 | 3 | #[derive(FixedLayout)] 4 | #[repr(C)] 5 | struct Foo<'a> { 6 | a: &'a Other, 7 | } 8 | struct Other { 9 | b: u8, 10 | } 11 | 12 | fn main() {} 13 | -------------------------------------------------------------------------------- /crates/macros/tests/pass/fixed-layout/tuple_struct.rs: -------------------------------------------------------------------------------- 1 | use mem_markers::FixedLayout; 2 | 3 | #[derive(FixedLayout)] 4 | #[repr(C)] 5 | struct Foo(u8); 6 | 7 | fn main() { 8 | fn ensure() {} 9 | ensure::(); 10 | } 11 | -------------------------------------------------------------------------------- /crates/macros/tests/pass/no-uninit/struct.rs: -------------------------------------------------------------------------------- 1 | use mem_markers::NoUninit; 2 | 3 | #[derive(NoUninit)] 4 | #[repr(C)] 5 | struct Foo { 6 | a: u8, 7 | } 8 | 9 | fn main() { 10 | fn ensure() {} 11 | ensure::(); 12 | } 13 | -------------------------------------------------------------------------------- /crates/macros/tests/pass/fixed-layout/named_fields.rs: -------------------------------------------------------------------------------- 1 | use mem_markers::FixedLayout; 2 | 3 | #[derive(FixedLayout)] 4 | #[repr(C)] 5 | struct Foo { 6 | a: u8, 7 | } 8 | 9 | fn main() { 10 | fn ensure() {} 11 | ensure::(); 12 | } 13 | -------------------------------------------------------------------------------- /crates/macros/tests/pass/from_bytes/struct.rs: -------------------------------------------------------------------------------- 1 | use mem_markers::*; 2 | 3 | #[derive(FromBytes, FixedLayout, ByteComplete, Zeroable)] 4 | #[repr(C)] 5 | struct Foo { 6 | a: u8, 7 | } 8 | 9 | fn main() { 10 | fn ensure() {} 11 | ensure::(); 12 | } 13 | -------------------------------------------------------------------------------- /crates/macros/tests/pass/as-bytes/struct.rs: -------------------------------------------------------------------------------- 1 | use mem_markers::{AsBytes, FixedLayout, NoUninit}; 2 | 3 | #[derive(AsBytes, FixedLayout, NoUninit)] 4 | #[repr(C)] 5 | struct Foo { 6 | a: u8, 7 | b: u8, 8 | } 9 | 10 | fn main() { 11 | fn ensure() {} 12 | ensure::(); 13 | } 14 | -------------------------------------------------------------------------------- /crates/macros/tests/fail/fixed-layout/enum.stderr: -------------------------------------------------------------------------------- 1 | error: FixedLayout on enums is not currently supported 2 | --> $DIR/enum.rs:3:10 3 | | 4 | 3 | #[derive(FixedLayout)] 5 | | ^^^^^^^^^^^ 6 | | 7 | = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) 8 | -------------------------------------------------------------------------------- /crates/macros/tests/fail/fixed-layout/union.stderr: -------------------------------------------------------------------------------- 1 | error: FixedLayout on unions is not currently supported 2 | --> $DIR/union.rs:3:10 3 | | 4 | 3 | #[derive(FixedLayout)] 5 | | ^^^^^^^^^^^ 6 | | 7 | = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) 8 | -------------------------------------------------------------------------------- /crates/macros/tests/fail/no-uninit/padding.stderr: -------------------------------------------------------------------------------- 1 | error[E0080]: evaluation of constant value failed 2 | --> $DIR/padding.rs:3:10 3 | | 4 | 3 | #[derive(NoUninit)] 5 | | ^^^^^^^^ attempt to divide by zero 6 | | 7 | = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) 8 | -------------------------------------------------------------------------------- /crates/macros/tests/fail/fixed-layout/lifetitme.stderr: -------------------------------------------------------------------------------- 1 | error: FixedLayout on types with generics is not currently supported 2 | --> $DIR/lifetitme.rs:3:10 3 | | 4 | 3 | #[derive(FixedLayout)] 5 | | ^^^^^^^^^^^ 6 | | 7 | = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) 8 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mem-markers" 3 | version = "0.1.0" 4 | authors = ["ryanlevick"] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | mem-markers-macros = { path = "crates/macros" } 11 | 12 | [workspace] 13 | members = ["crates/*"] 14 | -------------------------------------------------------------------------------- /crates/macros/tests/fail/fixed-layout/not-repr-c.stderr: -------------------------------------------------------------------------------- 1 | error: FixedLayout trait requires #[repr(C)] or #[repr(transparent)] on structs with fields 2 | --> $DIR/not-repr-c.rs:3:10 3 | | 4 | 3 | #[derive(FixedLayout)] 5 | | ^^^^^^^^^^^ 6 | | 7 | = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) 8 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build and Test 2 | 3 | on: [pull_request] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | 11 | - name: check 12 | run: cargo check --all 13 | 14 | - name: tests 15 | run: cargo test --all 16 | 17 | - name: fmt 18 | run: cargo fmt --all -- --check 19 | -------------------------------------------------------------------------------- /crates/macros/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mem-markers-macros" 3 | version = "0.1.0" 4 | authors = ["Ryan Levick "] 5 | edition = "2018" 6 | 7 | [lib] 8 | proc_macro = true 9 | 10 | [[test]] 11 | name = "tests" 12 | path = "tests/diagnostics.rs" 13 | 14 | [dependencies] 15 | quote = "1.0" 16 | syn = "1.0" 17 | proc-macro2 = "1.0" 18 | 19 | [dev-dependencies] 20 | trybuild = "1.0" 21 | mem-markers = { path = "../.." } 22 | -------------------------------------------------------------------------------- /crates/macros/tests/fail/from-bytes/not_fixed_layout.stderr: -------------------------------------------------------------------------------- 1 | error[E0277]: the trait bound `Foo: mem_markers::fixed_layout::FixedLayout` is not satisfied 2 | --> $DIR/not_fixed_layout.rs:3:10 3 | | 4 | 3 | #[derive(FromBytes, ByteComplete, Zeroable)] 5 | | ^^^^^^^^^ the trait `mem_markers::fixed_layout::FixedLayout` is not implemented for `Foo` 6 | | 7 | = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) 8 | -------------------------------------------------------------------------------- /crates/macros/tests/fail/fixed-layout/field-not-fixed-layout.stderr: -------------------------------------------------------------------------------- 1 | error[E0277]: the trait bound `Other: mem_markers::fixed_layout::FixedLayout` is not satisfied 2 | --> $DIR/field-not-fixed-layout.rs:6:8 3 | | 4 | 3 | #[derive(FixedLayout)] 5 | | ----------- required by this bound in `FooImplsFixedLayout` 6 | 4 | #[repr(C)] 7 | 5 | struct Foo { 8 | | --- 9 | 6 | a: Other, 10 | | ^^^^^ the trait `mem_markers::fixed_layout::FixedLayout` is not implemented for `Other` 11 | -------------------------------------------------------------------------------- /crates/macros/src/as_bytes.rs: -------------------------------------------------------------------------------- 1 | use quote::quote; 2 | use syn::DeriveInput; 3 | 4 | pub fn expand(input: DeriveInput) -> syn::Result { 5 | let type_name = &input.ident; 6 | if !input.generics.params.is_empty() { 7 | return Err(syn::Error::new( 8 | proc_macro2::Span::call_site(), 9 | "FromBytes on types with generics is not currently supported", 10 | )); 11 | } 12 | 13 | let stream = quote! { 14 | unsafe impl ::mem_markers::AsBytes for #type_name {} 15 | }; 16 | Ok(stream) 17 | } 18 | -------------------------------------------------------------------------------- /crates/macros/src/from_bytes.rs: -------------------------------------------------------------------------------- 1 | use quote::quote; 2 | use syn::DeriveInput; 3 | 4 | pub fn expand(input: DeriveInput) -> syn::Result { 5 | let type_name = &input.ident; 6 | if !input.generics.params.is_empty() { 7 | return Err(syn::Error::new( 8 | proc_macro2::Span::call_site(), 9 | "FromBytes on types with generics is not currently supported", 10 | )); 11 | } 12 | 13 | let stream = quote! { 14 | unsafe impl ::mem_markers::FromBytes for #type_name {} 15 | }; 16 | Ok(stream) 17 | } 18 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Marker traits for establishing certain invariants of how a type is represented in memory 2 | 3 | #![no_std] 4 | #![deny(missing_docs)] 5 | 6 | mod as_bytes; 7 | mod byte_complete; 8 | mod fixed_layout; 9 | mod from_bytes; 10 | mod no_uninit; 11 | mod zeroable; 12 | 13 | #[doc(inline)] 14 | pub use as_bytes::AsBytes; 15 | #[doc(inline)] 16 | pub use byte_complete::ByteComplete; 17 | #[doc(inline)] 18 | pub use fixed_layout::FixedLayout; 19 | #[doc(inline)] 20 | pub use from_bytes::FromBytes; 21 | #[doc(inline)] 22 | pub use no_uninit::NoUninit; 23 | #[doc(inline)] 24 | pub use zeroable::Zeroable; 25 | 26 | pub use mem_markers_macros::*; 27 | -------------------------------------------------------------------------------- /crates/macros/tests/fail/fixed-layout/non-sized-fixed-layout.stderr: -------------------------------------------------------------------------------- 1 | error[E0277]: the size for values of type `str` cannot be known at compilation time 2 | --> $DIR/non-sized-fixed-layout.rs:3:5 3 | | 4 | 2 | fn ensure() {} 5 | | ------ ------------------------ required by this bound in `main::ensure` 6 | 3 | ensure::<&str>(); 7 | | ^^^^^^^^^^^^^^ doesn't have a size known at compile-time 8 | | 9 | = help: the trait `std::marker::Sized` is not implemented for `str` 10 | = note: to learn more, visit 11 | = note: required because of the requirements on the impl of `mem_markers::fixed_layout::FixedLayout` for `&str` 12 | -------------------------------------------------------------------------------- /crates/macros/tests/fail/byte-complete/field-not-fixed-layout.stderr: -------------------------------------------------------------------------------- 1 | error[E0277]: the trait bound `Other: mem_markers::zeroable::Zeroable` is not satisfied 2 | --> $DIR/field-not-fixed-layout.rs:5:8 3 | | 4 | 3 | #[derive(Zeroable, ByteComplete)] 5 | | -------- required by this bound in `FooImplsZeroable` 6 | 4 | struct Foo { 7 | | --- 8 | 5 | a: Other, 9 | | ^^^^^ the trait `mem_markers::zeroable::Zeroable` is not implemented for `Other` 10 | 11 | error[E0277]: the trait bound `Other: mem_markers::byte_complete::ByteComplete` is not satisfied 12 | --> $DIR/field-not-fixed-layout.rs:5:8 13 | | 14 | 3 | #[derive(Zeroable, ByteComplete)] 15 | | ------------ required by this bound in `FooImplsByteComplete` 16 | 4 | struct Foo { 17 | | --- 18 | 5 | a: Other, 19 | | ^^^^^ the trait `mem_markers::byte_complete::ByteComplete` is not implemented for `Other` 20 | -------------------------------------------------------------------------------- /crates/macros/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate proc_macro; 2 | 3 | use proc_macro::TokenStream; 4 | use syn::{parse_macro_input, DeriveInput}; 5 | 6 | mod as_bytes; 7 | mod byte_complete; 8 | mod fixed_layout; 9 | mod from_bytes; 10 | mod no_uninit; 11 | mod utils; 12 | mod zeroable; 13 | 14 | macro_rules! define_derive { 15 | ($item:meta => $fun:ident => $expand:path) => { 16 | #[proc_macro_derive($item)] 17 | pub fn $fun(item: TokenStream) -> TokenStream { 18 | let input = parse_macro_input!(item as DeriveInput); 19 | $expand(input) 20 | .unwrap_or_else(|err| err.to_compile_error()) 21 | .into() 22 | } 23 | }; 24 | } 25 | 26 | define_derive!(FixedLayout => fixed_layout => fixed_layout::expand); 27 | define_derive!(ByteComplete => byte_complete => byte_complete::expand); 28 | define_derive!(FromBytes => from_bytes => from_bytes::expand); 29 | define_derive!(NoUninit => no_uninit => no_uninit::expand); 30 | define_derive!(AsBytes => as_bytes => as_bytes::expand); 31 | define_derive!(Zeroable => zeroable => zeroable::expand); 32 | -------------------------------------------------------------------------------- /crates/macros/src/utils.rs: -------------------------------------------------------------------------------- 1 | use proc_macro2::{Ident, TokenStream}; 2 | use quote::quote; 3 | 4 | /// Get the types of all fields of a struct 5 | pub(crate) fn struct_field_types(s: &syn::DataStruct) -> Vec<&syn::Type> { 6 | match &s.fields { 7 | syn::Fields::Named(n) => n.named.iter().map(|f| &f.ty).collect(), 8 | syn::Fields::Unnamed(n) => n.unnamed.iter().map(|f| &f.ty).collect(), 9 | syn::Fields::Unit => vec![], 10 | } 11 | } 12 | 13 | pub(crate) fn ensure_field_types( 14 | field_types: Vec<&syn::Type>, 15 | type_name: &Ident, 16 | trait_name: &Ident, 17 | extra: Option, 18 | ) -> TokenStream { 19 | let ensure_method_name = quote::format_ident!("r#{}Impls{}", type_name, trait_name); 20 | let extra = extra.unwrap_or(quote! {}); 21 | quote! { 22 | #[allow(missing_docs)] 23 | #[allow(non_snake_case)] 24 | fn #ensure_method_name() { 25 | #( 26 | #ensure_method_name::<#field_types>(); 27 | )* 28 | #extra 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Mem Markers 2 | 3 | A crate for traits that describe certain memory layout invariants of a given type along with derive macros for deriving these traits for custom types. 4 | 5 | ## Traits 6 | 7 | This crate currently contains the following traits: 8 | * `FixedLayout`: types that have a well-defined layout that can be relied on 9 | * `NoUninit`: types that do not have any unintialized bytes 10 | * `ByteComplete`: types where any appropriately sized and aligned array of bytes is a valid representation of that type 11 | * `Zeroable`: types where all zeros are a valid representation of the type in memory 12 | * `FromBytes`: types where any appropriately sized and aligned array of bytes can be viewed as the type. 13 | * `AsBytes`: The type can reliably be turned into a slice of bytes 14 | 15 | ## Examples 16 | 17 | ### Safe Transmute 18 | 19 | ```rust 20 | fn safe_transmute(from: From) -> To { 21 | let from = &std::mem::ManuallyDrop::new(from); 22 | assert!(std::mem::size_of::() == std::mem::size_of::(), "Cannot transmute to smaller type"); 23 | assert!(std::mem::align_of::() % std::mem::align_of::() == 0, "Not aligned"); 24 | 25 | unsafe { std::mem::transmute_copy(from) } 26 | } 27 | ``` -------------------------------------------------------------------------------- /crates/macros/src/no_uninit.rs: -------------------------------------------------------------------------------- 1 | use quote::quote; 2 | use syn::DeriveInput; 3 | 4 | pub fn expand(input: DeriveInput) -> syn::Result { 5 | let type_name = &input.ident; 6 | if !input.generics.params.is_empty() { 7 | return Err(syn::Error::new( 8 | proc_macro2::Span::call_site(), 9 | "NoUninit on types with generics is not currently supported", 10 | )); 11 | } 12 | let ensure = match &input.data { 13 | syn::Data::Struct(s) => ensure_struct_has_no_uninit(type_name, s)?, 14 | syn::Data::Enum(_e) => todo!(), 15 | syn::Data::Union(_u) => todo!(), 16 | }; 17 | 18 | let stream = quote! { 19 | #ensure 20 | unsafe impl ::mem_markers::NoUninit for #type_name {} 21 | }; 22 | Ok(stream) 23 | } 24 | 25 | fn ensure_struct_has_no_uninit( 26 | type_name: &syn::Ident, 27 | s: &syn::DataStruct, 28 | ) -> syn::Result { 29 | let field_types = crate::utils::struct_field_types(s); 30 | if field_types.is_empty() { 31 | return Ok(quote! {}); 32 | } 33 | let ensure_no_padding = quote! { 34 | const HAS_PADDING: bool = core::mem::size_of::<#type_name>() != #(core::mem::size_of::<#field_types>())+*; 35 | let _: [(); 1/(1 - HAS_PADDING as usize)]; 36 | }; 37 | 38 | let stream = crate::utils::ensure_field_types( 39 | field_types, 40 | type_name, 41 | "e::format_ident!("NoUninit"), 42 | Some(ensure_no_padding), 43 | ); 44 | Ok(stream) 45 | } 46 | -------------------------------------------------------------------------------- /crates/macros/src/byte_complete.rs: -------------------------------------------------------------------------------- 1 | use quote::quote; 2 | use syn::DeriveInput; 3 | 4 | pub fn expand(input: DeriveInput) -> syn::Result { 5 | let type_name = &input.ident; 6 | if !input.generics.params.is_empty() { 7 | return Err(syn::Error::new( 8 | proc_macro2::Span::call_site(), 9 | "ByteComplete on types with generics is not currently supported", 10 | )); 11 | } 12 | let ensure = match &input.data { 13 | syn::Data::Struct(s) => ensure_struct_is_byte_complete(type_name, s)?, 14 | syn::Data::Enum(e) => ensure_enum_is_byte_complete(type_name, e)?, 15 | syn::Data::Union(u) => ensure_union_is_byte_complete(type_name, u)?, 16 | }; 17 | 18 | let stream = quote! { 19 | #ensure 20 | unsafe impl ::mem_markers::ByteComplete for #type_name {} 21 | }; 22 | Ok(stream) 23 | } 24 | 25 | fn ensure_struct_is_byte_complete( 26 | type_name: &syn::Ident, 27 | s: &syn::DataStruct, 28 | ) -> syn::Result { 29 | let field_types = crate::utils::struct_field_types(s); 30 | if field_types.is_empty() { 31 | return Ok(quote! {}); 32 | } 33 | let stream = crate::utils::ensure_field_types( 34 | field_types, 35 | type_name, 36 | "e::format_ident!("ByteComplete"), 37 | None, 38 | ); 39 | 40 | Ok(stream.into()) 41 | } 42 | 43 | fn ensure_enum_is_byte_complete( 44 | _type_name: &syn::Ident, 45 | _e: &syn::DataEnum, 46 | ) -> syn::Result { 47 | return Err(syn::Error::new( 48 | proc_macro2::Span::call_site(), 49 | "ByteComplete on enums is not currently supported", 50 | )); 51 | } 52 | 53 | fn ensure_union_is_byte_complete( 54 | _type_name: &syn::Ident, 55 | _u: &syn::DataUnion, 56 | ) -> syn::Result { 57 | return Err(syn::Error::new( 58 | proc_macro2::Span::call_site(), 59 | "ByteComplete on unions is not currently supported", 60 | )); 61 | } 62 | -------------------------------------------------------------------------------- /crates/macros/src/zeroable.rs: -------------------------------------------------------------------------------- 1 | use quote::quote; 2 | use syn::DeriveInput; 3 | 4 | pub fn expand(input: DeriveInput) -> syn::Result { 5 | let type_name = &input.ident; 6 | let attrs = &input.attrs; 7 | if !input.generics.params.is_empty() { 8 | return Err(syn::Error::new( 9 | proc_macro2::Span::call_site(), 10 | "Zeroable on types with generics is not currently supported", 11 | )); 12 | } 13 | let ensure = match &input.data { 14 | syn::Data::Struct(s) => ensure_struct_has_stable_layout(type_name, s)?, 15 | syn::Data::Enum(e) => ensure_enum_has_stable_layout(type_name, e, attrs)?, 16 | syn::Data::Union(u) => ensure_union_has_stable_layout(type_name, u, attrs)?, 17 | }; 18 | 19 | let stream = quote! { 20 | #ensure 21 | unsafe impl ::mem_markers::Zeroable for #type_name {} 22 | }; 23 | Ok(stream) 24 | } 25 | 26 | fn ensure_struct_has_stable_layout( 27 | type_name: &syn::Ident, 28 | s: &syn::DataStruct, 29 | ) -> syn::Result { 30 | let field_types = crate::utils::struct_field_types(s); 31 | if field_types.is_empty() { 32 | return Ok(quote! {}); 33 | } 34 | 35 | let stream = crate::utils::ensure_field_types( 36 | field_types, 37 | type_name, 38 | "e::format_ident!("Zeroable"), 39 | None, 40 | ); 41 | Ok(stream) 42 | } 43 | 44 | fn ensure_enum_has_stable_layout( 45 | _type_name: &syn::Ident, 46 | _e: &syn::DataEnum, 47 | _attrs: &Vec, 48 | ) -> syn::Result { 49 | return Err(syn::Error::new( 50 | proc_macro2::Span::call_site(), 51 | "Zeroable on enums is not currently supported", 52 | )); 53 | } 54 | 55 | fn ensure_union_has_stable_layout( 56 | _type_name: &syn::Ident, 57 | _u: &syn::DataUnion, 58 | _attrs: &Vec, 59 | ) -> syn::Result { 60 | return Err(syn::Error::new( 61 | proc_macro2::Span::call_site(), 62 | "Zeroable on unions is not currently supported", 63 | )); 64 | } 65 | -------------------------------------------------------------------------------- /src/zeroable.rs: -------------------------------------------------------------------------------- 1 | /// A type which can be legally instantiate from zeroed out memory 2 | /// 3 | /// It is not necessary for this type have a fixed layout nor 4 | /// be byte complete just that its layout is guranteed to be valid 5 | /// if all zeros. 6 | pub unsafe trait Zeroable {} 7 | 8 | macro_rules! from_bytes_impl { 9 | ($($type:ty),*) => { 10 | $(unsafe impl Zeroable for $type {})* 11 | }; 12 | } 13 | 14 | from_bytes_impl!( 15 | (), 16 | u8, 17 | u16, 18 | u32, 19 | u64, 20 | u128, 21 | i8, 22 | i16, 23 | i32, 24 | i64, 25 | i128, 26 | isize, 27 | usize, 28 | Option, 29 | Option, 30 | Option, 31 | Option, 32 | Option, 33 | Option, 34 | Option, 35 | Option, 36 | Option, 37 | Option 38 | ); 39 | 40 | unsafe impl Zeroable for Option> {} 41 | unsafe impl Zeroable for [T; 0] {} 42 | unsafe impl Zeroable for [T; 1] {} 43 | unsafe impl Zeroable for [T; 2] {} 44 | unsafe impl Zeroable for [T; 3] {} 45 | unsafe impl Zeroable for [T; 4] {} 46 | unsafe impl Zeroable for [T; 5] {} 47 | unsafe impl Zeroable for [T; 6] {} 48 | unsafe impl Zeroable for [T; 7] {} 49 | unsafe impl Zeroable for [T; 8] {} 50 | unsafe impl Zeroable for [T; 9] {} 51 | unsafe impl Zeroable for [T; 10] {} 52 | unsafe impl Zeroable for [T; 11] {} 53 | unsafe impl Zeroable for [T; 12] {} 54 | unsafe impl Zeroable for [T; 13] {} 55 | unsafe impl Zeroable for [T; 14] {} 56 | unsafe impl Zeroable for [T; 15] {} 57 | unsafe impl Zeroable for [T; 16] {} 58 | unsafe impl Zeroable for [T; 17] {} 59 | unsafe impl Zeroable for [T; 18] {} 60 | unsafe impl Zeroable for [T; 19] {} 61 | unsafe impl Zeroable for [T; 20] {} 62 | unsafe impl Zeroable for [T; 21] {} 63 | unsafe impl Zeroable for [T; 22] {} 64 | unsafe impl Zeroable for [T; 23] {} 65 | unsafe impl Zeroable for [T; 24] {} 66 | -------------------------------------------------------------------------------- /src/from_bytes.rs: -------------------------------------------------------------------------------- 1 | use crate::{ByteComplete, FixedLayout}; 2 | 3 | /// A type which can be legally instantiated from raw bytes. 4 | /// 5 | /// It is necessary for this type have a fixed layout and be 6 | /// byte complete hence it requires the type implements 7 | /// [`ByteComplete`] and [`FixedLayout`]. See those types 8 | /// documentation for information on the invariants those 9 | /// traits represent. 10 | /// 11 | /// [`FromBytes`] is the logical opposite as [`AsBytes`]. 12 | /// 13 | /// [`FromBytes`]: trait.FromBytes.html 14 | /// [`AsBytes`]: trait.AsBytes.html 15 | /// [`ByteComplete`]: trait.ByteComplete.html 16 | /// [`FixedLayout`]: trait.FixedLayout.html 17 | pub unsafe trait FromBytes: ByteComplete + FixedLayout {} 18 | 19 | macro_rules! from_bytes_impl { 20 | ($($type:ty),*) => { 21 | $(unsafe impl FromBytes for $type {})* 22 | }; 23 | } 24 | 25 | from_bytes_impl!( 26 | u8, 27 | u16, 28 | u32, 29 | u64, 30 | u128, 31 | i8, 32 | i16, 33 | i32, 34 | i64, 35 | i128, 36 | isize, 37 | usize, 38 | Option, 39 | Option, 40 | Option, 41 | Option, 42 | Option, 43 | Option, 44 | Option, 45 | Option, 46 | Option, 47 | Option 48 | ); 49 | 50 | unsafe impl FromBytes for Option> {} 51 | unsafe impl FromBytes for [T; 0] {} 52 | unsafe impl FromBytes for [T; 1] {} 53 | unsafe impl FromBytes for [T; 2] {} 54 | unsafe impl FromBytes for [T; 3] {} 55 | unsafe impl FromBytes for [T; 4] {} 56 | unsafe impl FromBytes for [T; 5] {} 57 | unsafe impl FromBytes for [T; 6] {} 58 | unsafe impl FromBytes for [T; 7] {} 59 | unsafe impl FromBytes for [T; 8] {} 60 | unsafe impl FromBytes for [T; 9] {} 61 | unsafe impl FromBytes for [T; 10] {} 62 | unsafe impl FromBytes for [T; 11] {} 63 | unsafe impl FromBytes for [T; 12] {} 64 | unsafe impl FromBytes for [T; 13] {} 65 | unsafe impl FromBytes for [T; 14] {} 66 | unsafe impl FromBytes for [T; 15] {} 67 | unsafe impl FromBytes for [T; 16] {} 68 | unsafe impl FromBytes for [T; 17] {} 69 | unsafe impl FromBytes for [T; 18] {} 70 | unsafe impl FromBytes for [T; 19] {} 71 | unsafe impl FromBytes for [T; 20] {} 72 | unsafe impl FromBytes for [T; 21] {} 73 | unsafe impl FromBytes for [T; 22] {} 74 | unsafe impl FromBytes for [T; 23] {} 75 | unsafe impl FromBytes for [T; 24] {} 76 | -------------------------------------------------------------------------------- /src/as_bytes.rs: -------------------------------------------------------------------------------- 1 | /// A type which can be legally converted to raw bytes. 2 | /// 3 | /// It is necessary for this type have a fixed layout and not 4 | /// have any uninitialized bytes hence it requires those two traits 5 | pub unsafe trait AsBytes: crate::NoUninit + crate::FixedLayout {} 6 | 7 | macro_rules! as_bytes_impl { 8 | ($($type:ty),*) => { 9 | $(unsafe impl AsBytes for $type {})* 10 | }; 11 | } 12 | 13 | as_bytes_impl!( 14 | (), 15 | u8, 16 | u16, 17 | u32, 18 | u64, 19 | u128, 20 | i8, 21 | i16, 22 | i32, 23 | i64, 24 | i128, 25 | usize, 26 | isize, 27 | bool, 28 | char, 29 | core::num::NonZeroI8, 30 | core::num::NonZeroU8, 31 | core::num::NonZeroI16, 32 | core::num::NonZeroU16, 33 | core::num::NonZeroI32, 34 | core::num::NonZeroU32, 35 | core::num::NonZeroI64, 36 | core::num::NonZeroU64, 37 | core::num::NonZeroI128, 38 | core::num::NonZeroU128, 39 | Option, 40 | Option, 41 | Option, 42 | Option, 43 | Option, 44 | Option, 45 | Option, 46 | Option, 47 | Option, 48 | Option, 49 | f32, 50 | f64 51 | ); 52 | 53 | unsafe impl AsBytes for *const T {} 54 | unsafe impl AsBytes for *mut T {} 55 | unsafe impl AsBytes for &T {} 56 | unsafe impl AsBytes for &mut T {} 57 | unsafe impl AsBytes for core::ptr::NonNull {} 58 | unsafe impl AsBytes for Option> {} 59 | 60 | unsafe impl AsBytes for [T; 0] {} 61 | unsafe impl AsBytes for [T; 1] {} 62 | unsafe impl AsBytes for [T; 2] {} 63 | unsafe impl AsBytes for [T; 3] {} 64 | unsafe impl AsBytes for [T; 4] {} 65 | unsafe impl AsBytes for [T; 5] {} 66 | unsafe impl AsBytes for [T; 6] {} 67 | unsafe impl AsBytes for [T; 7] {} 68 | unsafe impl AsBytes for [T; 8] {} 69 | unsafe impl AsBytes for [T; 9] {} 70 | unsafe impl AsBytes for [T; 10] {} 71 | unsafe impl AsBytes for [T; 11] {} 72 | unsafe impl AsBytes for [T; 12] {} 73 | unsafe impl AsBytes for [T; 13] {} 74 | unsafe impl AsBytes for [T; 14] {} 75 | unsafe impl AsBytes for [T; 15] {} 76 | unsafe impl AsBytes for [T; 16] {} 77 | unsafe impl AsBytes for [T; 17] {} 78 | unsafe impl AsBytes for [T; 18] {} 79 | unsafe impl AsBytes for [T; 19] {} 80 | unsafe impl AsBytes for [T; 20] {} 81 | unsafe impl AsBytes for [T; 21] {} 82 | unsafe impl AsBytes for [T; 22] {} 83 | unsafe impl AsBytes for [T; 23] {} 84 | unsafe impl AsBytes for [T; 24] {} 85 | -------------------------------------------------------------------------------- /crates/macros/src/fixed_layout.rs: -------------------------------------------------------------------------------- 1 | use quote::quote; 2 | use syn::DeriveInput; 3 | 4 | pub fn expand(input: DeriveInput) -> syn::Result { 5 | let type_name = &input.ident; 6 | let attrs = &input.attrs; 7 | if !input.generics.params.is_empty() { 8 | return Err(syn::Error::new( 9 | proc_macro2::Span::call_site(), 10 | "FixedLayout on types with generics is not currently supported", 11 | )); 12 | } 13 | let ensure = match &input.data { 14 | syn::Data::Struct(s) => ensure_struct_has_stable_layout(type_name, s, attrs)?, 15 | syn::Data::Enum(e) => ensure_enum_has_stable_layout(type_name, e, attrs)?, 16 | syn::Data::Union(u) => ensure_union_has_stable_layout(type_name, u, attrs)?, 17 | }; 18 | 19 | let stream = quote! { 20 | #ensure 21 | unsafe impl ::mem_markers::FixedLayout for #type_name {} 22 | }; 23 | Ok(stream) 24 | } 25 | 26 | fn ensure_struct_has_stable_layout( 27 | type_name: &syn::Ident, 28 | s: &syn::DataStruct, 29 | attrs: &Vec, 30 | ) -> syn::Result { 31 | let field_types = crate::utils::struct_field_types(s); 32 | if field_types.is_empty() { 33 | return Ok(quote! {}); 34 | } 35 | 36 | if !has_stable_repr(attrs) { 37 | return Err(syn::Error::new( 38 | proc_macro2::Span::call_site(), 39 | "FixedLayout trait requires #[repr(C)] or #[repr(transparent)] on structs with fields", 40 | )); 41 | } 42 | let stream = crate::utils::ensure_field_types( 43 | field_types, 44 | type_name, 45 | "e::format_ident!("FixedLayout"), 46 | None, 47 | ); 48 | Ok(stream) 49 | } 50 | 51 | fn ensure_enum_has_stable_layout( 52 | _type_name: &syn::Ident, 53 | _e: &syn::DataEnum, 54 | _attrs: &Vec, 55 | ) -> syn::Result { 56 | return Err(syn::Error::new( 57 | proc_macro2::Span::call_site(), 58 | "FixedLayout on enums is not currently supported", 59 | )); 60 | } 61 | 62 | fn ensure_union_has_stable_layout( 63 | _type_name: &syn::Ident, 64 | _u: &syn::DataUnion, 65 | _attrs: &Vec, 66 | ) -> syn::Result { 67 | return Err(syn::Error::new( 68 | proc_macro2::Span::call_site(), 69 | "FixedLayout on unions is not currently supported", 70 | )); 71 | } 72 | 73 | fn has_stable_repr(attrs: &Vec) -> bool { 74 | for attr in attrs { 75 | if let Ok(syn::Meta::List(meta)) = attr.parse_meta() { 76 | if meta.path.is_ident("repr") && meta.nested.len() == 1 { 77 | if let syn::NestedMeta::Meta(syn::Meta::Path(path)) = &meta.nested[0] { 78 | if path.is_ident("C") || path.is_ident("transparent") { 79 | return true; 80 | } 81 | } 82 | } 83 | } 84 | } 85 | false 86 | } 87 | -------------------------------------------------------------------------------- /src/fixed_layout.rs: -------------------------------------------------------------------------------- 1 | /// A marker trait representing types that have fixed layouts in memory 2 | /// 3 | /// Types are `FixedLayout` if they have a well-defined and statically known 4 | /// layout in memory. This is usually reserved for primitive types like numbers 5 | /// and bool as well as complex type that are not `#[repr(rust)]` (the default 6 | /// representation for Rust types). 7 | pub unsafe trait FixedLayout {} 8 | 9 | macro_rules! fixed_layout_impl { 10 | ($($type:ty),*) => { 11 | $(unsafe impl FixedLayout for $type {})* 12 | }; 13 | } 14 | 15 | fixed_layout_impl!( 16 | (), 17 | u8, 18 | u16, 19 | u32, 20 | u64, 21 | u128, 22 | i8, 23 | i16, 24 | i32, 25 | i64, 26 | i128, 27 | usize, 28 | isize, 29 | bool, 30 | char, 31 | core::num::NonZeroI8, 32 | core::num::NonZeroU8, 33 | core::num::NonZeroI16, 34 | core::num::NonZeroU16, 35 | core::num::NonZeroI32, 36 | core::num::NonZeroU32, 37 | core::num::NonZeroI64, 38 | core::num::NonZeroU64, 39 | core::num::NonZeroI128, 40 | core::num::NonZeroU128, 41 | Option, 42 | Option, 43 | Option, 44 | Option, 45 | Option, 46 | Option, 47 | Option, 48 | Option, 49 | Option, 50 | Option, 51 | f32, 52 | f64 53 | ); 54 | 55 | unsafe impl FixedLayout for *const T {} 56 | unsafe impl FixedLayout for *mut T {} 57 | unsafe impl FixedLayout for &T {} 58 | unsafe impl FixedLayout for &mut T {} 59 | unsafe impl FixedLayout for core::ptr::NonNull {} 60 | unsafe impl FixedLayout for Option> {} 61 | 62 | unsafe impl FixedLayout for [T; 0] {} 63 | unsafe impl FixedLayout for [T; 1] {} 64 | unsafe impl FixedLayout for [T; 2] {} 65 | unsafe impl FixedLayout for [T; 3] {} 66 | unsafe impl FixedLayout for [T; 4] {} 67 | unsafe impl FixedLayout for [T; 5] {} 68 | unsafe impl FixedLayout for [T; 6] {} 69 | unsafe impl FixedLayout for [T; 7] {} 70 | unsafe impl FixedLayout for [T; 8] {} 71 | unsafe impl FixedLayout for [T; 9] {} 72 | unsafe impl FixedLayout for [T; 10] {} 73 | unsafe impl FixedLayout for [T; 11] {} 74 | unsafe impl FixedLayout for [T; 12] {} 75 | unsafe impl FixedLayout for [T; 13] {} 76 | unsafe impl FixedLayout for [T; 14] {} 77 | unsafe impl FixedLayout for [T; 15] {} 78 | unsafe impl FixedLayout for [T; 16] {} 79 | unsafe impl FixedLayout for [T; 17] {} 80 | unsafe impl FixedLayout for [T; 18] {} 81 | unsafe impl FixedLayout for [T; 19] {} 82 | unsafe impl FixedLayout for [T; 20] {} 83 | unsafe impl FixedLayout for [T; 21] {} 84 | unsafe impl FixedLayout for [T; 22] {} 85 | unsafe impl FixedLayout for [T; 23] {} 86 | unsafe impl FixedLayout for [T; 24] {} 87 | -------------------------------------------------------------------------------- /src/no_uninit.rs: -------------------------------------------------------------------------------- 1 | /// A type which has no uninitialized bytes 2 | /// 3 | /// A type usually has uninitialized bytes in two ways: 4 | /// * Explicitly uninitialized bytes: usually done through [`MaybeUninit`] 5 | /// * Padding 6 | /// 7 | /// As such, types implementing `NoUninit` must have none of the above. 8 | /// 9 | /// [`MaybeUninit`](https://doc.rust-lang.org/stable/core/mem/union.MaybeUninit.html) 10 | pub unsafe trait NoUninit {} 11 | 12 | macro_rules! no_uninit_impl { 13 | ($($type:ty),*) => { 14 | $(unsafe impl NoUninit for $type {})* 15 | }; 16 | } 17 | 18 | no_uninit_impl!( 19 | (), 20 | u8, 21 | u16, 22 | u32, 23 | u64, 24 | u128, 25 | i8, 26 | i16, 27 | i32, 28 | i64, 29 | i128, 30 | usize, 31 | isize, 32 | bool, 33 | char, 34 | core::num::NonZeroI8, 35 | core::num::NonZeroU8, 36 | core::num::NonZeroI16, 37 | core::num::NonZeroU16, 38 | core::num::NonZeroI32, 39 | core::num::NonZeroU32, 40 | core::num::NonZeroI64, 41 | core::num::NonZeroU64, 42 | core::num::NonZeroI128, 43 | core::num::NonZeroU128, 44 | Option, 45 | Option, 46 | Option, 47 | Option, 48 | Option, 49 | Option, 50 | Option, 51 | Option, 52 | Option, 53 | Option, 54 | f32, 55 | f64 56 | ); 57 | 58 | unsafe impl NoUninit for *const T {} 59 | unsafe impl NoUninit for *mut T {} 60 | unsafe impl NoUninit for &T {} 61 | unsafe impl NoUninit for &mut T {} 62 | unsafe impl NoUninit for core::ptr::NonNull {} 63 | unsafe impl NoUninit for Option> {} 64 | 65 | // Note: all types guarantee their size is a multiple of their alignment, 66 | // so a slice [T; N] can never contain padding that the type T doesn't itself contain. 67 | unsafe impl NoUninit for [T; 0] {} 68 | unsafe impl NoUninit for [T; 1] {} 69 | unsafe impl NoUninit for [T; 2] {} 70 | unsafe impl NoUninit for [T; 3] {} 71 | unsafe impl NoUninit for [T; 4] {} 72 | unsafe impl NoUninit for [T; 5] {} 73 | unsafe impl NoUninit for [T; 6] {} 74 | unsafe impl NoUninit for [T; 7] {} 75 | unsafe impl NoUninit for [T; 8] {} 76 | unsafe impl NoUninit for [T; 9] {} 77 | unsafe impl NoUninit for [T; 10] {} 78 | unsafe impl NoUninit for [T; 11] {} 79 | unsafe impl NoUninit for [T; 12] {} 80 | unsafe impl NoUninit for [T; 13] {} 81 | unsafe impl NoUninit for [T; 14] {} 82 | unsafe impl NoUninit for [T; 15] {} 83 | unsafe impl NoUninit for [T; 16] {} 84 | unsafe impl NoUninit for [T; 17] {} 85 | unsafe impl NoUninit for [T; 18] {} 86 | unsafe impl NoUninit for [T; 19] {} 87 | unsafe impl NoUninit for [T; 20] {} 88 | unsafe impl NoUninit for [T; 21] {} 89 | unsafe impl NoUninit for [T; 22] {} 90 | unsafe impl NoUninit for [T; 23] {} 91 | unsafe impl NoUninit for [T; 24] {} 92 | -------------------------------------------------------------------------------- /src/byte_complete.rs: -------------------------------------------------------------------------------- 1 | use crate::Zeroable; 2 | 3 | /// A marker trait representing types are valid no matter what byte values represent them in memory 4 | /// 5 | /// Types like `u8` are `ByteComplete` because no matter what value the byte that represents the `u8` 6 | /// is in memory, it's guranteed to be a valid `u8`. `bool` is not `ByteComplete` because only the bytes 7 | /// `0b1` and `0b0` are valid `bool`s. 8 | /// 9 | /// `ByteComplete` is a more general version of `Zeroable` which has the same constraints but only for 10 | /// zero bytes. 11 | /// 12 | /// `ByteComplete` vs `FromBytes` 13 | /// `ByteComplete` types are not guranteed to have fixed layouts so creating types from bytes 14 | /// may not be predictable though it will always yield a valid value. If you want predictability, 15 | /// use `FromBytes`. 16 | /// 17 | /// So why is `ByteComplete` useful? There may be situations where you simply want to allocate 18 | /// `ByteComplete` values and do not want to ensure that their memory is in some given state before use. 19 | /// `ByteComplete` means that types are always in some valid state no matter their memory. 20 | pub unsafe trait ByteComplete: Zeroable {} 21 | 22 | macro_rules! byte_complete_impl { 23 | ($($type:ty),*) => { 24 | $(unsafe impl ByteComplete for $type {})* 25 | }; 26 | } 27 | 28 | byte_complete_impl!( 29 | (), 30 | u8, 31 | u16, 32 | u32, 33 | u64, 34 | u128, 35 | i8, 36 | i16, 37 | i32, 38 | i64, 39 | i128, 40 | isize, 41 | usize, 42 | Option, 43 | Option, 44 | Option, 45 | Option, 46 | Option, 47 | Option, 48 | Option, 49 | Option, 50 | Option, 51 | Option 52 | ); 53 | 54 | unsafe impl ByteComplete for Option> {} 55 | unsafe impl ByteComplete for [T; 0] {} 56 | unsafe impl ByteComplete for [T; 1] {} 57 | unsafe impl ByteComplete for [T; 2] {} 58 | unsafe impl ByteComplete for [T; 3] {} 59 | unsafe impl ByteComplete for [T; 4] {} 60 | unsafe impl ByteComplete for [T; 5] {} 61 | unsafe impl ByteComplete for [T; 6] {} 62 | unsafe impl ByteComplete for [T; 7] {} 63 | unsafe impl ByteComplete for [T; 8] {} 64 | unsafe impl ByteComplete for [T; 9] {} 65 | unsafe impl ByteComplete for [T; 10] {} 66 | unsafe impl ByteComplete for [T; 11] {} 67 | unsafe impl ByteComplete for [T; 12] {} 68 | unsafe impl ByteComplete for [T; 13] {} 69 | unsafe impl ByteComplete for [T; 14] {} 70 | unsafe impl ByteComplete for [T; 15] {} 71 | unsafe impl ByteComplete for [T; 16] {} 72 | unsafe impl ByteComplete for [T; 17] {} 73 | unsafe impl ByteComplete for [T; 18] {} 74 | unsafe impl ByteComplete for [T; 19] {} 75 | unsafe impl ByteComplete for [T; 20] {} 76 | unsafe impl ByteComplete for [T; 21] {} 77 | unsafe impl ByteComplete for [T; 22] {} 78 | unsafe impl ByteComplete for [T; 23] {} 79 | unsafe impl ByteComplete for [T; 24] {} 80 | --------------------------------------------------------------------------------