Repository: sharksforarms/deku
Pull request #158 (2021-01-07 17:15:01)

feat: zero copy read for &[u8]
Fixes: #147 


Patch:
diff --git a/deku-derive/src/macros/deku_read.rs b/deku-derive/src/macros/deku_read.rs
index fef1827..75c726b 100644
--- a/deku-derive/src/macros/deku_read.rs
+++ b/deku-derive/src/macros/deku_read.rs
@@ -17,6 +17,12 @@ pub(crate) fn emit_deku_read(input: &DekuData) -> Result<TokenStream, syn::Error
 fn emit_struct(input: &DekuData) -> Result<TokenStream, syn::Error> {
     let mut tokens = TokenStream::new();
 
+    let lifetime = input
+        .generics
+        .lifetimes()
+        .next()
+        .map_or(quote!('_), |v| quote!(#v));
+
     let (imp, ty, wher) = input.generics.split_for_impl();
 
     let ident = &input.ident;
@@ -71,9 +77,15 @@ fn emit_struct(input: &DekuData) -> Result<TokenStream, syn::Error> {
             &input.ctx_default,
         );
 
-        tokens.extend(emit_try_from(&imp, &ident, wher));
+        tokens.extend(emit_try_from(&imp, &lifetime, &ident, wher));
 
-        tokens.extend(emit_from_bytes(&imp, &ident, wher, from_bytes_body));
+        tokens.extend(emit_from_bytes(
+            &imp,
+            &lifetime,
+            &ident,
+            wher,
+            from_bytes_body,
+        ));
     }
 
     let (ctx_types, ctx_arg) = gen_ctx_types_and_arg(input.ctx.as_ref())?;
@@ -91,8 +103,8 @@ fn emit_struct(input: &DekuData) -> Result<TokenStream, syn::Error> {
     };
 
     tokens.extend(quote! {
-        impl #imp DekuRead<#ctx_types> for #ident #wher {
-            fn read<'a>(__deku_input_bits: &'a BitSlice<Msb0, u8>, #ctx_arg) -> Result<(&'a BitSlice<Msb0, u8>, Self), DekuError> {
+        impl #imp DekuRead<#lifetime, #ctx_types> for #ident #wher {
+            fn read(__deku_input_bits: &#lifetime BitSlice<Msb0, u8>, #ctx_arg) -> Result<(&#lifetime BitSlice<Msb0, u8>, Self), DekuError> {
                 #read_body
             }
         }
@@ -102,8 +114,8 @@ fn emit_struct(input: &DekuData) -> Result<TokenStream, syn::Error> {
         let read_body = wrap_default_ctx(read_body, &input.ctx, &input.ctx_default);
 
         tokens.extend(quote! {
-            impl #imp DekuRead for #ident #wher {
-                fn read<'a>(__deku_input_bits: &'a BitSlice<Msb0, u8>, _: ()) -> Result<(&'a BitSlice<Msb0, u8>, Self), DekuError> {
+            impl #imp DekuRead<#lifetime> for #ident #wher {
+                fn read(__deku_input_bits: &#lifetime BitSlice<Msb0, u8>, _: ()) -> Result<(&#lifetime BitSlice<Msb0, u8>, Self), DekuError> {
                     #read_body
                 }
             }
@@ -117,6 +129,12 @@ fn emit_struct(input: &DekuData) -> Result<TokenStream, syn::Error> {
 fn emit_enum(input: &DekuData) -> Result<TokenStream, syn::Error> {
     let mut tokens = TokenStream::new();
 
+    let lifetime = input
+        .generics
+        .lifetimes()
+        .next()
+        .map_or(quote!('_), |v| quote!(#v));
+
     let (imp, ty, wher) = input.generics.split_for_impl();
 
     // checked in `emit_deku_read`
@@ -273,9 +291,15 @@ fn emit_enum(input: &DekuData) -> Result<TokenStream, syn::Error> {
             &input.ctx_default,
         );
 
-        tokens.extend(emit_try_from(&imp, &ident, wher));
+        tokens.extend(emit_try_from(&imp, &lifetime, &ident, wher));
 
-        tokens.extend(emit_from_bytes(&imp, &ident, wher, from_bytes_body));
+        tokens.extend(emit_from_bytes(
+            &imp,
+            &lifetime,
+            &ident,
+            wher,
+            from_bytes_body,
+        ));
     }
 
     let (ctx_types, ctx_arg) = gen_ctx_types_and_arg(input.ctx.as_ref())?;
@@ -293,8 +317,8 @@ fn emit_enum(input: &DekuData) -> Result<TokenStream, syn::Error> {
 
     tokens.extend(quote! {
         #[allow(non_snake_case)]
-        impl #imp DekuRead<#ctx_types> for #ident #wher {
-            fn read<'a>(__deku_input_bits: &'a BitSlice<Msb0, u8>, #ctx_arg) -> Result<(&'a BitSlice<Msb0, u8>, Self), DekuError> {
+        impl #imp DekuRead<#lifetime, #ctx_types> for #ident #wher {
+            fn read(__deku_input_bits: &#lifetime BitSlice<Msb0, u8>, #ctx_arg) -> Result<(&#lifetime BitSlice<Msb0, u8>, Self), DekuError> {
                 #read_body
             }
         }
@@ -305,8 +329,8 @@ fn emit_enum(input: &DekuData) -> Result<TokenStream, syn::Error> {
 
         tokens.extend(quote! {
             #[allow(non_snake_case)]
-            impl #imp DekuRead for #ident #wher {
-                fn read<'a>(__deku_input_bits: &'a BitSlice<Msb0, u8>, _: ()) -> Result<(&'a BitSlice<Msb0, u8>, Self), DekuError> {
+            impl #imp DekuRead<#lifetime> for #ident #wher {
+                fn read(__deku_input_bits: &#lifetime BitSlice<Msb0, u8>, _: ()) -> Result<(&#lifetime BitSlice<Msb0, u8>, Self), DekuError> {
                     #read_body
                 }
             }
@@ -531,14 +555,15 @@ fn emit_field_read(
 /// emit `from_bytes()` for struct/enum
 pub fn emit_from_bytes(
     imp: &syn::ImplGenerics,
+    lifetime: &TokenStream,
     ident: &TokenStream,
     wher: Option<&syn::WhereClause>,
     body: TokenStream,
 ) -> TokenStream {
     quote! {
-        impl #imp DekuContainerRead for #ident #wher {
+        impl #imp DekuContainerRead<#lifetime> for #ident #wher {
             #[allow(non_snake_case)]
-            fn from_bytes(__deku_input: (&[u8], usize)) -> Result<((&[u8], usize), Self), DekuError> {
+            fn from_bytes(__deku_input: (&#lifetime [u8], usize)) -> Result<((&#lifetime [u8], usize), Self), DekuError> {
                 #body
             }
         }
@@ -548,14 +573,15 @@ pub fn emit_from_bytes(
 /// emit `TryFrom` trait for struct/enum
 pub fn emit_try_from(
     imp: &syn::ImplGenerics,
+    lifetime: &TokenStream,
     ident: &TokenStream,
     wher: Option<&syn::WhereClause>,
 ) -> TokenStream {
     quote! {
-        impl #imp core::convert::TryFrom<&[u8]> for #ident #wher {
+        impl #imp core::convert::TryFrom<&#lifetime [u8]> for #ident #wher {
             type Error = DekuError;
 
-            fn try_from(input: &[u8]) -> Result<Self, Self::Error> {
+            fn try_from(input: &#lifetime [u8]) -> Result<Self, Self::Error> {
                 let (rest, res) = Self::from_bytes((input, 0))?;
                 if !rest.0.is_empty() {
                     return Err(DekuError::Parse(format!("Too much data")));
diff --git a/deku-derive/src/macros/mod.rs b/deku-derive/src/macros/mod.rs
index 8d85f4e..b146ef5 100644
--- a/deku-derive/src/macros/mod.rs
+++ b/deku-derive/src/macros/mod.rs
@@ -202,7 +202,7 @@ fn gen_field_args(
         .filter_map(|i| *i)
         .collect::<Vec<_>>();
 
-    // Because `impl DekuRead<(T1, T2)>` but `impl DekuRead<T1>`(not tuple)
+    // Because `impl DekuRead<'_, (T1, T2)>` but `impl DekuRead<'_, T1>`(not tuple)
     match &field_args[..] {
         [arg] => Ok(quote! {#arg}),
         args => Ok(quote! {#(#args),*}),
diff --git a/src/impls/cstring.rs b/src/impls/cstring.rs
index 24d127d..87d486b 100644
--- a/src/impls/cstring.rs
+++ b/src/impls/cstring.rs
@@ -14,11 +14,14 @@ where
     }
 }
 
-impl<Ctx: Copy> DekuRead<Ctx> for CString
+impl<'a, Ctx: Copy> DekuRead<'a, Ctx> for CString
 where
-    u8: DekuRead<Ctx>,
+    u8: DekuRead<'a, Ctx>,
 {
-    fn read(input: &BitSlice<Msb0, u8>, ctx: Ctx) -> Result<(&BitSlice<Msb0, u8>, Self), DekuError>
+    fn read(
+        input: &'a BitSlice<Msb0, u8>,
+        ctx: Ctx,
+    ) -> Result<(&'a BitSlice<Msb0, u8>, Self), DekuError>
     where
         Self: Sized,
     {
diff --git a/src/impls/ipaddr.rs b/src/impls/ipaddr.rs
index 44ecac1..26b9069 100644
--- a/src/impls/ipaddr.rs
+++ b/src/impls/ipaddr.rs
@@ -2,11 +2,14 @@ use crate::{DekuError, DekuRead, DekuWrite};
 use bitvec::prelude::*;
 use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
 
-impl<Ctx> DekuRead<Ctx> for Ipv4Addr
+impl<'a, Ctx> DekuRead<'a, Ctx> for Ipv4Addr
 where
-    u32: DekuRead<Ctx>,
+    u32: DekuRead<'a, Ctx>,
 {
-    fn read(input: &BitSlice<Msb0, u8>, ctx: Ctx) -> Result<(&BitSlice<Msb0, u8>, Self), DekuError>
+    fn read(
+        input: &'a BitSlice<Msb0, u8>,
+        ctx: Ctx,
+    ) -> Result<(&'a BitSlice<Msb0, u8>, Self), DekuError>
     where
         Self: Sized,
     {
@@ -25,11 +28,14 @@ where
     }
 }
 
-impl<Ctx> DekuRead<Ctx> for Ipv6Addr
+impl<'a, Ctx> DekuRead<'a, Ctx> for Ipv6Addr
 where
-    u128: DekuRead<Ctx>,
+    u128: DekuRead<'a, Ctx>,
 {
-    fn read(input: &BitSlice<Msb0, u8>, ctx: Ctx) -> Result<(&BitSlice<Msb0, u8>, Self), DekuError>
+    fn read(
+        input: &'a BitSlice<Msb0, u8>,
+        ctx: Ctx,
+    ) -> Result<(&'a BitSlice<Msb0, u8>, Self), DekuError>
     where
         Self: Sized,
     {
diff --git a/src/impls/nonzero.rs b/src/impls/nonzero.rs
index c112071..5157e23 100644
--- a/src/impls/nonzero.rs
+++ b/src/impls/nonzero.rs
@@ -7,7 +7,7 @@ use alloc::format;
 
 macro_rules! ImplDekuTraitsCtx {
     ($typ:ty, $readtype:ty, $ctx_arg:tt, $ctx_type:tt) => {
-        impl DekuRead<$ctx_type> for $typ {
+        impl DekuRead<'_, $ctx_type> for $typ {
             fn read(
                 input: &BitSlice<Msb0, u8>,
                 $ctx_arg: $ctx_type,
diff --git a/src/impls/option.rs b/src/impls/option.rs
index 3f37296..651e983 100644
--- a/src/impls/option.rs
+++ b/src/impls/option.rs
@@ -1,7 +1,7 @@
 use crate::{DekuError, DekuRead, DekuWrite};
 use bitvec::prelude::*;
 
-impl<T: DekuRead<Ctx>, Ctx: Copy> DekuRead<Ctx> for Option<T> {
+impl<'a, T: DekuRead<'a, Ctx>, Ctx: Copy> DekuRead<'a, Ctx> for Option<T> {
     /// Read a T from input and store as Some(T)
     /// * `inner_ctx` - The context required by `T`. It will be passed to every `T`s when constructing.
     /// # Examples
@@ -15,9 +15,9 @@ impl<T: DekuRead<Ctx>, Ctx: Copy> DekuRead<Ctx> for Option<T> {
     /// assert_eq!(v, Some(0x04030201))
     /// ```
     fn read(
-        input: &BitSlice<Msb0, u8>,
+        input: &'a BitSlice<Msb0, u8>,
         inner_ctx: Ctx,
-    ) -> Result<(&BitSlice<Msb0, u8>, Self), DekuError>
+    ) -> Result<(&'a BitSlice<Msb0, u8>, Self), DekuError>
     where
         Self: Sized,
     {
diff --git a/src/impls/primitive.rs b/src/impls/primitive.rs
index c429607..b4e8db1 100644
--- a/src/impls/primitive.rs
+++ b/src/impls/primitive.rs
@@ -7,7 +7,7 @@ use alloc::format;
 
 macro_rules! ImplDekuTraits {
     ($typ:ty) => {
-        impl DekuRead<(Endian, Size)> for $typ {
+        impl DekuRead<'_, (Endian, Size)> for $typ {
             fn read(
                 input: &BitSlice<Msb0, u8>,
                 (endian, size): (Endian, Size),
@@ -97,7 +97,7 @@ macro_rules! ImplDekuTraits {
         }
 
         // Only have `endian`, set `bit_size` to `Size::of::<Type>()`
-        impl DekuRead<Endian> for $typ {
+        impl DekuRead<'_, Endian> for $typ {
             fn read(
                 input: &BitSlice<Msb0, u8>,
                 endian: Endian,
@@ -109,7 +109,7 @@ macro_rules! ImplDekuTraits {
         }
 
         // Only have `bit_size`, set `endian` to `Endian::default`.
-        impl DekuRead<Size> for $typ {
+        impl DekuRead<'_, Size> for $typ {
             fn read(
                 input: &BitSlice<Msb0, u8>,
                 bit_size: Size,
@@ -120,7 +120,7 @@ macro_rules! ImplDekuTraits {
             }
         }
 
-        impl DekuRead for $typ {
+        impl DekuRead<'_> for $typ {
             fn read(
                 input: &BitSlice<Msb0, u8>,
                 _: (),
diff --git a/src/impls/slice.rs b/src/impls/slice.rs
index 65240b3..609ae95 100644
--- a/src/impls/slice.rs
+++ b/src/impls/slice.rs
@@ -1,9 +1,94 @@
 //! Implementations of DekuRead and DekuWrite for [T; N] where 0 < N <= 32
 
-use crate::{DekuError, DekuRead, DekuWrite};
+use crate::{ctx::Limit, DekuError, DekuRead, DekuWrite};
 use bitvec::prelude::*;
 pub use deku_derive::*;
 
+/// Read `u8`s and returns a byte slice up until a given predicate returns true
+/// * `ctx` - The context required by `u8`. It will be passed to every `u8` when constructing.
+/// * `predicate` - the predicate that decides when to stop reading `u8`s
+/// The predicate takes two parameters: the number of bits that have been read so far,
+/// and a borrow of the latest value to have been read. It should return `true` if reading
+/// should now stop, and `false` otherwise
+fn read_slice_with_predicate<'a, Ctx: Copy, Predicate: FnMut(usize, &u8) -> bool>(
+    input: &'a BitSlice<Msb0, u8>,
+    ctx: Ctx,
+    mut predicate: Predicate,
+) -> Result<(&'a BitSlice<Msb0, u8>, &[u8]), DekuError>
+where
+    u8: DekuRead<'a, Ctx>,
+{
+    let mut rest = input;
+    let mut value;
+
+    loop {
+        let (new_rest, val) = u8::read(rest, ctx)?;
+        rest = new_rest;
+
+        let read_idx = input.offset_from(rest) as usize;
+        value = input[..read_idx].as_slice();
+
+        if predicate(read_idx, &val) {
+            break;
+        }
+    }
+
+    Ok((rest, value))
+}
+
+impl<'a, Ctx: Copy, Predicate: FnMut(&u8) -> bool> DekuRead<'a, (Limit<u8, Predicate>, Ctx)>
+    for &'a [u8]
+where
+    u8: DekuRead<'a, Ctx>,
+{
+    /// Read `u8`s until the given limit
+    /// * `limit` - the limiting factor on the amount of `u8`s to read
+    /// * `inner_ctx` - The context required by `u8`. It will be passed to every `u8`s when constructing.
+    /// # Examples
+    /// ```rust
+    /// # use deku::ctx::*;
+    /// # use deku::DekuRead;
+    /// # use bitvec::view::BitView;
+    /// let input = vec![1u8, 2, 3, 4];
+    /// let (rest, v) = <&[u8]>::read(input.view_bits(), (4.into(), Endian::Little)).unwrap();
+    /// assert!(rest.is_empty());
+    /// assert_eq!(&[1u8, 2, 3, 4], v)
+    /// ```
+    fn read(
+        input: &'a BitSlice<Msb0, u8>,
+        (limit, inner_ctx): (Limit<u8, Predicate>, Ctx),
+    ) -> Result<(&'a BitSlice<Msb0, u8>, Self), DekuError> {
+        match limit {
+            // Read a given count of elements
+            Limit::Count(mut count) => {
+                // Handle the trivial case of reading an empty slice
+                if count == 0 {
+                    return Ok((input, &input.as_slice()[..0]));
+                }
+
+                // Otherwise, read until we have read `count` elements
+                read_slice_with_predicate(input, inner_ctx, move |_, _| {
+                    count -= 1;
+                    count == 0
+                })
+            }
+
+            // Read until a given predicate returns true
+            Limit::Until(mut predicate, _) => {
+                read_slice_with_predicate(input, inner_ctx, move |_, value| predicate(value))
+            }
+
+            // Read until a given quantity of bits have been read
+            Limit::Size(size) => {
+                let bit_size = size.bit_size();
+                read_slice_with_predicate(input, inner_ctx, move |read_bits, _| {
+                    read_bits == bit_size
+                })
+            }
+        }
+    }
+}
+
 macro_rules! ImplDekuSliceTraits {
     ($typ:ty; $($count:expr),+ $(,)?) => {
 
@@ -20,14 +105,14 @@ macro_rules! ImplDekuSliceTraits {
         }
 
         $(
-            impl<Ctx: Copy> DekuRead<Ctx> for [$typ; $count]
+            impl<'a, Ctx: Copy> DekuRead<'a, Ctx> for [$typ; $count]
             where
-                $typ: DekuRead<Ctx>,
+                $typ: DekuRead<'a, Ctx>,
             {
                 fn read(
-                    input: &BitSlice<Msb0, u8>,
+                    input: &'a BitSlice<Msb0, u8>,
                     ctx: Ctx,
-                ) -> Result<(&BitSlice<Msb0, u8>, Self), DekuError>
+                ) -> Result<(&'a BitSlice<Msb0, u8>, Self), DekuError>
                 where
                     Self: Sized,
                 {
diff --git a/src/impls/vec.rs b/src/impls/vec.rs
index 19ee1a5..14b3b1a 100644
--- a/src/impls/vec.rs
+++ b/src/impls/vec.rs
@@ -11,12 +11,17 @@ use alloc::vec::Vec;
 /// The predicate takes two parameters: the number of bits that have been read so far,
 /// and a borrow of the latest value to have been read. It should return `true` if reading
 /// should now stop, and `false` otherwise
-fn read_vec_with_predicate<T: DekuRead<Ctx>, Ctx: Copy, Predicate: FnMut(usize, &T) -> bool>(
-    input: &BitSlice<Msb0, u8>,
+fn read_vec_with_predicate<
+    'a,
+    T: DekuRead<'a, Ctx>,
+    Ctx: Copy,
+    Predicate: FnMut(usize, &T) -> bool,
+>(
+    input: &'a BitSlice<Msb0, u8>,
     capacity: Option<usize>,
     ctx: Ctx,
     mut predicate: Predicate,
-) -> Result<(&BitSlice<Msb0, u8>, Vec<T>), DekuError> {
+) -> Result<(&'a BitSlice<Msb0, u8>, Vec<T>), DekuError> {
     let mut res = if let Some(capacity) = capacity {
         Vec::with_capacity(capacity)
     } else {
@@ -40,8 +45,8 @@ fn read_vec_with_predicate<T: DekuRead<Ctx>, Ctx: Copy, Predicate: FnMut(usize,
     Ok((rest, res))
 }
 
-impl<T: DekuRead<Ctx>, Ctx: Copy, Predicate: FnMut(&T) -> bool> DekuRead<(Limit<T, Predicate>, Ctx)>
-    for Vec<T>
+impl<'a, T: DekuRead<'a, Ctx>, Ctx: Copy, Predicate: FnMut(&T) -> bool>
+    DekuRead<'a, (Limit<T, Predicate>, Ctx)> for Vec<T>
 {
     /// Read `T`s until the given limit
     /// * `limit` - the limiting factor on the amount of `T`s to read
@@ -54,12 +59,12 @@ impl<T: DekuRead<Ctx>, Ctx: Copy, Predicate: FnMut(&T) -> bool> DekuRead<(Limit<
     /// let input = vec![1u8, 2, 3, 4];
     /// let (rest, v) = Vec::<u32>::read(input.view_bits(), (1.into(), Endian::Little)).unwrap();
     /// assert!(rest.is_empty());
-    /// assert_eq!(v, vec![0x04030201])
+    /// assert_eq!(vec![0x04030201], v)
     /// ```
     fn read(
-        input: &BitSlice<Msb0, u8>,
+        input: &'a BitSlice<Msb0, u8>,
         (limit, inner_ctx): (Limit<T, Predicate>, Ctx),
-    ) -> Result<(&BitSlice<Msb0, u8>, Self), DekuError>
+    ) -> Result<(&'a BitSlice<Msb0, u8>, Self), DekuError>
     where
         Self: Sized,
     {
@@ -84,29 +89,24 @@ impl<T: DekuRead<Ctx>, Ctx: Copy, Predicate: FnMut(&T) -> bool> DekuRead<(Limit<
             }
 
             // Read until a given quantity of bits have been read
-            Limit::Size(size) => match size {
-                Size::Bits(bit_size) => {
-                    read_vec_with_predicate(input, None, inner_ctx, move |read_bits, _| {
-                        read_bits == bit_size
-                    })
-                }
-                Size::Bytes(_) => {
-                    let bit_size = size.bit_size();
-                    read_vec_with_predicate(input, None, inner_ctx, move |read_bits, _| {
-                        read_bits == bit_size
-                    })
-                }
-            },
+            Limit::Size(size) => {
+                let bit_size = size.bit_size();
+                read_vec_with_predicate(input, None, inner_ctx, move |read_bits, _| {
+                    read_bits == bit_size
+                })
+            }
         }
     }
 }
 
-impl<T: DekuRead, Predicate: FnMut(&T) -> bool> DekuRead<Limit<T, Predicate>> for Vec<T> {
+impl<'a, T: DekuRead<'a>, Predicate: FnMut(&T) -> bool> DekuRead<'a, Limit<T, Predicate>>
+    for Vec<T>
+{
     /// Read `T`s until the given limit from input for types which don't require context.
     fn read(
-        input: &BitSlice<Msb0, u8>,
+        input: &'a BitSlice<Msb0, u8>,
         limit: Limit<T, Predicate>,
-    ) -> Result<(&BitSlice<Msb0, u8>, Self), DekuError>
+    ) -> Result<(&'a BitSlice<Msb0, u8>, Self), DekuError>
     where
         Self: Sized,
     {
diff --git a/src/lib.rs b/src/lib.rs
index 3a2745a..d5f7c60 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -281,24 +281,27 @@ pub mod prelude;
 pub use crate::error::DekuError;
 
 /// "Reader" trait: read bits and construct type
-pub trait DekuRead<Ctx = ()> {
+pub trait DekuRead<'a, Ctx = ()> {
     /// Read bits and construct type
     /// * **input** - Input as bits
     /// * **ctx** - A context required by context-sensitive reading. A unit type `()` means no context
     /// needed.
-    fn read(input: &BitSlice<Msb0, u8>, ctx: Ctx) -> Result<(&BitSlice<Msb0, u8>, Self), DekuError>
+    fn read(
+        input: &'a BitSlice<Msb0, u8>,
+        ctx: Ctx,
+    ) -> Result<(&'a BitSlice<Msb0, u8>, Self), DekuError>
     where
         Self: Sized;
 }
 
 /// "Reader" trait: implemented on DekuRead struct and enum containers. A `container` is a type which
 /// doesn't need any context information.
-pub trait DekuContainerRead: DekuRead<()> {
+pub trait DekuContainerRead<'a>: DekuRead<'a, ()> {
     /// Read bytes and construct type
     /// * **input** - Input as a tuple of (bytes, bit_offset)
     ///
     /// Returns a tuple of the remaining data as (bytes, bit_offset) and a constructed value
-    fn from_bytes(input: (&[u8], usize)) -> Result<((&[u8], usize), Self), DekuError>
+    fn from_bytes(input: (&'a [u8], usize)) -> Result<((&'a [u8], usize), Self), DekuError>
     where
         Self: Sized;
 }


Test patch:
diff --git a/tests/test_alloc.rs b/tests/test_alloc.rs
index 630dfe5..fc2d5a8 100644
--- a/tests/test_alloc.rs
+++ b/tests/test_alloc.rs
@@ -10,7 +10,7 @@ static A: AllocCounterSystem = AllocCounterSystem;
 #[derive(Debug, PartialEq, DekuRead, DekuWrite)]
 #[deku(ctx = "_endian: Endian")]
 struct NestedStruct {
-    pub field_a: u8,
+    field_a: u8,
 }
 
 #[derive(Debug, PartialEq, DekuRead, DekuWrite)]
@@ -23,17 +23,17 @@ enum NestedEnum {
 #[derive(Debug, PartialEq, DekuRead, DekuWrite)]
 #[deku(endian = "big")]
 struct TestDeku {
-    pub field_a: u8,
-    pub field_b: u16,
-    pub field_c: NestedStruct,
-    pub field_d: NestedEnum,
+    field_a: u8,
+    field_b: u16,
+    field_c: NestedStruct,
+    field_d: NestedEnum,
     #[deku(count = "1")]
-    pub field_e: Vec<u8>, // 1 alloc
-    pub field_f: [u8; 3],
+    field_e: Vec<u8>, // 1 alloc
+    field_f: [u8; 3],
     #[deku(bits = "3")]
-    pub field_g: u8, // 1 alloc (bits read)
+    field_g: u8, // 1 alloc (bits read)
     #[deku(bits = "5")]
-    pub field_h: u8, // 1 alloc (bits read)
+    field_h: u8, // 1 alloc (bits read)
 }
 
 mod tests {
diff --git a/tests/test_attributes/mod.rs b/tests/test_attributes/mod.rs
index 92379b5..adb11fa 100644
--- a/tests/test_attributes/mod.rs
+++ b/tests/test_attributes/mod.rs
@@ -1,7 +1,7 @@
 mod test_cond;
 mod test_ctx;
+mod test_limits;
 mod test_map;
 mod test_skip;
 mod test_temp;
 mod test_update;
-mod test_vec_limits;
diff --git a/tests/test_attributes/test_vec_limits/mod.rs b/tests/test_attributes/test_limits/mod.rs
similarity index 100%
rename from tests/test_attributes/test_vec_limits/mod.rs
rename to tests/test_attributes/test_limits/mod.rs
diff --git a/tests/test_attributes/test_limits/test_bits_read.rs b/tests/test_attributes/test_limits/test_bits_read.rs
new file mode 100644
index 0000000..832a59d
--- /dev/null
+++ b/tests/test_attributes/test_limits/test_bits_read.rs
@@ -0,0 +1,126 @@
+use deku::prelude::*;
+use rstest::rstest;
+use std::convert::{TryFrom, TryInto};
+
+mod test_slice {
+    use super::*;
+
+    #[test]
+    fn test_bits_read_static() {
+        #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
+        struct TestStruct<'a> {
+            #[deku(bits_read = "16")]
+            data: &'a [u8],
+        }
+
+        let test_data: Vec<u8> = [0xAA, 0xBB].to_vec();
+
+        let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap();
+        assert_eq!(
+            TestStruct {
+                data: test_data.as_ref()
+            },
+            ret_read
+        );
+
+        let ret_write: Vec<u8> = ret_read.try_into().unwrap();
+        assert_eq!(test_data, ret_write);
+    }
+
+    #[rstest(input_bits,
+        #[should_panic(expected = "Parse(\"not enough data: expected 8 bits got 0 bits\")")]
+        case(15),
+
+        case(16),
+
+        #[should_panic(expected = "Parse(\"not enough data: expected 8 bits got 0 bits\")")]
+        case(17),
+    )]
+    fn test_bits_read_from_field(input_bits: u8) {
+        #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
+        struct TestStruct<'a> {
+            bits: u8,
+
+            #[deku(bits_read = "bits")]
+            data: &'a [u8],
+        }
+
+        let test_data: Vec<u8> = [input_bits, 0xAA, 0xBB].to_vec();
+
+        let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap();
+        assert_eq!(
+            TestStruct {
+                bits: 16,
+                data: &test_data[1..]
+            },
+            ret_read
+        );
+
+        let ret_write: Vec<u8> = ret_read.try_into().unwrap();
+        assert_eq!(test_data, ret_write);
+    }
+}
+
+mod test_vec {
+    use super::*;
+
+    #[test]
+    fn test_bits_read_static() {
+        #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
+        struct TestStruct {
+            #[deku(endian = "little", bits_read = "16")]
+            data: Vec<u16>,
+        }
+
+        let test_data: Vec<u8> = [0xAA, 0xBB].to_vec();
+
+        let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap();
+        assert_eq!(
+            TestStruct {
+                // We should read 16 bits, not 16 elements,
+                // thus resulting in a single u16 element
+                data: vec![0xBBAA]
+            },
+            ret_read
+        );
+
+        let ret_write: Vec<u8> = ret_read.try_into().unwrap();
+        assert_eq!(test_data, ret_write);
+    }
+
+    #[rstest(input_bits,
+        #[should_panic(expected = "Parse(\"not enough data: expected 16 bits got 0 bits\")")]
+        case(15),
+
+        case(16),
+
+        #[should_panic(expected = "Parse(\"not enough data: expected 16 bits got 0 bits\")")]
+        case(17),
+    )]
+    fn test_bits_read_from_field(input_bits: u8) {
+        #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
+        struct TestStruct {
+            bits: u8,
+
+            #[deku(endian = "little", bits_read = "bits")]
+            data: Vec<u16>,
+        }
+
+        let test_data: Vec<u8> = [input_bits, 0xAA, 0xBB].to_vec();
+
+        let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap();
+        assert_eq!(
+            TestStruct {
+                bits: 16,
+
+                // We should read 16 bits, not 16 elements,
+                // thus resulting in a single u16 element
+                data: vec![0xBBAA]
+            },
+            ret_read
+        );
+
+        let ret_write: Vec<u8> = ret_read.try_into().unwrap();
+        assert_eq!(test_data, ret_write);
+    }
+}
diff --git a/tests/test_attributes/test_limits/test_bytes_read.rs b/tests/test_attributes/test_limits/test_bytes_read.rs
new file mode 100644
index 0000000..03a5c45
--- /dev/null
+++ b/tests/test_attributes/test_limits/test_bytes_read.rs
@@ -0,0 +1,120 @@
+use deku::prelude::*;
+use rstest::rstest;
+use std::convert::{TryFrom, TryInto};
+
+mod test_slice {
+    use super::*;
+
+    #[test]
+    fn test_bytes_read_static() {
+        #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
+        struct TestStruct<'a> {
+            #[deku(bytes_read = "2")]
+            data: &'a [u8],
+        }
+
+        let test_data: Vec<u8> = [0xAA, 0xBB].to_vec();
+
+        let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap();
+        assert_eq!(
+            TestStruct {
+                data: test_data.as_ref()
+            },
+            ret_read
+        );
+
+        let ret_write: Vec<u8> = ret_read.try_into().unwrap();
+        assert_eq!(test_data, ret_write);
+    }
+
+    #[rstest(input_bytes,
+        case(2),
+
+        #[should_panic(expected = "Parse(\"not enough data: expected 8 bits got 0 bits\")")]
+        case(3),
+    )]
+    fn test_bytes_read_from_field(input_bytes: u8) {
+        #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
+        struct TestStruct<'a> {
+            bytes: u8,
+
+            #[deku(bytes_read = "bytes")]
+            data: &'a [u8],
+        }
+
+        let test_data: Vec<u8> = [input_bytes, 0xAA, 0xBB].to_vec();
+
+        let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap();
+        assert_eq!(
+            TestStruct {
+                bytes: 0x02,
+                data: &test_data[1..]
+            },
+            ret_read
+        );
+
+        let ret_write: Vec<u8> = ret_read.try_into().unwrap();
+        assert_eq!(test_data, ret_write);
+    }
+}
+
+mod test_vec {
+    use super::*;
+
+    #[test]
+    fn test_bytes_read_static() {
+        #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
+        struct TestStruct {
+            #[deku(endian = "little", bytes_read = "2")]
+            data: Vec<u16>,
+        }
+
+        let test_data: Vec<u8> = [0xAA, 0xBB].to_vec();
+
+        let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap();
+        assert_eq!(
+            TestStruct {
+                // We should read two bytes, not two elements,
+                // thus resulting in a single u16 element
+                data: vec![0xBBAA]
+            },
+            ret_read
+        );
+
+        let ret_write: Vec<u8> = ret_read.try_into().unwrap();
+        assert_eq!(test_data, ret_write);
+    }
+
+    #[rstest(input_bytes,
+        case(2),
+
+        #[should_panic(expected = "Parse(\"not enough data: expected 16 bits got 0 bits\")")]
+        case(3),
+    )]
+    fn test_bytes_read_from_field(input_bytes: u8) {
+        #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
+        struct TestStruct {
+            bytes: u8,
+
+            #[deku(endian = "little", bytes_read = "bytes")]
+            data: Vec<u16>,
+        }
+
+        let test_data: Vec<u8> = [input_bytes, 0xAA, 0xBB].to_vec();
+
+        let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap();
+        assert_eq!(
+            TestStruct {
+                bytes: 0x02,
+
+                // We should read two bytes, not two elements,
+                // thus resulting in a single u16 element
+                data: vec![0xBBAA]
+            },
+            ret_read
+        );
+
+        let ret_write: Vec<u8> = ret_read.try_into().unwrap();
+        assert_eq!(test_data, ret_write);
+    }
+}
diff --git a/tests/test_attributes/test_limits/test_count.rs b/tests/test_attributes/test_limits/test_count.rs
new file mode 100644
index 0000000..dae98e7
--- /dev/null
+++ b/tests/test_attributes/test_limits/test_count.rs
@@ -0,0 +1,132 @@
+use deku::prelude::*;
+use std::convert::{TryFrom, TryInto};
+
+mod test_slice {
+    use super::*;
+
+    #[test]
+    fn test_count_static() {
+        #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
+        struct TestStruct<'a> {
+            #[deku(count = "2")]
+            data: &'a [u8],
+        }
+
+        let test_data: Vec<u8> = [0xAA, 0xBB].to_vec();
+
+        let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap();
+        assert_eq!(
+            TestStruct {
+                data: test_data.as_ref()
+            },
+            ret_read
+        );
+
+        let ret_write: Vec<u8> = ret_read.try_into().unwrap();
+        assert_eq!(test_data, ret_write);
+    }
+
+    #[test]
+    fn test_count_from_field() {
+        #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
+        struct TestStruct<'a> {
+            count: u8,
+            #[deku(count = "count")]
+            data: &'a [u8],
+        }
+
+        let test_data: Vec<u8> = [0x02, 0xAA, 0xBB].to_vec();
+
+        let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap();
+        assert_eq!(
+            TestStruct {
+                count: 0x02,
+                data: &test_data[1..]
+            },
+            ret_read
+        );
+
+        let ret_write: Vec<u8> = ret_read.try_into().unwrap();
+        assert_eq!(test_data, ret_write);
+    }
+
+    #[test]
+    #[should_panic(expected = "Parse(\"not enough data: expected 8 bits got 0 bits\")")]
+    fn test_count_error() {
+        #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
+        struct TestStruct<'a> {
+            count: u8,
+            #[deku(count = "count")]
+            data: &'a [u8],
+        }
+
+        let test_data: Vec<u8> = [0x03, 0xAA, 0xBB].to_vec();
+
+        let _ret_read = TestStruct::try_from(test_data.as_ref()).unwrap();
+    }
+}
+
+mod test_vec {
+    use super::*;
+
+    #[test]
+    fn test_count_static() {
+        #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
+        struct TestStruct {
+            #[deku(count = "2")]
+            data: Vec<u8>,
+        }
+
+        let test_data: Vec<u8> = [0xAA, 0xBB].to_vec();
+
+        let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap();
+        assert_eq!(
+            TestStruct {
+                data: vec![0xAA, 0xBB]
+            },
+            ret_read
+        );
+
+        let ret_write: Vec<u8> = ret_read.try_into().unwrap();
+        assert_eq!(test_data, ret_write);
+    }
+
+    #[test]
+    fn test_count_from_field() {
+        #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
+        struct TestStruct {
+            count: u8,
+            #[deku(count = "count")]
+            data: Vec<u8>,
+        }
+
+        let test_data: Vec<u8> = [0x02, 0xAA, 0xBB].to_vec();
+
+        let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap();
+        assert_eq!(
+            TestStruct {
+                count: 0x02,
+                data: vec![0xAA, 0xBB]
+            },
+            ret_read
+        );
+
+        let ret_write: Vec<u8> = ret_read.try_into().unwrap();
+        assert_eq!(test_data, ret_write);
+    }
+
+    #[test]
+    #[should_panic(expected = "Parse(\"not enough data: expected 8 bits got 0 bits\")")]
+    fn test_count_error() {
+        #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
+        struct TestStruct {
+            count: u8,
+            #[deku(count = "count")]
+            data: Vec<u8>,
+        }
+
+        let test_data: Vec<u8> = [0x03, 0xAA, 0xBB].to_vec();
+
+        let _ret_read = TestStruct::try_from(test_data.as_ref()).unwrap();
+    }
+}
diff --git a/tests/test_attributes/test_limits/test_until.rs b/tests/test_attributes/test_limits/test_until.rs
new file mode 100644
index 0000000..4bf56d0
--- /dev/null
+++ b/tests/test_attributes/test_limits/test_until.rs
@@ -0,0 +1,136 @@
+use deku::prelude::*;
+use std::convert::{TryFrom, TryInto};
+
+mod test_slice {
+    use super::*;
+
+    #[test]
+    fn test_until_static() {
+        #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
+        struct TestStruct<'a> {
+            #[deku(until = "|v: &u8| *v == 0xBB")]
+            data: &'a [u8],
+        }
+
+        let test_data: Vec<u8> = [0xAA, 0xBB].to_vec();
+
+        let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap();
+        assert_eq!(
+            TestStruct {
+                data: test_data.as_ref()
+            },
+            ret_read
+        );
+
+        let ret_write: Vec<u8> = ret_read.try_into().unwrap();
+        assert_eq!(test_data, ret_write);
+    }
+
+    #[test]
+    fn test_until_from_field() {
+        #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
+        struct TestStruct<'a> {
+            until: u8,
+
+            #[deku(until = "|v: &u8| *v == *until")]
+            data: &'a [u8],
+        }
+
+        let test_data: Vec<u8> = [0xBB, 0xAA, 0xBB].to_vec();
+
+        let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap();
+        assert_eq!(
+            TestStruct {
+                until: 0xBB,
+                data: &test_data[1..]
+            },
+            ret_read
+        );
+
+        let ret_write: Vec<u8> = ret_read.try_into().unwrap();
+        assert_eq!(test_data, ret_write);
+    }
+
+    #[test]
+    #[should_panic(expected = "Parse(\"not enough data: expected 8 bits got 0 bits\")")]
+    fn test_until_error() {
+        #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
+        struct TestStruct<'a> {
+            until: u8,
+
+            #[deku(until = "|v: &u8| *v == *until")]
+            data: &'a [u8],
+        }
+
+        let test_data: Vec<u8> = [0xCC, 0xAA, 0xBB].to_vec();
+
+        let _ret_read = TestStruct::try_from(test_data.as_ref()).unwrap();
+    }
+}
+
+mod test_vec {
+    use super::*;
+
+    #[test]
+    fn test_until_static() {
+        #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
+        struct TestStruct {
+            #[deku(until = "|v: &u8| *v == 0xBB")]
+            data: Vec<u8>,
+        }
+
+        let test_data: Vec<u8> = [0xAA, 0xBB].to_vec();
+
+        let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap();
+        assert_eq!(
+            TestStruct {
+                data: vec![0xAA, 0xBB]
+            },
+            ret_read
+        );
+
+        let ret_write: Vec<u8> = ret_read.try_into().unwrap();
+        assert_eq!(test_data, ret_write);
+    }
+
+    #[test]
+    fn test_until_from_field() {
+        #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
+        struct TestStruct {
+            until: u8,
+
+            #[deku(until = "|v: &u8| *v == *until")]
+            data: Vec<u8>,
+        }
+
+        let test_data: Vec<u8> = [0xBB, 0xAA, 0xBB].to_vec();
+
+        let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap();
+        assert_eq!(
+            TestStruct {
+                until: 0xBB,
+                data: vec![0xAA, 0xBB]
+            },
+            ret_read
+        );
+
+        let ret_write: Vec<u8> = ret_read.try_into().unwrap();
+        assert_eq!(test_data, ret_write);
+    }
+
+    #[test]
+    #[should_panic(expected = "Parse(\"not enough data: expected 8 bits got 0 bits\")")]
+    fn test_until_error() {
+        #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
+        struct TestStruct {
+            until: u8,
+
+            #[deku(until = "|v: &u8| *v == *until")]
+            data: Vec<u8>,
+        }
+
+        let test_data: Vec<u8> = [0xCC, 0xAA, 0xBB].to_vec();
+
+        let _ret_read = TestStruct::try_from(test_data.as_ref()).unwrap();
+    }
+}
diff --git a/tests/test_attributes/test_vec_limits/test_bits_read.rs b/tests/test_attributes/test_vec_limits/test_bits_read.rs
deleted file mode 100644
index 90e4707..0000000
--- a/tests/test_attributes/test_vec_limits/test_bits_read.rs
+++ /dev/null
@@ -1,78 +0,0 @@
-use deku::prelude::*;
-use std::convert::{TryFrom, TryInto};
-
-#[test]
-fn test_bits_read_static() {
-    #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
-    struct TestStruct {
-        #[deku(endian = "little", bits_read = "16")]
-        data: Vec<u16>,
-    }
-
-    let test_data: Vec<u8> = [0xAA, 0xBB].to_vec();
-
-    let mut ret_read = TestStruct::try_from(test_data.as_ref()).unwrap();
-    assert_eq!(
-        TestStruct {
-            // We should read 16 bits, not 16 elements,
-            // thus resulting in a single u16 element
-            data: vec![0xBBAA]
-        },
-        ret_read
-    );
-
-    // Add an item to the vec
-    ret_read.data.push(0xFFEE);
-
-    let ret_write: Vec<u8> = ret_read.try_into().unwrap();
-    assert_eq!([0xAA, 0xBB, 0xEE, 0xFF].to_vec(), ret_write);
-}
-
-#[test]
-fn test_bits_read_from_field() {
-    #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
-    struct TestStruct {
-        bits: u8,
-
-        #[deku(endian = "little", bits_read = "bits")]
-        data: Vec<u16>,
-    }
-
-    let test_data: Vec<u8> = [16, 0xAA, 0xBB].to_vec();
-
-    let mut ret_read = TestStruct::try_from(test_data.as_ref()).unwrap();
-    assert_eq!(
-        TestStruct {
-            bits: 16,
-
-            // We should read 16 bits, not 16 elements,
-            // thus resulting in a single u16 element
-            data: vec![0xBBAA]
-        },
-        ret_read
-    );
-
-    // Add an item to the vec
-    ret_read.data.push(0xFFEE);
-
-    // `bits` is still 16, this is intended. `update` attribute should be
-    // used if `bits` is to be updated
-    let ret_write: Vec<u8> = ret_read.try_into().unwrap();
-    assert_eq!([16, 0xAA, 0xBB, 0xEE, 0xFF].to_vec(), ret_write);
-}
-
-#[test]
-#[should_panic(expected = "Parse(\"not enough data: expected 16 bits got 0 bits\")")]
-fn test_bits_read_error() {
-    #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
-    struct TestStruct {
-        bits: u8,
-
-        #[deku(endian = "little", bits_read = "bits")]
-        data: Vec<u16>,
-    }
-
-    let test_data: Vec<u8> = [17, 0xAA, 0xBB].to_vec();
-
-    let _ret_read = TestStruct::try_from(test_data.as_ref()).unwrap();
-}
diff --git a/tests/test_attributes/test_vec_limits/test_bytes_read.rs b/tests/test_attributes/test_vec_limits/test_bytes_read.rs
deleted file mode 100644
index 0a7317c..0000000
--- a/tests/test_attributes/test_vec_limits/test_bytes_read.rs
+++ /dev/null
@@ -1,78 +0,0 @@
-use deku::prelude::*;
-use std::convert::{TryFrom, TryInto};
-
-#[test]
-fn test_bytes_read_static() {
-    #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
-    struct TestStruct {
-        #[deku(endian = "little", bytes_read = "2")]
-        data: Vec<u16>,
-    }
-
-    let test_data: Vec<u8> = [0xAA, 0xBB].to_vec();
-
-    let mut ret_read = TestStruct::try_from(test_data.as_ref()).unwrap();
-    assert_eq!(
-        TestStruct {
-            // We should read two bytes, not two elements,
-            // thus resulting in a single u16 element
-            data: vec![0xBBAA]
-        },
-        ret_read
-    );
-
-    // Add an item to the vec
-    ret_read.data.push(0xFFEE);
-
-    let ret_write: Vec<u8> = ret_read.try_into().unwrap();
-    assert_eq!([0xAA, 0xBB, 0xEE, 0xFF].to_vec(), ret_write);
-}
-
-#[test]
-fn test_bytes_read_from_field() {
-    #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
-    struct TestStruct {
-        bytes: u8,
-
-        #[deku(endian = "little", bytes_read = "bytes")]
-        data: Vec<u16>,
-    }
-
-    let test_data: Vec<u8> = [0x02, 0xAA, 0xBB].to_vec();
-
-    let mut ret_read = TestStruct::try_from(test_data.as_ref()).unwrap();
-    assert_eq!(
-        TestStruct {
-            bytes: 0x02,
-
-            // We should read two bytes, not two elements,
-            // thus resulting in a single u16 element
-            data: vec![0xBBAA]
-        },
-        ret_read
-    );
-
-    // Add an item to the vec
-    ret_read.data.push(0xFFEE);
-
-    // `bytes` is still 0x02, this is intended. `update` attribute should be
-    // used if `bytes` is to be updated
-    let ret_write: Vec<u8> = ret_read.try_into().unwrap();
-    assert_eq!([0x02, 0xAA, 0xBB, 0xEE, 0xFF].to_vec(), ret_write);
-}
-
-#[test]
-#[should_panic(expected = "Parse(\"not enough data: expected 16 bits got 0 bits\")")]
-fn test_bytes_read_error() {
-    #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
-    struct TestStruct {
-        bytes: u8,
-
-        #[deku(endian = "little", bytes_read = "bytes")]
-        data: Vec<u16>,
-    }
-
-    let test_data: Vec<u8> = [0x03, 0xAA, 0xBB].to_vec();
-
-    let _ret_read = TestStruct::try_from(test_data.as_ref()).unwrap();
-}
diff --git a/tests/test_attributes/test_vec_limits/test_count.rs b/tests/test_attributes/test_vec_limits/test_count.rs
deleted file mode 100644
index a85515f..0000000
--- a/tests/test_attributes/test_vec_limits/test_count.rs
+++ /dev/null
@@ -1,71 +0,0 @@
-use deku::prelude::*;
-use std::convert::{TryFrom, TryInto};
-
-#[test]
-fn test_count_static() {
-    #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
-    struct TestStruct {
-        #[deku(count = "2")]
-        data: Vec<u8>,
-    }
-
-    let test_data: Vec<u8> = [0xAA, 0xBB].to_vec();
-
-    let mut ret_read = TestStruct::try_from(test_data.as_ref()).unwrap();
-    assert_eq!(
-        TestStruct {
-            data: vec![0xAA, 0xBB]
-        },
-        ret_read
-    );
-
-    // Add an item to the vec
-    ret_read.data.push(0xFF);
-
-    let ret_write: Vec<u8> = ret_read.try_into().unwrap();
-    assert_eq!([0xAA, 0xBB, 0xFF].to_vec(), ret_write);
-}
-
-#[test]
-fn test_count_from_field() {
-    #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
-    struct TestStruct {
-        count: u8,
-        #[deku(count = "count")]
-        data: Vec<u8>,
-    }
-
-    let test_data: Vec<u8> = [0x02, 0xAA, 0xBB].to_vec();
-
-    let mut ret_read = TestStruct::try_from(test_data.as_ref()).unwrap();
-    assert_eq!(
-        TestStruct {
-            count: 0x02,
-            data: vec![0xAA, 0xBB]
-        },
-        ret_read
-    );
-
-    // Add an item to the vec
-    ret_read.data.push(0xFF);
-
-    // `count` is still 0x02, this is intended. `update` attribute should be
-    // used if `count` is to be updated
-    let ret_write: Vec<u8> = ret_read.try_into().unwrap();
-    assert_eq!([0x02, 0xAA, 0xBB, 0xFF].to_vec(), ret_write);
-}
-
-#[test]
-#[should_panic(expected = "Parse(\"not enough data: expected 8 bits got 0 bits\")")]
-fn test_count_error() {
-    #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
-    struct TestStruct {
-        count: u8,
-        #[deku(count = "count")]
-        data: Vec<u8>,
-    }
-
-    let test_data: Vec<u8> = [0x03, 0xAA, 0xBB].to_vec();
-
-    let _ret_read = TestStruct::try_from(test_data.as_ref()).unwrap();
-}
diff --git a/tests/test_attributes/test_vec_limits/test_until.rs b/tests/test_attributes/test_vec_limits/test_until.rs
deleted file mode 100644
index a182e7b..0000000
--- a/tests/test_attributes/test_vec_limits/test_until.rs
+++ /dev/null
@@ -1,73 +0,0 @@
-use deku::prelude::*;
-use std::convert::{TryFrom, TryInto};
-
-#[test]
-fn test_until_static() {
-    #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
-    struct TestStruct {
-        #[deku(until = "|v: &u8| *v == 0xBB")]
-        data: Vec<u8>,
-    }
-
-    let test_data: Vec<u8> = [0xAA, 0xBB].to_vec();
-
-    let mut ret_read = TestStruct::try_from(test_data.as_ref()).unwrap();
-    assert_eq!(
-        TestStruct {
-            data: vec![0xAA, 0xBB]
-        },
-        ret_read
-    );
-
-    // Add an item to the vec
-    ret_read.data.push(0xFF);
-
-    let ret_write: Vec<u8> = ret_read.try_into().unwrap();
-    assert_eq!([0xAA, 0xBB, 0xFF].to_vec(), ret_write);
-}
-
-#[test]
-fn test_until_from_field() {
-    #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
-    struct TestStruct {
-        until: u8,
-
-        #[deku(until = "|v: &u8| *v == *until")]
-        data: Vec<u8>,
-    }
-
-    let test_data: Vec<u8> = [0xBB, 0xAA, 0xBB].to_vec();
-
-    let mut ret_read = TestStruct::try_from(test_data.as_ref()).unwrap();
-    assert_eq!(
-        TestStruct {
-            until: 0xBB,
-            data: vec![0xAA, 0xBB]
-        },
-        ret_read
-    );
-
-    // Add an item to the vec
-    ret_read.data.push(0xFF);
-
-    // `until` is still 0x02, this is intended. `update` attribute should be
-    // used if `until` is to be updated
-    let ret_write: Vec<u8> = ret_read.try_into().unwrap();
-    assert_eq!([0xBB, 0xAA, 0xBB, 0xFF].to_vec(), ret_write);
-}
-
-#[test]
-#[should_panic(expected = "Parse(\"not enough data: expected 8 bits got 0 bits\")")]
-fn test_until_error() {
-    #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
-    struct TestStruct {
-        until: u8,
-
-        #[deku(until = "|v: &u8| *v == *until")]
-        data: Vec<u8>,
-    }
-
-    let test_data: Vec<u8> = [0xCC, 0xAA, 0xBB].to_vec();
-
-    let _ret_read = TestStruct::try_from(test_data.as_ref()).unwrap();
-}
diff --git a/tests/test_enum.rs b/tests/test_enum.rs
index b87b56e..65e6057 100644
--- a/tests/test_enum.rs
+++ b/tests/test_enum.rs
@@ -8,7 +8,7 @@ use std::convert::{TryFrom, TryInto};
 
 #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
 #[deku(type = "u8")]
-pub enum TestEnum {
+enum TestEnum {
     #[deku(id = "1")]
     VarA(u8),
     #[deku(id = "2")]
@@ -53,7 +53,7 @@ fn test_enum(input: &[u8], expected: TestEnum) {
 fn test_enum_error() {
     #[derive(DekuRead)]
     #[deku(type = "u8")]
-    pub enum TestEnum {
+    enum TestEnum {
         #[deku(id = "1")]
         VarA(u8),
     }
@@ -64,7 +64,7 @@ fn test_enum_error() {
 
 #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
 #[deku(type = "u8")]
-pub enum TestEnumDiscriminant {
+enum TestEnumDiscriminant {
     VarA = 0x00,
     VarB,
     VarC = 0x02,
diff --git a/tests/test_generic.rs b/tests/test_generic.rs
index 668799a..6151c22 100644
--- a/tests/test_generic.rs
+++ b/tests/test_generic.rs
@@ -4,11 +4,11 @@ use std::convert::{TryFrom, TryInto};
 #[test]
 fn test_generic_struct() {
     #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
-    pub struct TestStruct<T>
+    struct TestStruct<T>
     where
-        T: deku::DekuWrite + deku::DekuRead,
+        T: deku::DekuWrite + for<'a> deku::DekuRead<'a>,
     {
-        pub field_a: T,
+        field_a: T,
     }
 
     let test_data: Vec<u8> = [0x01].to_vec();
@@ -24,9 +24,9 @@ fn test_generic_struct() {
 fn test_generic_enum() {
     #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
     #[deku(type = "u8")]
-    pub enum TestEnum<T>
+    enum TestEnum<T>
     where
-        T: deku::DekuWrite + deku::DekuRead,
+        T: deku::DekuWrite + for<'a> deku::DekuRead<'a>,
     {
         #[deku(id = "1")]
         VariantT(T),
@@ -40,3 +40,25 @@ fn test_generic_enum() {
     let ret_write: Vec<u8> = ret_read.try_into().unwrap();
     assert_eq!(test_data, ret_write);
 }
+
+#[test]
+fn test_slice_struct() {
+    #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
+    struct TestStruct<'a> {
+        #[deku(count = "2")]
+        field_a: &'a [u8],
+    }
+
+    let test_data: Vec<u8> = [0x01, 0x02].to_vec();
+
+    let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap();
+    assert_eq!(
+        TestStruct {
+            field_a: test_data.as_ref()
+        },
+        ret_read
+    );
+
+    let ret_write: Vec<u8> = ret_read.try_into().unwrap();
+    assert_eq!(test_data, ret_write);
+}
diff --git a/tests/test_magic.rs b/tests/test_magic.rs
index f48052f..b9b4f1e 100644
--- a/tests/test_magic.rs
+++ b/tests/test_magic.rs
@@ -24,7 +24,7 @@ use std::convert::{TryFrom, TryInto};
 fn test_magic_struct(input: &[u8]) {
     #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
     #[deku(magic = b"deku")]
-    pub struct TestStruct {}
+    struct TestStruct {}
 
     let ret_read = TestStruct::try_from(input).unwrap();
 
@@ -58,7 +58,7 @@ fn test_magic_struct(input: &[u8]) {
 fn test_magic_enum(input: &[u8]) {
     #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
     #[deku(magic = b"deku", type = "u8")]
-    pub enum TestEnum {
+    enum TestEnum {
         #[deku(id = "0")]
         Variant,
     }