Repository: sharksforarms/deku
Pull request #61 (2020-07-19 14:16:20)

Attempt to add context support
### Motivation

This PR added a generic parameter called `Ctx` for `DekuRead` and `DekuWrite` to support context transmitting. So we can replace fixed arguments `input_is_le`, `bit_size`, and `count` (only used by `Vec`) with more flexible ones. Currently we need to pass a `None` even those arguments won't be used at all.

And it will make providing an attribute of context possible:

```rust
#[deku(ctx = "a: u8")]
struct Foo{}
#[derive(DekuRead, DekuWrite)]
struct Bar {
    b: u8,
    #[deku(ctx = "a")]
    foo: Foo,
    #[deku(ctx = "a, foo")]
    foos: Vec<Xx>
}
```

### Detail

Both of `DekuRead` and `DekuWrite` have an generic parameter to allow users implement context (`Ctx`) sensitive structure:

```rust
pub trait DekuRead<Ctx> {
    fn read(input: _, ctx: Ctx) -> Self;
}
pub trait DekuWrite<Ctx> {
    fn write(&self, ctx: Ctx) -> Vec<u8>;
}
```

All primary types need two "context" (`endian` and `bit_size`):

```rust
impl DekuRead<(Endian, usize)> for u8 {
    fn read(input: _, (endian, bit_size): (Endian, usize)) -> u8{}
}
impl DekuRead<Endian> for u8 {
    fn read(input: _, endian: Endian) -> u8 { u8::read(endian, size_of<u8>()) }
}
// usage:
let _ = u8::read(Endian::Native);
let _ = u8::read(Endian::Bit, 12);
```

A `Vec` need a `count` (and some addition context for inner type):

```rust
impl<T, InnerCtx> DekuRead<(Count, InnerCtx)> for Vec<T> {
    fn read(input: _, (count, inner_ctx): (Count, InnerCtx)) -> Vec<T> {
        for _i in 0..count {
            let (new_rest, val) = <T>::read(rest, inner_ctx);
            res.push(val);
            rest = new_rest;
        }
    }
}
impl<T> DekuRead<Count> for Vec<T> {}
// usage:
let _ = Vec::<u8>::read((2, (Endian::Native, 7));
let _ = Vec::<u8>::read((2, Endian::Native));
```

#### Derive Macro

A `ctx` attribute will automatically add context for a structure: 

```rust
#[derive(DekuRead)]
#[deku(ctx = "a: u8, x: String, y: bool")]
struct Foo {
    #[deku(cond="a == 0", endian="big")]
    b: Option<u8>;
    #[deku(ctx="y", count=a)]
    c: Vec<Bar>;
}
// expanded to
impl DekuRead<(u8, String, bool)> for Foo {
    fn read(input: _, (a, x, y): (u8, String, bool)) -> Self {
        let b = if a == 0 {
            Some(u8::read(input, Endian::Big))
        } else { 
            None
        };
        let c = Vec<Bar>::read(input, (a, y));
        Foo{ b, c }
    }
}
// usage
let _ = Foo::read((1, "".to_owned(), false));
```

Why not use associate type like `DekuRead::Ctx`? Because a generic trait allows us to write specific implementation (like default value).

### Drawback

- The implementation of `Vec` is confusing, what `Vec::read((1, (2, 3, 4)))` (or ``Vec::read((VecCount(1), (2, 3, 4)))`) means?
- More complexity
- Difficult to write derive macro(e.g. Not sure how would we parse "a: u8" to `(a): (u8)`)

### Todo

A lot of work to do

- [x] Modify trait declaration
- [x] Modify derive macro
- [x] Add `ctx` attribute
- [x] Add useful types(like `Endian`)
- [ ] Rewrite document
- [ ] Add tests


Patch:
diff --git a/Cargo.toml b/Cargo.toml
index a138903..9719cd3 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -32,6 +32,7 @@ hex-literal = "0.3"
 rstest = "0.6"
 criterion = "0.3"
 alloc_counter = "0.0.4"
+trybuild = "1.0"
 
 [[bench]]
 name = "deku"
diff --git a/deku-derive/src/lib.rs b/deku-derive/src/lib.rs
index 879e134..083a93d 100644
--- a/deku-derive/src/lib.rs
+++ b/deku-derive/src/lib.rs
@@ -1,45 +1,310 @@
-use darling::{ast, FromDeriveInput, FromField, FromMeta, FromVariant};
+use darling::{ast, FromDeriveInput, FromField, FromVariant};
 use proc_macro2::TokenStream;
 use quote::quote;
 mod macros;
 use crate::macros::{deku_read::emit_deku_read, deku_write::emit_deku_write};
+use syn::punctuated::Punctuated;
+use syn::spanned::Spanned;
 
-#[derive(Debug, Clone, Copy, PartialEq, FromMeta)]
-#[darling(default)]
-/// Endian types for `endian` attribute
-pub(crate) enum EndianNess {
-    Little,
-    Big,
+#[derive(Debug)]
+struct DekuData {
+    vis: syn::Visibility,
+    ident: syn::Ident,
+    generics: syn::Generics,
+    data: ast::Data<VariantData, FieldData>,
+
+    /// Endianness for all fields
+    endian: Option<syn::LitStr>,
+
+    ctx: Option<syn::punctuated::Punctuated<syn::FnArg, syn::token::Comma>>,
+
+    id_type: Option<syn::Ident>,
+
+    id_bits: Option<usize>,
 }
 
-impl Default for EndianNess {
-    fn default() -> Self {
-        #[cfg(target_endian = "little")]
-        let ret = EndianNess::Little;
+impl DekuData {
+    /// Map `DekuReceiver` to `DekuData`. It will check if attributes valid. Return a compile error
+    /// if failed.
+    fn from_receiver(receiver: DekuReceiver) -> Result<Self, TokenStream> {
+        // Validate
+        DekuData::validate(&receiver)
+            .map_err(|(span, msg)| syn::Error::new(span, msg).to_compile_error())?;
+
+        let data = match receiver.data {
+            ast::Data::Struct(fields) => ast::Data::Struct(ast::Fields {
+                style: fields.style,
+                fields: fields
+                    .fields
+                    .into_iter()
+                    .map(FieldData::from_receiver)
+                    .collect::<Result<Vec<_>, _>>()?,
+            }),
+            ast::Data::Enum(variants) => ast::Data::Enum(
+                variants
+                    .into_iter()
+                    .map(VariantData::from_receiver)
+                    .collect::<Result<Vec<_>, _>>()?,
+            ),
+        };
+
+        let ctx = receiver
+            .ctx
+            .map(|s| s.parse_with(syn::punctuated::Punctuated::parse_terminated))
+            .transpose()
+            .map_err(|e| e.to_compile_error())?;
+
+        let id_bits = receiver.id_bytes.map(|b| b * 8).or(receiver.id_bits);
+
+        Ok(Self {
+            vis: receiver.vis,
+            ident: receiver.ident,
+            generics: receiver.generics,
+            data,
+            endian: receiver.endian,
+            ctx,
+            id_type: receiver.id_type,
+            id_bits,
+        })
+    }
+
+    fn validate(receiver: &DekuReceiver) -> Result<(), (proc_macro2::Span, &str)> {
+        /*
+        FIXME: All `span` call have the same issue with `receiver.bits.span()` except `receiver.ident`
+            see `FieldData::validate`.
+         */
+
+        match receiver.data {
+            ast::Data::Struct(_) => {
+                // Validate id_* attributes are being used on an enum
+                if receiver.id_type.is_some() {
+                    Err((receiver.id_type.span(), "`id_type` only supported on enum"))
+                } else if receiver.id_bytes.is_some() {
+                    Err((
+                        receiver.id_bytes.span(),
+                        "`id_bytes` only supported on enum",
+                    ))
+                } else if receiver.id_bits.is_some() {
+                    Err((receiver.id_bits.span(), "`id_bits` only supported on enum"))
+                } else {
+                    Ok(())
+                }
+            }
+            ast::Data::Enum(_) => {
+                // Validate `id_type` is specified.
+                if receiver.id_type.is_none() {
+                    return Err((receiver.ident.span(), "`id_type` must be specified on enum"));
+                }
+
+                // Validate either `id_bits` or `id_bytes` is specified
+                if receiver.id_bits.is_some() && receiver.id_bytes.is_some() {
+                    return Err((
+                        receiver.id_bits.span(),
+                        "conflicting: both \"id_bits\" and \"id_bytes\" specified on field",
+                    ));
+                }
+
+                Ok(())
+            }
+        }
+    }
+
+    /// Emit a reader. If any error happened, the result will be a compile error.
+    fn emit_reader(&self) -> TokenStream {
+        match self.emit_reader_checked() {
+            Ok(tks) => tks,
+            Err(e) => e.to_compile_error(),
+        }
+    }
+
+    /// Emit a writer. If any error happened, the result will be a compile error.
+    fn emit_writer(&self) -> TokenStream {
+        match self.emit_writer_checked() {
+            Ok(tks) => tks,
+            Err(e) => e.to_compile_error(),
+        }
+    }
+
+    /// Same as `emit_reader`, but won't auto convert error to compile error.
+    fn emit_reader_checked(&self) -> Result<TokenStream, syn::Error> {
+        emit_deku_read(self)
+    }
+
+    /// Same as `emit_writer`, but won't auto convert error to compile error.
+    fn emit_writer_checked(&self) -> Result<TokenStream, syn::Error> {
+        emit_deku_write(self)
+    }
+}
+
+#[derive(Debug)]
+struct FieldData {
+    ident: Option<syn::Ident>,
+    ty: syn::Type,
+
+    /// Endianness for the field
+    endian: Option<syn::LitStr>,
+
+    /// field bit size
+    bits: Option<usize>,
+
+    /// tokens providing the length of the container
+    count: Option<TokenStream>,
+
+    /// apply a function to the field after it's read
+    map: Option<TokenStream>,
 
-        #[cfg(target_endian = "big")]
-        let rets = EndianNess::Big;
+    /// context passed to the type
+    ctx: Option<Punctuated<syn::Expr, syn::token::Comma>>,
 
-        ret
+    /// map field when updating struct
+    update: Option<TokenStream>,
+
+    /// custom field reader code
+    reader: Option<TokenStream>,
+
+    /// custom field writer code
+    writer: Option<TokenStream>,
+
+    // skip field reading/writing
+    skip: bool,
+
+    // default value code when used with skip
+    default: Option<TokenStream>,
+}
+
+impl FieldData {
+    fn from_receiver(receiver: DekuFieldReceiver) -> Result<Self, TokenStream> {
+        FieldData::validate(&receiver)
+            .map_err(|(span, msg)| syn::Error::new(span, msg).to_compile_error())?;
+
+        let bits = receiver.bytes.map(|b| b * 8).or(receiver.bits);
+
+        // Default `default` if skip is provided without `default`
+        let default = if receiver.skip && receiver.default.is_none() {
+            Some(quote! { Default::default() })
+        } else {
+            receiver.default
+        };
+
+        let ctx = receiver
+            .ctx
+            .map(|s| s.parse_with(Punctuated::parse_terminated))
+            .transpose()
+            .map_err(|e| e.to_compile_error())?;
+
+        Ok(Self {
+            ident: receiver.ident,
+            ty: receiver.ty,
+            endian: receiver.endian,
+            bits,
+            count: receiver.count,
+            map: receiver.map,
+            ctx,
+            update: receiver.update,
+            reader: receiver.reader,
+            writer: receiver.writer,
+            skip: receiver.skip,
+            default,
+        })
+    }
+
+    fn validate(receiver: &DekuFieldReceiver) -> Result<(), (proc_macro2::Span, &str)> {
+        // Validate either `bits` or `bytes` is specified
+        if receiver.bits.is_some() && receiver.bytes.is_some() {
+            /*
+            FIXME: `receiver.bits.span()` will return `call_site`, that's unexpected. It makes
+               compiler given `#[derive(DekuRead)]`
+                                         ^^^^^^^^
+               instead of `#[deku(bits = "", bytes = "")]`
+                                  ^^^^^^^^^^^^^^^^^^^^^
+               A possible reason might be that the `span` was discorded by `darling`(because inner
+               type don't have a `span`).
+               Maybe we should parse it manually.
+            */
+
+            // FIXME: Ideally we need to use `Span::join` to encompass `bits` and `bytes` together.
+            return Err((
+                receiver.bits.span(),
+                "conflicting: both \"bits\" and \"bytes\" specified on field",
+            ));
+        }
+
+        // Validate `skip` is provided with `default`
+        if receiver.default.is_some() && !receiver.skip {
+            // FIXME: Same issue with `receiver.bits.span()` see above.
+            return Err((
+                receiver.default.span(),
+                "`default` attribute must be used with `skip`",
+            ));
+        }
+
+        Ok(())
+    }
+
+    /// Get ident of the field
+    /// `index` is provided in the case of un-named structs
+    /// `prefix` is true in the case of variable declarations, false if original field is desired
+    fn get_ident(&self, index: usize, prefix: bool) -> TokenStream {
+        let field_ident = gen_field_ident(self.ident.as_ref(), index, prefix);
+        quote! { #field_ident }
+    }
+}
+
+#[derive(Debug)]
+struct VariantData {
+    ident: syn::Ident,
+    fields: ast::Fields<FieldData>,
+
+    /// custom variant reader code
+    reader: Option<TokenStream>,
+
+    /// custom variant reader code
+    writer: Option<TokenStream>,
+
+    /// variant `id` value
+    id: Option<String>,
+}
+
+impl VariantData {
+    fn from_receiver(receiver: DekuVariantReceiver) -> Result<Self, TokenStream> {
+        let fields = ast::Fields {
+            style: receiver.fields.style,
+            fields: receiver
+                .fields
+                .fields
+                .into_iter()
+                .map(FieldData::from_receiver)
+                .collect::<Result<Vec<_>, _>>()?,
+        };
+
+        Ok(Self {
+            ident: receiver.ident,
+            fields,
+            reader: receiver.reader,
+            writer: receiver.writer,
+            id: receiver.id,
+        })
     }
 }
 
 /// Receiver for the top-level struct or enum
 #[derive(Debug, FromDeriveInput)]
-#[darling(
-    attributes(deku),
-    supports(struct_any, enum_any),
-    map = "DekuReceiver::init"
-)]
+#[darling(attributes(deku), supports(struct_any, enum_any))]
 struct DekuReceiver {
     vis: syn::Visibility,
     ident: syn::Ident,
     generics: syn::Generics,
     data: ast::Data<DekuVariantReceiver, DekuFieldReceiver>,
 
-    /// Endian default for the fields
+    /// Endianness for all fields
+    #[darling(default)]
+    endian: Option<syn::LitStr>,
+
+    /// struct/enum level ctx like "a: u8, b: u8"
+    /// The type of it should be `syn::punctuated::Punctuated<syn::FnArg, syn::token::Comma>`. `darling`
+    /// can't parse it from `Meta`, so we will parse it latter.
     #[darling(default)]
-    endian: EndianNess,
+    ctx: Option<syn::LitStr>,
 
     /// enum only: type of the enum `id`
     #[darling(default)]
@@ -54,47 +319,6 @@ struct DekuReceiver {
     id_bytes: Option<usize>,
 }
 
-impl DekuReceiver {
-    /// Initialize and validate the DekuReceiver
-    fn init(self) -> Self {
-        // Validate id_* attributes are being used on an enum
-        if (self.id_type.is_some() || self.id_bits.is_some() || self.id_bytes.is_some())
-            && !self.data.is_enum()
-        {
-            panic!("`id_*` attributes only supported on enum")
-        }
-
-        // Validate that `id_type` is set with a size
-        if (self.id_bits.is_some() || self.id_bytes.is_some()) && self.id_type.is_none() {
-            panic!("`id_type` must be specified with `id_bits` or `id_bytes`");
-        }
-
-        // Validate either `id_bits` or `id_bytes` is specified
-        if self.id_bits.is_some() && self.id_bytes.is_some() {
-            panic!("conflicting: both \"id_bits\" and \"id_bytes\" specified on field");
-        }
-
-        // Calculate bit size from both attributes
-        let id_bits = self.id_bits.or_else(|| self.id_bytes.map(|v| v * 8));
-        let id_bytes = None;
-
-        // Return updated receiver
-        Self {
-            id_bits,
-            id_bytes,
-            ..self
-        }
-    }
-
-    fn emit_reader(&self) -> Result<TokenStream, darling::Error> {
-        emit_deku_read(self)
-    }
-
-    fn emit_writer(&self) -> Result<TokenStream, darling::Error> {
-        emit_deku_write(self)
-    }
-}
-
 /// Parse a TokenStream from an Option<String>
 fn option_as_tokenstream(input: Option<String>) -> Option<TokenStream> {
     input.map(|v| {
@@ -123,14 +347,14 @@ fn gen_field_ident<T: ToString>(ident: Option<T>, index: usize, prefix: bool) ->
 
 /// Receiver for the field-level attributes inside a struct/enum variant
 #[derive(Debug, FromField)]
-#[darling(attributes(deku), map = "DekuFieldReceiver::init")]
+#[darling(attributes(deku))]
 struct DekuFieldReceiver {
     ident: Option<syn::Ident>,
     ty: syn::Type,
 
     /// Endianness for the field
     #[darling(default)]
-    endian: Option<EndianNess>,
+    endian: Option<syn::LitStr>,
 
     /// field bit size
     #[darling(default)]
@@ -148,6 +372,10 @@ struct DekuFieldReceiver {
     #[darling(default, map = "option_as_tokenstream")]
     map: Option<TokenStream>,
 
+    /// context like `"a, c + 1"`. We will parse it to `Punctuated<Expr, Comma>` latter.
+    #[darling(default)]
+    ctx: Option<syn::LitStr>,
+
     /// map field when updating struct
     #[darling(default, map = "option_as_tokenstream")]
     update: Option<TokenStream>,
@@ -169,51 +397,9 @@ struct DekuFieldReceiver {
     default: Option<TokenStream>,
 }
 
-impl DekuFieldReceiver {
-    /// Initialize and validate the DekuFieldReceiver
-    fn init(self) -> Self {
-        // Validate either `bits` or `bytes` is specified
-        if self.bits.is_some() && self.bytes.is_some() {
-            panic!("conflicting: both \"bits\" and \"bytes\" specified on field");
-        }
-
-        // Calculate bit size from both attributes
-        let bits = self.bits.or_else(|| self.bytes.map(|v| v * 8));
-        let bytes = None;
-
-        // Validate `skip` is provided with `default`
-        if self.default.is_some() && !self.skip {
-            panic!("`default` attribute must be used with `skip`");
-        }
-
-        // Default `default` if skip is provided without `default`
-        let default = if self.skip && self.default.is_none() {
-            Some(quote! { Default::default() })
-        } else {
-            self.default
-        };
-
-        // Return updated receiver
-        Self {
-            bits,
-            bytes,
-            default,
-            ..self
-        }
-    }
-
-    /// Get ident of the field
-    /// `index` is provided in the case of un-named structs
-    /// `prefix` is true in the case of variable declarations, false if original field is desired
-    fn get_ident(&self, index: usize, prefix: bool) -> TokenStream {
-        let field_ident = gen_field_ident(self.ident.as_ref(), index, prefix);
-        quote! { #field_ident }
-    }
-}
-
 /// Receiver for the variant-level attributes inside a enum
 #[derive(Debug, FromVariant)]
-#[darling(attributes(deku), map = "DekuVariantReceiver::init")]
+#[darling(attributes(deku))]
 struct DekuVariantReceiver {
     ident: syn::Ident,
     fields: ast::Fields<DekuFieldReceiver>,
@@ -231,32 +417,44 @@ struct DekuVariantReceiver {
     id: Option<String>,
 }
 
-impl DekuVariantReceiver {
-    fn init(self) -> Self {
-        self
-    }
-}
-
 #[proc_macro_derive(DekuRead, attributes(deku))]
 pub fn proc_deku_read(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
-    match DekuReceiver::from_derive_input(&syn::parse(input).unwrap()) {
-        Ok(v) => v
-            .emit_reader()
-            .unwrap_or_else(|err| err.write_errors())
-            .into(),
-        Err(e) => e.write_errors().into(),
-    }
+    let input = match syn::parse(input) {
+        Ok(input) => input,
+        Err(err) => return err.to_compile_error().into(),
+    };
+
+    let receiver = match DekuReceiver::from_derive_input(&input) {
+        Ok(receiver) => receiver,
+        Err(err) => return err.write_errors().into(),
+    };
+
+    let data = match DekuData::from_receiver(receiver) {
+        Ok(data) => data,
+        Err(err) => return err.into(),
+    };
+
+    data.emit_reader().into()
 }
 
 #[proc_macro_derive(DekuWrite, attributes(deku))]
 pub fn proc_deku_write(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
-    match DekuReceiver::from_derive_input(&syn::parse(input).unwrap()) {
-        Ok(v) => v
-            .emit_writer()
-            .unwrap_or_else(|err| err.write_errors())
-            .into(),
-        Err(e) => e.write_errors().into(),
-    }
+    let input = match syn::parse(input) {
+        Ok(input) => input,
+        Err(err) => return err.to_compile_error().into(),
+    };
+
+    let receiver = match DekuReceiver::from_derive_input(&input) {
+        Ok(receiver) => receiver,
+        Err(err) => return err.write_errors().into(),
+    };
+
+    let data = match DekuData::from_receiver(receiver) {
+        Ok(data) => data,
+        Err(err) => return err.into(),
+    };
+
+    data.emit_writer().into()
 }
 
 #[cfg(test)]
@@ -284,18 +482,6 @@ mod tests {
             field_e: u32,
         }"#),
 
-        // Invalid Struct
-        #[should_panic(expected = "UnknownField(ErrorUnknownField { name: \"sbits\", did_you_mean: Some(\"bits\") })")]
-        case::invalid_field(r#"struct Test(#[deku(sbits=4)] u8);"#),
-        #[should_panic(expected = "DuplicateField(\"bits\")")]
-        case::invalid_field_duplicate(r#"struct Test(#[deku(bits=4, bits=5)] u8);"#),
-        #[should_panic(expected = "conflicting: both \"bits\" and \"bytes\" specified on field")]
-        case::invalid_field_bitsnbytes(r#"struct Test(#[deku(bits=4, bytes=1)] u8);"#),
-        #[should_panic(expected = "`id_*` attributes only supported on enum")]
-        case::invalid_struct_id_type(r#"#[deku(id_type="u8")] struct Test(u8);"#),
-        #[should_panic(expected = "`default` attribute must be used with `skip`")]
-        case::invalid_default(r#"struct Test(u8, #[deku(default ="asd")] Vec<u8>);"#),
-
         // Valid Enum
         case::enum_empty(r#"#[deku(id_type = "u8")] enum Test {}"#),
         case::enum_all(r#"
@@ -309,16 +495,6 @@ mod tests {
             C { field_n: u8 },
         }"#),
 
-        // Invalid Enum
-        #[should_panic(expected = "expected `id_type` on enum")]
-        case::invalid_expected_id_type(r#"enum Test { #[deku(id="1")] A }"#),
-        #[should_panic(expected = "`id_type` must be specified with `id_bits` or `id_bytes`")]
-        case::invalid_expected_id_type(r#"#[deku(id_bits="5")] enum Test { #[deku(id="1")] A }"#),
-        #[should_panic(expected = "`id_type` must be specified with `id_bits` or `id_bytes`")]
-        case::invalid_expected_id_type(r#"#[deku(id_bytes="5")] enum Test { #[deku(id="1")] A }"#),
-        #[should_panic(expected = "conflicting: both \"id_bits\" and \"id_bytes\" specified on field")]
-        case::invalid_conflict(r#"#[deku(id_type="u8", id_bytes="5", id_bits="5")] enum Test { #[deku(id="1")] A }"#),
-
         // TODO: these tests should error/warn eventually?
         // error: trying to store 9 bits in 8 bit type
         case::invalid_storage(r#"struct Test(#[deku(bits=9)] u8);"#),
@@ -329,8 +505,9 @@ mod tests {
         let parsed = parse_str(input).unwrap();
 
         let receiver = DekuReceiver::from_derive_input(&parsed).unwrap();
-        let res_reader = receiver.emit_reader();
-        let res_writer = receiver.emit_writer();
+        let data = DekuData::from_receiver(receiver).unwrap();
+        let res_reader = data.emit_reader_checked();
+        let res_writer = data.emit_writer_checked();
 
         res_reader.unwrap();
         res_writer.unwrap();
diff --git a/deku-derive/src/macros/deku_read.rs b/deku-derive/src/macros/deku_read.rs
index 595284c..1c13159 100644
--- a/deku-derive/src/macros/deku_read.rs
+++ b/deku-derive/src/macros/deku_read.rs
@@ -1,21 +1,20 @@
-use crate::{DekuFieldReceiver, DekuReceiver, EndianNess};
+use crate::macros::{
+    gen_ctx_types_and_arg, gen_field_args, gen_id_args, gen_internal_field_ident,
+    gen_internal_field_idents,
+};
+use crate::{DekuData, FieldData};
 use darling::ast::{Data, Fields};
 use proc_macro2::TokenStream;
 use quote::quote;
 
-pub(crate) fn emit_deku_read(input: &DekuReceiver) -> Result<TokenStream, darling::Error> {
-    assert!(
-        input.id_bytes.is_none(),
-        "dev error: `id_bytes` should be None, use `id_bits` to get size"
-    );
-
+pub(crate) fn emit_deku_read(input: &DekuData) -> Result<TokenStream, syn::Error> {
     match &input.data {
         Data::Enum(_) => emit_enum(input),
         Data::Struct(_) => emit_struct(input),
     }
 }
 
-fn emit_struct(input: &DekuReceiver) -> Result<TokenStream, darling::Error> {
+fn emit_struct(input: &DekuData) -> Result<TokenStream, syn::Error> {
     let mut tokens = TokenStream::new();
 
     let (imp, ty, wher) = input.generics.split_for_impl();
@@ -23,11 +22,8 @@ fn emit_struct(input: &DekuReceiver) -> Result<TokenStream, darling::Error> {
     let ident = &input.ident;
     let ident = quote! { #ident #ty };
 
-    let fields = &input
-        .data
-        .as_ref()
-        .take_struct()
-        .expect("expected `struct` type");
+    // checked in `emit_deku_read`
+    let fields = &input.data.as_ref().take_struct().unwrap();
 
     // check if the first field has an ident, if not, it's a unnamed struct
     let is_named_struct = fields
@@ -38,9 +34,13 @@ fn emit_struct(input: &DekuReceiver) -> Result<TokenStream, darling::Error> {
 
     let (field_idents, field_reads) = emit_field_reads(input, &fields)?;
 
-    let initialize_struct = super::gen_struct_init(is_named_struct, field_idents);
+    let internal_fields = gen_internal_field_idents(is_named_struct, field_idents);
 
-    tokens.extend(quote! {
+    let initialize_struct = super::gen_struct_init(is_named_struct, internal_fields);
+
+    // Only implement `DekuContainerRead` for types don't need any context.
+    if input.ctx.is_none() {
+        tokens.extend(quote! {
         impl #imp core::convert::TryFrom<&[u8]> for #ident #wher {
             type Error = DekuError;
 
@@ -69,10 +69,14 @@ fn emit_struct(input: &DekuReceiver) -> Result<TokenStream, darling::Error> {
 
                 Ok(((&input_bits[read_idx..].as_slice(), pad), value))
             }
-        }
+        }})
+    }
 
-        impl #imp DekuRead for #ident #wher {
-            fn read(input: &BitSlice<Msb0, u8>, _input_is_le: bool, _bit_size: Option<usize>, _count: Option<usize>) -> Result<(&BitSlice<Msb0, u8>, Self), DekuError> {
+    let (ctx_types, ctx_arg) = gen_ctx_types_and_arg(input.ctx.as_ref())?;
+
+    tokens.extend(quote! {
+        impl #imp DekuRead<#ctx_types> for #ident #wher {
+            fn read<'a>(input: &'a BitSlice<Msb0, u8>, #ctx_arg) -> Result<(&'a BitSlice<Msb0, u8>, Self), DekuError> {
                 use core::convert::TryFrom;
                 let mut rest = input;
 
@@ -88,27 +92,29 @@ fn emit_struct(input: &DekuReceiver) -> Result<TokenStream, darling::Error> {
     Ok(tokens)
 }
 
-fn emit_enum(input: &DekuReceiver) -> Result<TokenStream, darling::Error> {
+fn emit_enum(input: &DekuData) -> Result<TokenStream, syn::Error> {
     let mut tokens = TokenStream::new();
 
     let (imp, ty, wher) = input.generics.split_for_impl();
 
-    let variants = input
-        .data
-        .as_ref()
-        .take_enum()
-        .expect("expected `enum` type");
+    // checked in `emit_deku_read`
+    let variants = input.data.as_ref().take_enum().unwrap();
 
     let ident = &input.ident;
     let ident = quote! { #ident #ty };
 
-    let id_type = input.id_type.as_ref().expect("expected `id_type` on enum");
-    let id_is_le_bytes = input.endian == EndianNess::Little;
-    let id_bit_size = super::option_as_literal_token(input.id_bits);
+    // checked in `DekuData::validate`
+    let id_type = input.id_type.as_ref().unwrap();
+
+    let id_args = gen_id_args(input.endian.as_ref(), input.id_bits)?;
 
     let mut variant_matches = vec![];
     let mut has_default_match = false;
 
+    /*
+    FIXME: The loop body is too big. The usage of enumerate looks strange. And `mut Vec` can be
+        replaced with `map`.
+     */
     for (_i, variant) in variants.into_iter().enumerate() {
         // check if the first field has an ident, if not, it's a unnamed struct
         let variant_is_named = variant
@@ -134,8 +140,9 @@ fn emit_enum(input: &DekuReceiver) -> Result<TokenStream, darling::Error> {
         } else {
             let (field_idents, field_reads) = emit_field_reads(input, &variant.fields.as_ref())?;
 
+            let internal_fields = gen_internal_field_idents(variant_is_named, field_idents);
             let initialize_enum =
-                super::gen_enum_init(variant_is_named, variant_ident, field_idents);
+                super::gen_enum_init(variant_is_named, variant_ident, internal_fields);
 
             // if we're consuming an id, set the rest to new_rest before reading the variant
             let new_rest = if variant.id.is_some() {
@@ -172,14 +179,17 @@ fn emit_enum(input: &DekuReceiver) -> Result<TokenStream, darling::Error> {
     }
 
     let variant_read = quote! {
-        let (new_rest, variant_id) = #id_type::read(rest, #id_is_le_bytes, #id_bit_size, None)?;
+        let (new_rest, variant_id) = #id_type::read(rest, (#id_args))?;
 
         let value = match variant_id {
             #(#variant_matches),*
         };
     };
 
-    tokens.extend(quote! {
+    // Only implement `DekuContainerRead` for types don't need any context.
+    if input.ctx.is_none() {
+        tokens.extend(quote! {
+
         impl #imp core::convert::TryFrom<&[u8]> for #ident #wher {
             type Error = DekuError;
 
@@ -208,9 +218,14 @@ fn emit_enum(input: &DekuReceiver) -> Result<TokenStream, darling::Error> {
                 Ok(((&input_bits[read_idx..].as_slice(), pad), value))
             }
         }
+        })
+    }
+
+    let (ctx_types, ctx_arg) = gen_ctx_types_and_arg(input.ctx.as_ref())?;
 
-        impl #imp DekuRead for #ident #wher {
-            fn read(input: &BitSlice<Msb0, u8>, _input_is_le: bool, _bit_size: Option<usize>, _count: Option<usize>) -> Result<(&BitSlice<Msb0, u8>, Self), DekuError> {
+    tokens.extend(quote! {
+        impl #imp DekuRead<#ctx_types> for #ident #wher {
+            fn read<'a>(input: &'a BitSlice<Msb0, u8>, #ctx_arg) -> Result<(&'a BitSlice<Msb0, u8>, Self), DekuError> {
                 use core::convert::TryFrom;
                 let mut rest = input;
 
@@ -226,9 +241,9 @@ fn emit_enum(input: &DekuReceiver) -> Result<TokenStream, darling::Error> {
 }
 
 fn emit_field_reads(
-    input: &DekuReceiver,
-    fields: &Fields<&DekuFieldReceiver>,
-) -> Result<(Vec<TokenStream>, Vec<TokenStream>), darling::Error> {
+    input: &DekuData,
+    fields: &Fields<&FieldData>,
+) -> Result<(Vec<TokenStream>, Vec<TokenStream>), syn::Error> {
     let mut field_reads = vec![];
     let mut field_idents = vec![];
 
@@ -242,19 +257,16 @@ fn emit_field_reads(
 }
 
 fn emit_field_read(
-    input: &DekuReceiver,
+    input: &DekuData,
     i: usize,
-    f: &DekuFieldReceiver,
-) -> Result<(TokenStream, TokenStream), darling::Error> {
-    assert!(
-        f.bytes.is_none(),
-        "dev error: `bytes` should be None, use `bits` to get size"
-    );
-
+    f: &FieldData,
+) -> Result<(TokenStream, TokenStream), syn::Error> {
     let field_type = &f.ty;
-    let is_le_bytes = f.endian.unwrap_or(input.endian) == EndianNess::Little;
-    let field_bits = super::option_as_literal_token(f.bits);
+
+    let field_endian = f.endian.as_ref().or_else(|| input.endian.as_ref());
+
     let field_reader = &f.reader;
+
     let field_map = f
         .map
         .as_ref()
@@ -262,22 +274,42 @@ fn emit_field_read(
             quote! { (#v) }
         })
         .or_else(|| Some(quote! { Result::<_, DekuError>::Ok }));
-    let field_count = &f.count;
+
     let field_ident = f.get_ident(i, true);
 
+    let internal_field_ident = gen_internal_field_ident(field_ident.clone());
+
     let field_read_func = if field_reader.is_some() {
         quote! { #field_reader }
-    } else if field_count.is_some() {
-        quote! { DekuRead::read(rest, input_is_le, field_bits, Some(usize::try_from(#field_count)?)) }
     } else {
-        quote! { DekuRead::read(rest, input_is_le, field_bits, None) }
+        let read_args = gen_field_args(field_endian, f.bits, f.ctx.as_ref())?;
+
+        // Count is special, we need to generate `(count, (other, ..))` for it.
+        if let Some(field_count) = &f.count {
+            // The count has same problem, when it isn't a copy type, the field will be moved.
+            // e.g. struct FooBar {
+            //   a: Baz // a type implement `Into<usize>` but not `Copy`.
+            //   #[deku(count = "a") <-- Oops, use of moved value: `a`
+            //   b: Vec<_>
+            // }
+            quote! {
+                {
+                    use core::borrow::Borrow;
+                    DekuRead::read(rest, (deku::ctx::Count(usize::try_from(*((#field_count).borrow()))?), (#read_args)))
+                }
+            }
+        } else {
+            quote! {DekuRead::read(rest, (#read_args))}
+        }
     };
 
+    // We must pass a ref to context so that it won't be moved when use.
+    // e.g.
+    // let a = read(rest);
+    // let b = read(rest, a); <-- Oops! a have been moved, then we can't use it for constructing.
+    // let c = read(rest, &mut b); <-- `b` will be changed.
     let field_read = quote! {
-        let #field_ident = {
-            let field_bits: Option<usize> = #field_bits;
-            let input_is_le = #is_le_bytes;
-
+        let #internal_field_ident = {
             let (new_rest, value) = #field_read_func?;
             let value: #field_type = #field_map(value)?;
 
@@ -285,15 +317,18 @@ fn emit_field_read(
 
             value
         };
+        let #field_ident = &#internal_field_ident;
     };
 
     if f.skip {
+        // TODO: Replace `expect` with `syn::Error` or check it in `FieldData::validate`.
         let default_tok = f.default.as_ref().expect("expected `default` attribute");
 
         let default_read = quote! {
-            let #field_ident = {
+            let #internal_field_ident = {
                 #default_tok
             };
+            let #field_ident = &#internal_field_ident;
         };
         return Ok((field_ident, default_read));
     }
diff --git a/deku-derive/src/macros/deku_write.rs b/deku-derive/src/macros/deku_write.rs
index 01dddea..23b1d0c 100644
--- a/deku-derive/src/macros/deku_write.rs
+++ b/deku-derive/src/macros/deku_write.rs
@@ -1,21 +1,17 @@
-use crate::{DekuFieldReceiver, DekuReceiver, EndianNess};
+use crate::macros::{gen_ctx_types_and_arg, gen_field_args, gen_id_args, gen_struct_destruction};
+use crate::{DekuData, FieldData};
 use darling::ast::{Data, Fields};
 use proc_macro2::TokenStream;
 use quote::quote;
 
-pub(crate) fn emit_deku_write(input: &DekuReceiver) -> Result<TokenStream, darling::Error> {
-    assert!(
-        input.id_bytes.is_none(),
-        "dev error: `id_bytes` should be None, use `id_bits` to get size"
-    );
-
+pub(crate) fn emit_deku_write(input: &DekuData) -> Result<TokenStream, syn::Error> {
     match &input.data {
         Data::Enum(_) => emit_enum(input),
         Data::Struct(_) => emit_struct(input),
     }
 }
 
-fn emit_struct(input: &DekuReceiver) -> Result<TokenStream, darling::Error> {
+fn emit_struct(input: &DekuData) -> Result<TokenStream, syn::Error> {
     let mut tokens = TokenStream::new();
 
     let (imp, ty, wher) = input.generics.split_for_impl();
@@ -23,32 +19,69 @@ fn emit_struct(input: &DekuReceiver) -> Result<TokenStream, darling::Error> {
     let ident = &input.ident;
     let ident = quote! { #ident #ty };
 
-    let fields = input
-        .data
-        .as_ref()
-        .take_struct()
-        .expect("expected `struct` type");
+    // We checked in `emit_deku_write`.
+    let fields = input.data.as_ref().take_struct().unwrap();
 
-    let field_writes = emit_field_writes(input, &fields, Some(quote! { self. }))?;
+    let field_writes = emit_field_writes(input, &fields, None)?;
     let field_updates = emit_field_updates(&fields, Some(quote! { self. }))?;
 
-    tokens.extend(quote! {
-        impl #imp core::convert::TryFrom<#ident> for BitVec<Msb0, u8> #wher {
-            type Error = DekuError;
+    /*
+    NOTE:
+    Because the requirement of former fields accessing, we need to deconstruct first.
+    e.g.: match *self { Self{ ref field_0, ref field_1 } => { /* do something */} }
+     */
+    let named = fields.style.is_struct();
+
+    let field_idents = fields
+        .iter()
+        .enumerate()
+        .map(|(i, f)| f.get_ident(i, true))
+        .collect::<Vec<_>>();
+
+    let destructured = gen_struct_destruction(named, &input.ident, &field_idents);
+
+    // Only implement `DekuContainerWrite` for types don't need any context.
+    if input.ctx.is_none() {
+        tokens.extend(quote! {
+            impl #imp core::convert::TryFrom<#ident> for BitVec<Msb0, u8> #wher {
+                type Error = DekuError;
+
+                fn try_from(input: #ident) -> Result<Self, Self::Error> {
+                    input.to_bitvec()
+                }
+            }
 
-            fn try_from(input: #ident) -> Result<Self, Self::Error> {
-                input.to_bitvec()
+            impl #imp core::convert::TryFrom<#ident> for Vec<u8> #wher {
+                type Error = DekuError;
+
+                fn try_from(input: #ident) -> Result<Self, Self::Error> {
+                    input.to_bytes()
+                }
             }
-        }
 
-        impl #imp core::convert::TryFrom<#ident> for Vec<u8> #wher {
-            type Error = DekuError;
+            impl #imp DekuContainerWrite for #ident #wher {
+                fn to_bytes(&self) -> Result<Vec<u8>, DekuError> {
+                    let mut acc: BitVec<Msb0, u8> = self.to_bitvec()?;
+                    Ok(acc.into_vec())
+                }
+
+                fn to_bitvec(&self) -> Result<BitVec<Msb0, u8>, DekuError> {
+                    match *self {
+                        #destructured => {
+                            let mut acc: BitVec<Msb0, u8> = BitVec::new();
+                            #(#field_writes)*
 
-            fn try_from(input: #ident) -> Result<Self, Self::Error> {
-                input.to_bytes()
+                            Ok(acc)
+                        }
+                    }
+                }
             }
-        }
+        })
+    }
 
+    let (ctx_types, ctx_arg) = gen_ctx_types_and_arg(input.ctx.as_ref())?;
+
+    tokens.extend(quote! {
         impl #imp DekuUpdate for #ident #wher {
             fn update(&mut self) -> Result<(), DekuError> {
                 use core::convert::TryInto;
@@ -58,24 +91,16 @@ fn emit_struct(input: &DekuReceiver) -> Result<TokenStream, darling::Error> {
             }
         }
 
-        impl #imp DekuContainerWrite for #ident #wher {
-            fn to_bytes(&self) -> Result<Vec<u8>, DekuError> {
-                let mut acc: BitVec<Msb0, u8> = self.to_bitvec()?;
-                Ok(acc.into_vec())
-            }
+        impl #imp DekuWrite<#ctx_types> for #ident #wher {
+            fn write(&self, #ctx_arg) -> Result<BitVec<Msb0, u8>, DekuError> {
+                match *self {
+                    #destructured => {
+                        let mut acc: BitVec<Msb0, u8> = BitVec::new();
+                        #(#field_writes)*
 
-            fn to_bitvec(&self) -> Result<BitVec<Msb0, u8>, DekuError> {
-                let mut acc: BitVec<Msb0, u8> = BitVec::new();
-
-                #(#field_writes)*
-
-                Ok(acc)
-            }
-        }
-
-        impl #imp DekuWrite for #ident #wher {
-            fn write(&self, output_is_le: bool, bit_size: Option<usize>) -> Result<BitVec<Msb0, u8>, DekuError> {
-                self.to_bitvec()
+                        Ok(acc)
+                    }
+                }
             }
         }
     });
@@ -84,27 +109,29 @@ fn emit_struct(input: &DekuReceiver) -> Result<TokenStream, darling::Error> {
     Ok(tokens)
 }
 
-fn emit_enum(input: &DekuReceiver) -> Result<TokenStream, darling::Error> {
+fn emit_enum(input: &DekuData) -> Result<TokenStream, syn::Error> {
     let mut tokens = TokenStream::new();
 
     let (imp, ty, wher) = input.generics.split_for_impl();
 
-    let variants = input
-        .data
-        .as_ref()
-        .take_enum()
-        .expect("expected `enum` type");
+    // checked in emit_deku_write
+    let variants = input.data.as_ref().take_enum().unwrap();
 
     let ident = &input.ident;
     let ident = quote! { #ident #ty };
 
-    let id_type = input.id_type.as_ref().expect("expected `id_type` on enum");
-    let id_is_le_bytes = input.endian == EndianNess::Little;
-    let id_bit_size = super::option_as_literal_token(input.id_bits);
+    // checked in `DekuData::validate`
+    let id_type = input.id_type.as_ref().unwrap();
+
+    let id_args = gen_id_args(input.endian.as_ref(), input.id_bits)?;
 
     let mut variant_writes = vec![];
     let mut variant_updates = vec![];
 
+    /*
+    FIXME: The loop body is too big. The usage of `enumerate` looks strange. And two `mut Vec` can be
+        replaced with `map` and `split`.
+     */
     for (_i, variant) in variants.into_iter().enumerate() {
         // check if the first field has an ident, if not, it's a unnamed struct
         let variant_is_named = variant
@@ -115,7 +142,7 @@ fn emit_enum(input: &DekuReceiver) -> Result<TokenStream, darling::Error> {
             .is_some();
 
         let variant_ident = &variant.ident;
-        let variant_writer = &variant.reader;
+        let variant_writer = &variant.writer;
 
         let field_idents = variant
             .fields
@@ -130,7 +157,7 @@ fn emit_enum(input: &DekuReceiver) -> Result<TokenStream, darling::Error> {
 
             quote! {
                     let mut variant_id: #id_type = #variant_id;
-                    let bits = variant_id.write(#id_is_le_bytes, #id_bit_size)?;
+                    let bits = variant_id.write((#id_args))?;
                     acc.extend(bits);
             }
         } else {
@@ -167,22 +194,48 @@ fn emit_enum(input: &DekuReceiver) -> Result<TokenStream, darling::Error> {
         });
     }
 
-    tokens.extend(quote! {
-        impl #imp core::convert::TryFrom<#ident> for BitVec<Msb0, u8> #wher {
-            type Error = DekuError;
+    // Only implement `DekuContainerWrite` for types don't need any context.
+    if input.ctx.is_none() {
+        tokens.extend(quote! {
+            impl #imp core::convert::TryFrom<#ident> for BitVec<Msb0, u8> #wher {
+                type Error = DekuError;
 
-            fn try_from(input: #ident) -> Result<Self, Self::Error> {
-                input.to_bitvec()
+                fn try_from(input: #ident) -> Result<Self, Self::Error> {
+                    input.to_bitvec()
+                }
             }
-        }
 
-        impl #imp core::convert::TryFrom<#ident> for Vec<u8> #wher {
-            type Error = DekuError;
+            impl #imp core::convert::TryFrom<#ident> for Vec<u8> #wher {
+                type Error = DekuError;
 
-            fn try_from(input: #ident) -> Result<Self, Self::Error> {
-                input.to_bytes()
+                fn try_from(input: #ident) -> Result<Self, Self::Error> {
+                    input.to_bytes()
+                }
             }
-        }
+
+            impl #imp DekuContainerWrite for #ident #wher {
+
+                fn to_bytes(&self) -> Result<Vec<u8>, DekuError> {
+                    let mut acc: BitVec<Msb0, u8> = self.to_bitvec()?;
+                    Ok(acc.into_vec())
+                }
+
+                fn to_bitvec(&self) -> Result<BitVec<Msb0, u8>, DekuError> {
+                    let mut acc: BitVec<Msb0, u8> = BitVec::new();
+
+                    match self {
+                        #(#variant_writes),*
+                    }
+
+                    Ok(acc)
+                }
+            }
+        })
+    }
+
+    let (ctx_types, ctx_arg) = gen_ctx_types_and_arg(input.ctx.as_ref())?;
+
+    tokens.extend(quote! {
 
         impl #imp DekuUpdate for #ident #wher {
             fn update(&mut self) -> Result<(), DekuError> {
@@ -196,14 +249,8 @@ fn emit_enum(input: &DekuReceiver) -> Result<TokenStream, darling::Error> {
             }
         }
 
-        impl #imp DekuContainerWrite for #ident #wher {
-
-            fn to_bytes(&self) -> Result<Vec<u8>, DekuError> {
-                let mut acc: BitVec<Msb0, u8> = self.to_bitvec()?;
-                Ok(acc.into_vec())
-            }
-
-            fn to_bitvec(&self) -> Result<BitVec<Msb0, u8>, DekuError> {
+        impl #imp DekuWrite<#ctx_types> for #ident #wher {
+            fn write(&self, #ctx_arg) -> Result<BitVec<Msb0, u8>, DekuError> {
                 let mut acc: BitVec<Msb0, u8> = BitVec::new();
 
                 match self {
@@ -213,12 +260,6 @@ fn emit_enum(input: &DekuReceiver) -> Result<TokenStream, darling::Error> {
                 Ok(acc)
             }
         }
-
-        impl #imp DekuWrite for #ident #wher {
-            fn write(&self, output_is_le: bool, bit_size: Option<usize>) -> Result<BitVec<Msb0, u8>, DekuError> {
-                self.to_bitvec()
-            }
-        }
     });
 
     // println!("{}", tokens.to_string());
@@ -226,10 +267,10 @@ fn emit_enum(input: &DekuReceiver) -> Result<TokenStream, darling::Error> {
 }
 
 fn emit_field_writes(
-    input: &DekuReceiver,
-    fields: &Fields<&DekuFieldReceiver>,
+    input: &DekuData,
+    fields: &Fields<&FieldData>,
     object_prefix: Option<TokenStream>,
-) -> Result<Vec<TokenStream>, darling::Error> {
+) -> Result<Vec<TokenStream>, syn::Error> {
     let mut field_writes = vec![];
 
     for (i, f) in fields.iter().enumerate() {
@@ -241,9 +282,9 @@ fn emit_field_writes(
 }
 
 fn emit_field_updates(
-    fields: &Fields<&DekuFieldReceiver>,
+    fields: &Fields<&FieldData>,
     object_prefix: Option<TokenStream>,
-) -> Result<Vec<TokenStream>, darling::Error> {
+) -> Result<Vec<TokenStream>, syn::Error> {
     let mut field_updates = vec![];
 
     for (i, f) in fields.iter().enumerate() {
@@ -256,13 +297,9 @@ fn emit_field_updates(
 
 fn emit_field_update(
     i: usize,
-    f: &DekuFieldReceiver,
+    f: &FieldData,
     object_prefix: &Option<TokenStream>,
-) -> Result<Vec<TokenStream>, darling::Error> {
-    assert!(
-        f.bytes.is_none(),
-        "dev error: `bytes` should be None, use `bits` to get size"
-    );
+) -> Result<Vec<TokenStream>, syn::Error> {
     let mut field_updates = vec![];
 
     let field_ident = f.get_ident(i, object_prefix.is_none());
@@ -282,35 +319,30 @@ fn emit_field_update(
 }
 
 fn emit_field_write(
-    input: &DekuReceiver,
+    input: &DekuData,
     i: usize,
-    f: &DekuFieldReceiver,
+    f: &FieldData,
     object_prefix: &Option<TokenStream>,
-) -> Result<TokenStream, darling::Error> {
-    assert!(
-        f.bytes.is_none(),
-        "dev error: `bytes` should be None, use `bits` to get size"
-    );
-
+) -> Result<TokenStream, syn::Error> {
     // skip writing this field
     if f.skip {
         return Ok(quote! {});
     }
 
-    let is_le_bytes = f.endian.unwrap_or(input.endian) == EndianNess::Little;
-    let field_bits = super::option_as_literal_token(f.bits);
+    let field_endian = f.endian.as_ref().or_else(|| input.endian.as_ref());
+
     let field_writer = &f.writer;
     let field_ident = f.get_ident(i, object_prefix.is_none());
 
     let field_write_func = if field_writer.is_some() {
         quote! { #field_writer }
     } else {
-        quote! { #object_prefix #field_ident.write(output_is_le, field_bits) }
+        let write_args = gen_field_args(field_endian, f.bits, f.ctx.as_ref())?;
+
+        quote! { #object_prefix #field_ident.write((#write_args)) }
     };
 
     let field_write = quote! {
-        let output_is_le = #is_le_bytes;
-        let field_bits: Option<usize> = #field_bits;
 
         let bits = #field_write_func ?;
         acc.extend(bits);
diff --git a/deku-derive/src/macros/mod.rs b/deku-derive/src/macros/mod.rs
index 89c5c9a..51fc68b 100644
--- a/deku-derive/src/macros/mod.rs
+++ b/deku-derive/src/macros/mod.rs
@@ -1,17 +1,11 @@
 use proc_macro2::TokenStream;
 use quote::{quote, ToTokens};
+use syn::punctuated::Punctuated;
+use syn::spanned::Spanned;
 
 pub(crate) mod deku_read;
 pub(crate) mod deku_write;
 
-/// Generate a literal token stream for an Option<T>
-fn option_as_literal_token<T: ToTokens>(input: Option<T>) -> TokenStream {
-    match input {
-        Some(b) => quote! {Some(#b)},
-        None => quote! {None},
-    }
-}
-
 /// Generate enum initialization TokenStream
 /// Cases:
 /// - No fields: `MyEnum`
@@ -65,3 +59,158 @@ fn gen_struct_init<I: ToTokens>(is_named: bool, field_idents: Vec<I>) -> TokenSt
         }
     }
 }
+
+/// Generate struct destruction
+///
+/// - Named: `#ident { ref fields }`
+/// - Unnamed: `#ident ( ref fields )`
+fn gen_struct_destruction<I: ToTokens, F: ToTokens>(
+    named: bool,
+    ident: I,
+    field_idents: &[F],
+) -> TokenStream {
+    if named {
+        quote! {
+            #ident {
+                #(ref #field_idents),*
+            }
+        }
+    } else {
+        quote! {
+            #ident (
+                #(ref #field_idents),*
+            )
+        }
+    }
+}
+
+/// Convert a field ident to internal ident:
+/// `a` -> `__deku_a`
+fn gen_internal_field_ident(ident: TokenStream) -> TokenStream {
+    // We can't concat to token, so I use string.
+    // See https://github.com/rust-lang/rust/issues/29599
+    let span = ident.span();
+    let s = ident.to_string();
+    let mut name = "__deku_".to_owned();
+    name.push_str(&s);
+
+    syn::Ident::new(&name, span).to_token_stream()
+}
+
+/// Map all field indents to internal idents
+///
+/// - Named: `{ a: __deku_a }`
+/// - Unnamed: `( __deku_a )`
+fn gen_internal_field_idents(named: bool, idents: Vec<TokenStream>) -> Vec<TokenStream> {
+    // -> `{ a: __a }` or `(__a)`
+    if named {
+        idents
+            .into_iter()
+            .map(|i| (i.clone(), gen_internal_field_ident(i)))
+            .map(|(i, h)| quote! {#i: #h})
+            .collect()
+    } else {
+        idents.into_iter().map(gen_internal_field_ident).collect()
+    }
+}
+
+fn split_ctx_to_pats_and_types(
+    ctx: &Punctuated<syn::FnArg, syn::token::Comma>,
+) -> syn::Result<Vec<(&syn::Pat, &syn::Type)>> {
+    // `()` or `(u8, u32)`
+    ctx.iter()
+        .map(|arg| {
+            match arg {
+                syn::FnArg::Typed(pat_type) => Ok((pat_type.pat.as_ref(), pat_type.ty.as_ref())),
+                // a self is unacceptable
+                syn::FnArg::Receiver(r) => Err(syn::Error::new(r.span(), "Unacceptable context")),
+            }
+        })
+        .collect::<Result<Vec<_>, _>>()
+}
+
+/// Generate ctx types and argument
+///
+/// - Empty: arg: `(): ()`, type: `()`
+/// - One: arg: `a: usize`, type: `usize`
+/// - Other: arg: `(a, b, ...): (u8, u8, ...)`, type: `(u8, u8, ...)`
+fn gen_ctx_types_and_arg(
+    ctx: Option<&Punctuated<syn::FnArg, syn::token::Comma>>,
+) -> syn::Result<(TokenStream, TokenStream)> {
+    if let Some(ctx) = ctx {
+        let pats_types = split_ctx_to_pats_and_types(ctx)?;
+
+        if pats_types.len() == 1 {
+            // remove paren for single item
+            let (pat, ty) = pats_types[0];
+            Ok((quote! {#ty}, quote! {#pat:#ty}))
+        } else {
+            let pats = pats_types.iter().map(|(pat, _)| pat);
+            let types = pats_types.iter().map(|(_, ty)| ty);
+
+            // avoid move
+            let types2 = types.clone();
+
+            // "a: u8, b: usize" -> (u8, usize)
+            let ctx_types = quote! {(#(#types2),*)};
+            // "a: u8, b: usize" -> (a, b): (u8, usize)
+            let ctx_arg = quote! {(#(#pats),*): (#(#types),*)};
+
+            Ok((ctx_types, ctx_arg))
+        }
+    } else {
+        Ok((quote! {()}, quote! {_: ()}))
+    }
+}
+
+/// Generate argument for `id`:
+/// `#deku(endian = "big", id_bits = "1")` -> `Endian::Big, BitSize(1)`
+fn gen_id_args(endian: Option<&syn::LitStr>, bits: Option<usize>) -> syn::Result<TokenStream> {
+    let endian = endian.map(gen_endian_from_str).transpose()?;
+    let bits = bits.map(|n| quote! {deku::ctx::BitSize(#n)});
+
+    // FIXME: Should be `into_iter` here, see https://github.com/rust-lang/rust/issues/66145.
+    let id_args = [endian.as_ref(), bits.as_ref()]
+        .iter()
+        .filter_map(|i| *i)
+        .collect::<Vec<_>>();
+
+    match &id_args[..] {
+        [arg] => Ok(quote! {#arg}),
+        args => Ok(quote! {#(#args),*}),
+    }
+}
+
+/// Generate argument for fields:
+///
+/// `#deku(endian = "big", id_bits = "1", ctx = "a")` -> `Endian::Big, BitSize(1), a`
+fn gen_field_args(
+    endian: Option<&syn::LitStr>,
+    bits: Option<usize>,
+    ctx: Option<&Punctuated<syn::Expr, syn::token::Comma>>,
+) -> syn::Result<TokenStream> {
+    let endian = endian.map(gen_endian_from_str).transpose()?;
+    let bits = bits.map(|n| quote! {deku::ctx::BitSize(#n)});
+    let ctx = ctx.map(|c| quote! {#c});
+
+    // FIXME: Should be `into_iter` here, see https://github.com/rust-lang/rust/issues/66145.
+    let field_args = [endian.as_ref(), bits.as_ref(), ctx.as_ref()]
+        .iter()
+        .filter_map(|i| *i)
+        .collect::<Vec<_>>();
+
+    // Because `impl DekuRead<(T1, T2)>` but `impl DekuRead<T1>`(not tuple)
+    match &field_args[..] {
+        [arg] => Ok(quote! {#arg}),
+        args => Ok(quote! {#(#args),*}),
+    }
+}
+
+/// Generate endian tokens from string: `big` -> `Endian::Big`.
+fn gen_endian_from_str(s: &syn::LitStr) -> syn::Result<TokenStream> {
+    match s.value().as_str() {
+        "little" => Ok(quote! {deku::ctx::Endian::Little}),
+        "big" => Ok(quote! {deku::ctx::Endian::Big}),
+        _ => Err(syn::Error::new(s.span(), "Unknown endian name")),
+    }
+}
diff --git a/examples/custom_reader_and_writer.rs b/examples/custom_reader_and_writer.rs
index e4a6dbd..4e2063d 100644
--- a/examples/custom_reader_and_writer.rs
+++ b/examples/custom_reader_and_writer.rs
@@ -1,11 +1,11 @@
 use deku::prelude::*;
+use deku::ctx::BitSize;
 use std::convert::TryInto;
 
 fn bit_flipper_read(
     field_a: u8,
     rest: &BitSlice<Msb0, u8>,
-    input_is_le: bool,
-    bit_size: Option<usize>,
+    bit_size: BitSize,
 ) -> Result<(&BitSlice<Msb0, u8>, u8), DekuError> {
     // Access to previously read fields
     println!("field_a = 0x{:X}", field_a);
@@ -17,7 +17,7 @@ fn bit_flipper_read(
     println!("bit_size: {:?}", bit_size);
 
     // read field_b, calling original func
-    let (rest, value) = u8::read(rest, input_is_le, bit_size, None)?;
+    let (rest, value) = u8::read(rest, bit_size)?;
 
     // flip the bits on value if field_a is 0x01
     let value = if field_a == 0x01 { !value } else { value };
@@ -28,8 +28,7 @@ fn bit_flipper_read(
 fn bit_flipper_write(
     field_a: u8,
     field_b: u8,
-    output_is_le: bool,
-    bit_size: Option<usize>,
+    bit_size: BitSize,
 ) -> Result<BitVec<Msb0, u8>, DekuError> {
     // Access to previously written fields
     println!("field_a = 0x{:X}", field_a);
@@ -43,7 +42,7 @@ fn bit_flipper_write(
     // flip the bits on value if field_a is 0x01
     let value = if field_a == 0x01 { !field_b } else { field_b };
 
-    value.write(output_is_le, bit_size)
+    value.write(bit_size)
 }
 
 #[derive(Debug, PartialEq, DekuRead, DekuWrite)]
@@ -51,9 +50,8 @@ struct DekuTest {
     field_a: u8,
 
     #[deku(
-        bits = "8",
-        reader = "bit_flipper_read(field_a, rest, input_is_le, field_bits)",
-        writer = "bit_flipper_write(self.field_a, self.field_b, output_is_le, field_bits)"
+        reader = "bit_flipper_read(*field_a, rest, BitSize(8))",
+        writer = "bit_flipper_write(*field_a, *field_b, BitSize(8))"
     )]
     field_b: u8,
 }
diff --git a/src/attributes.rs b/src/attributes.rs
index c45d5d6..2074831 100644
--- a/src/attributes.rs
+++ b/src/attributes.rs
@@ -19,6 +19,8 @@ A documentation-only module for #[deku] attributes
 | [id_type](#id_type) | top-level (enum only) | Set the type of the variant `id`
 | [id_bits](#id_bits) | top-level (enum only) | Set the bit-size of the variant `id`
 | [id_bytes](#id_bytes) | top-level (enum only) | Set the byte-size of the variant `id`
+| [ctx](#top_level_ctx) | top-level | The context a struct/enum needed for context-sensitive parsing.
+| [ctx](#field_level_ctx) | field | Set to pass a context required by this field.
 
 # endian
 
@@ -240,7 +242,7 @@ Example:
 #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
 pub struct DekuTest {
     pub field_a: u8,
-    #[deku(skip, default = "Some(field_a)")]
+    #[deku(skip, default = "Some(*field_a)")]
     pub field_b: Option<u8>,
     pub field_c: u8,
 }
@@ -301,8 +303,8 @@ Example:
 # #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
 struct DekuTest {
     #[deku(
-        reader = "DekuTest::read(rest, input_is_le, field_bits)",
-        writer = "DekuTest::write(&self.field_a, output_is_le, field_bits)"
+        reader = "DekuTest::read(rest)",
+        writer = "DekuTest::write(&self.field_a)"
     )]
     field_a: String,
 }
@@ -311,17 +313,15 @@ impl DekuTest {
     // Read and convert to String
     fn read(
         rest: &BitSlice<Msb0, u8>,
-        input_is_le: bool,
-        bit_size: Option<usize>,
     ) -> Result<(&BitSlice<Msb0, u8>, String), DekuError> {
-        let (rest, value) = u8::read(rest, input_is_le, bit_size, None)?;
+        let (rest, value) = u8::read(rest, ())?;
         Ok((rest, value.to_string()))
     }
 
     // Parse from String to u8 and write
-    fn write(field_a: &str, output_is_le: bool, bit_size: Option<usize>) -> Result<BitVec<Msb0, u8>, DekuError> {
+    fn write(field_a: &str) -> Result<BitVec<Msb0, u8>, DekuError> {
         let value = field_a.parse::<u8>().unwrap();
-        value.write(output_is_le, bit_size)
+        value.write(())
     }
 }
 
@@ -460,4 +460,90 @@ assert_eq!(
 let value: Vec<u8> = value.try_into().unwrap();
 assert_eq!(data, value);
 ```
+
+# top_level_ctx
+
+The context a struct/enum needed for context-sensitive parsing.
+
+**Value**: The value of a ctx attribute must be a literal string which can be parsed to function
+argument list:
+```ignore
+#[deku(ctx = "a: Type, b: Type")] // <-- good
+struct A{}
+#[deku(ctx = "self")] // <-- bad
+struct B{}
+```
+
+Example:
+```
+# use deku::prelude::*;
+# use bitvec::slice::AsBits;
+#[derive(DekuRead, DekuWrite)]
+#[deku(ctx = "_a: u8")]
+struct Test {}
+
+let data: Vec<u8> = vec![0xEF, 0xBE, 0xFF];
+
+let (_, value) = Test::read(data.bits(), 10).unwrap();
+// let _ = Test::read(data.bits(), ""); <-- compile error.
+let _ = value.write(10);
+// let _ = Test::write(true); <-- compile error.
+```
+
+# field_level_ctx
+
+Set to pass a context required by this field.
+
+**Value**: This attribute accept a literal string which can be parsed to expression list:
+```ignore
+struct Test {
+    p: u8,
+    #[deku(ctx = r#"p, 12, "str", true"#)] // <-- good
+    a: u8,
+    #[deku(ctx = ",")] // <-- bad
+    b: u8,
+}
+```
+
+**Visibility**: List of what you can access:
+1. All former fields which have been parsed(you can only access const reference, no move, no mut).
+2. Every context defined through `top-level-ctx` attribute.
+
+Example
+```
+# use deku::prelude::*;
+#[derive(DekuRead, DekuWrite)]
+#[deku(ctx = "a: u8")]
+struct Subtype {
+    #[deku(map = "|b: u8| -> Result<_, DekuError> { Ok(b + a) }")]
+    b: u8
+}
+
+#[derive(DekuRead, DekuWrite)]
+struct Test {
+    a: u8,
+    #[deku(ctx = "*a")] // `a` is a reference
+    sub: Subtype
+}
+
+let data: Vec<u8> = vec![0x01, 0x02];
+
+let (rest, value) = Test::from_bytes((&data[..], 0)).unwrap();
+assert_eq!(value.a, 0x01);
+assert_eq!(value.sub.b, 0x01 + 0x02)
+```
+
+In addition, currently `endian`, `bytes` and `bits` are a sugar of `ctx`, codes below are equivalent:
+```ignore
+struct Type1 {
+    #[deku(endian = "big", bits = "1")]
+    field: u8,
+}
+
+struct Type2 {
+    #[deku(ctx = "Endian::Big, BitSize(1)")]
+    field: u8,
+}
+```
+
 */
diff --git a/src/ctx.rs b/src/ctx.rs
new file mode 100644
index 0000000..6cbd3d4
--- /dev/null
+++ b/src/ctx.rs
@@ -0,0 +1,166 @@
+//! This module provided types for context representation could be used in context-sensitive parsing.
+//! See [ctx attribute](../attributes/index.html#ctx) for more information.
+
+use core::ops::{Deref, DerefMut};
+use core::str::FromStr;
+
+/// An endian.
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub enum Endian {
+    Little,
+    Big,
+}
+
+/// An error returned when parsing a `Endian` using [`from_str`] fails
+///
+/// [`from_str`]: enum.Endian.html#method.from_str
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct ParseEndianError {}
+
+impl Endian {
+    /// As same as [`Endian::default`], but const.
+    ///
+    /// [`Endian::default`]: #method.default
+    pub const fn new() -> Self {
+        #[cfg(target_endian = "little")]
+        let endian = Endian::Little;
+
+        #[cfg(target_endian = "big")]
+        let endian = Endian::Big;
+
+        endian
+    }
+
+    /// Is it a little endian.
+    pub fn is_le(&self) -> bool {
+        self == &Endian::Little
+    }
+
+    /// Is it a big endian.
+    pub fn is_be(&self) -> bool {
+        self == &Endian::Big
+    }
+}
+
+impl Default for Endian {
+    /// Return the endianness of the target's CPU.
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl FromStr for Endian {
+    type Err = ParseEndianError;
+
+    /// Parse a `Endian` from a string.
+    /// # Examples
+    /// ```rust
+    /// use std::str::FromStr;
+    /// use deku::ctx::Endian;
+    /// assert_eq!(FromStr::from_str("little"), Ok(Endian::Little));
+    /// assert_eq!(FromStr::from_str("big"), Ok(Endian::Big));
+    /// assert!(<Endian as FromStr>::from_str("not an endian").is_err());
+    /// ```
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        match s {
+            "little" => Ok(Endian::Little),
+            "big" => Ok(Endian::Big),
+            _ => Err(ParseEndianError {}),
+        }
+    }
+}
+
+/// The count of a container's elements.
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
+pub struct Count(pub usize);
+
+impl Into<usize> for Count {
+    fn into(self) -> usize {
+        self.0
+    }
+}
+
+impl From<usize> for Count {
+    fn from(n: usize) -> Self {
+        Self(n)
+    }
+}
+
+impl Deref for Count {
+    type Target = usize;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl DerefMut for Count {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+
+/// The number of a data's bits.
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
+pub struct BitSize(pub usize);
+
+impl BitSize {
+    /// Convert the size in bytes to the bit size.
+    /// # Examples
+    /// ```rust
+    /// # use std::mem::size_of;
+    /// # use deku::ctx::BitSize;
+    ///
+    /// assert_eq!(BitSize::with_byte_size(1), BitSize(8));
+    /// ```
+    ///
+    /// # Panic
+    /// Panic if `byte_size * 8` is greater than `usize::MAX`.
+    pub fn with_byte_size(byte_size: usize) -> Self {
+        Self(byte_size.checked_mul(8).expect("bit size overflow"))
+    }
+
+    /// Returns the bit size of a type.
+    /// # Examples
+    /// ```rust
+    /// # use deku::ctx::BitSize;
+    ///
+    /// assert_eq!(BitSize::of::<i32>(), BitSize(4 * 8));
+    /// ```
+    /// # Panics
+    /// Panic if the bit size of given type is greater than `usize::MAX`
+    pub fn of<T>() -> Self {
+        Self::with_byte_size(core::mem::size_of::<T>())
+    }
+
+    /// Returns the bit size of the pointed-to value.
+    pub fn of_val<T: ?Sized>(val: &T) -> Self {
+        Self::with_byte_size(core::mem::size_of_val(val))
+    }
+}
+
+impl Into<usize> for BitSize {
+    fn into(self) -> usize {
+        self.0
+    }
+}
+
+impl From<usize> for BitSize {
+    fn from(n: usize) -> Self {
+        Self(n)
+    }
+}
+
+impl Deref for BitSize {
+    type Target = usize;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl DerefMut for BitSize {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 982793c..fe08b8d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -171,58 +171,50 @@ use alloc::{format, vec::Vec};
 #[cfg(feature = "std")]
 use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
 
+use crate::ctx::{BitSize, Count, Endian};
 use bitvec::prelude::*;
 use core::convert::TryInto;
 pub use deku_derive::*;
+
 pub mod attributes;
+pub mod ctx;
 pub mod error;
 pub mod prelude;
 mod slice_impls;
+
 use crate::error::DekuError;
 
 /// "Reader" trait: read bits and construct type
-pub trait DekuRead {
+pub trait DekuRead<Ctx = ()> {
     /// Read bits and construct type
     /// * **input** - Input as bits
-    /// * **input_is_le** - `true` if input is to be interpreted as little endian,
-    /// false otherwise (controlled via `endian` deku attribute)
-    /// * **bit_size** - `Some` if `bits` or `bytes` deku attributes provided,
-    /// `None` otherwise
-    /// * **count** - Number of elements to read for container, Some if `count` attribute
-    /// is provided, else None
-    fn read(
-        input: &BitSlice<Msb0, u8>,
-        input_is_le: bool,
-        bit_size: Option<usize>,
-        count: Option<usize>,
-    ) -> Result<(&BitSlice<Msb0, u8>, Self), DekuError>
+    /// * **ctx** - A context required by context-sensitive reading. A unit type `()` means not context
+    /// needed.
+    fn read(input: &BitSlice<Msb0, u8>, ctx: Ctx) -> Result<(&BitSlice<Msb0, u8>, Self), DekuError>
     where
         Self: Sized;
 }
 
-/// "Reader" trait: implemented on DekuRead struct and enum containers
-pub trait DekuContainerRead: DekuRead {
+/// "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<()> {
+    // TODO: Explain that's the second arg `usize` means.
     fn from_bytes(input: (&[u8], usize)) -> Result<((&[u8], usize), Self), DekuError>
     where
         Self: Sized;
 }
 
 /// "Writer" trait: write from type to bits
-pub trait DekuWrite {
+pub trait DekuWrite<Ctx = ()> {
     /// Write type to bits
-    /// * **output_is_le** - `true` if output is to be interpreted as little endian,
-    /// false otherwise (controlled via `endian` deku attribute)
-    /// * **bit_size** - `Some` if `bits` or `bytes` deku attributes provided,
-    /// `None` otherwise
-    fn write(
-        &self,
-        output_is_le: bool,
-        bit_size: Option<usize>,
-    ) -> Result<BitVec<Msb0, u8>, DekuError>;
+    /// * **ctx** - A context required by context-sensitive reading. A unit type `()` means not context
+    /// needed.
+    fn write(&self, ctx: Ctx) -> Result<BitVec<Msb0, u8>, DekuError>;
 }
 
-/// "Writer" trait: implemented on DekuWrite struct and enum containers
-pub trait DekuContainerWrite: DekuWrite {
+/// "Writer" trait: implemented on DekuWrite struct and enum containers. A `container` is a type which
+/// doesn't need any context information.
+pub trait DekuContainerWrite: DekuWrite<()> {
     /// Write struct/enum to Vec<u8>
     fn to_bytes(&self) -> Result<Vec<u8>, DekuError>;
 
@@ -238,27 +230,23 @@ pub trait DekuUpdate {
 
 macro_rules! ImplDekuTraits {
     ($typ:ty) => {
-        impl DekuRead for $typ {
+        impl DekuRead<(Endian, BitSize)> for $typ {
             fn read(
                 input: &BitSlice<Msb0, u8>,
-                input_is_le: bool,
-                bit_size: Option<usize>,
-                count: Option<usize>,
+                (endian, bit_size): (Endian, BitSize),
             ) -> Result<(&BitSlice<Msb0, u8>, Self), DekuError> {
-                assert!(count.is_none(), "Dev error: `count` should always be None");
+                let max_type_bits: usize = BitSize::of::<$typ>().into();
+                let bit_size: usize = bit_size.into();
 
-                let max_type_bits: usize = core::mem::size_of::<$typ>() * 8;
+                let input_is_le = endian.is_le();
+
+                if bit_size > max_type_bits {
+                    return Err(DekuError::Parse(format!(
+                        "too much data: container of {} cannot hold {}",
+                        max_type_bits, bit_size
+                    )));
+                }
 
-                let bit_size = match bit_size {
-                    None => max_type_bits,
-                    Some(s) if s > max_type_bits => {
-                        return Err(DekuError::Parse(format!(
-                            "too much data: container of {} cannot hold {}",
-                            max_type_bits, s
-                        )))
-                    }
-                    Some(s) => s,
-                };
                 if input.len() < bit_size {
                     return Err(DekuError::Parse(format!(
                         "not enough data: expected {} got {}",
@@ -335,87 +323,155 @@ macro_rules! ImplDekuTraits {
             }
         }
 
-        impl DekuWrite for $typ {
+        // Only have `endian`, set `bit_size` to `BitSize::of::<Type>()`
+        impl DekuRead<Endian> for $typ {
+            fn read(
+                input: &BitSlice<Msb0, u8>,
+                endian: Endian,
+            ) -> Result<(&BitSlice<Msb0, u8>, Self), DekuError> {
+                let max_type_bits = BitSize::of::<$typ>();
+
+                <$typ>::read(input, (endian, max_type_bits))
+            }
+        }
+
+        // Only have `bit_size`, set `endian` to `Endian::default`.
+        impl DekuRead<BitSize> for $typ {
+            fn read(
+                input: &BitSlice<Msb0, u8>,
+                bit_size: BitSize,
+            ) -> Result<(&BitSlice<Msb0, u8>, Self), DekuError> {
+                let endian = Endian::default();
+
+                <$typ>::read(input, (endian, bit_size))
+            }
+        }
+
+        impl DekuRead for $typ {
+            fn read(
+                input: &BitSlice<Msb0, u8>,
+                _: (),
+            ) -> Result<(&BitSlice<Msb0, u8>, Self), DekuError> {
+                <$typ>::read(input, Endian::default())
+            }
+        }
+
+        impl DekuWrite<(Endian, BitSize)> for $typ {
             fn write(
                 &self,
-                output_is_le: bool,
-                bit_size: Option<usize>,
+                (endian, bit_size): (Endian, BitSize),
             ) -> Result<BitVec<Msb0, u8>, DekuError> {
+                let output_is_le = endian.is_le();
                 let input = if output_is_le {
                     self.to_le_bytes()
                 } else {
                     self.to_be_bytes()
                 };
 
+                let bit_size: usize = bit_size.into();
+
                 let input_bits: BitVec<Msb0, u8> = input.to_vec().into();
 
                 let res_bits: BitVec<Msb0, u8> = {
-                    if let Some(bit_size) = bit_size {
-                        if bit_size > input_bits.len() {
-                            return Err(DekuError::InvalidParam(format!(
-                                "bit size {} is larger then input {}",
-                                bit_size,
-                                input_bits.len()
-                            )));
-                        }
+                    if bit_size > input_bits.len() {
+                        return Err(DekuError::InvalidParam(format!(
+                            "bit size {} is larger then input {}",
+                            bit_size,
+                            input_bits.len()
+                        )));
+                    }
 
-                        if output_is_le {
-                            // Example read 10 bits u32 [0xAB, 0b11_000000]
-                            // => [10101011, 00000011, 00000000, 00000000]
-                            let mut res_bits = BitVec::<Msb0, u8>::with_capacity(bit_size);
-                            let mut remaining_bits = bit_size;
-                            for chunk in input_bits.chunks(8) {
-                                if chunk.len() > remaining_bits {
-                                    let bits = &chunk[chunk.len() - remaining_bits..];
-                                    for b in bits {
-                                        res_bits.push(*b);
-                                    }
-                                    // https://github.com/myrrlyn/bitvec/issues/62
-                                    // res_bits.extend_from_slice(chunk[chunk.len() - remaining_bits..]);
-                                    break;
-                                } else {
-                                    for b in chunk {
-                                        res_bits.push(*b);
-                                    }
-                                    // https://github.com/myrrlyn/bitvec/issues/62
-                                    // res_bits.extend_from_slice(chunk)
+                    if output_is_le {
+                        // Example read 10 bits u32 [0xAB, 0b11_000000]
+                        // => [10101011, 00000011, 00000000, 00000000]
+                        let mut res_bits = BitVec::<Msb0, u8>::with_capacity(bit_size);
+                        let mut remaining_bits = bit_size;
+                        for chunk in input_bits.chunks(8) {
+                            if chunk.len() > remaining_bits {
+                                let bits = &chunk[chunk.len() - remaining_bits..];
+                                for b in bits {
+                                    res_bits.push(*b);
+                                }
+                                // https://github.com/myrrlyn/bitvec/issues/62
+                                // res_bits.extend_from_slice(chunk[chunk.len() - remaining_bits..]);
+                                break;
+                            } else {
+                                for b in chunk {
+                                    res_bits.push(*b);
                                 }
-                                remaining_bits -= chunk.len();
+                                // https://github.com/myrrlyn/bitvec/issues/62
+                                // res_bits.extend_from_slice(chunk)
                             }
-
-                            res_bits
-                        } else {
-                            // Example read 10 bits u32 [0xAB, 0b11_000000]
-                            // => [00000000, 00000000, 00000010, 10101111]
-                            input_bits[input_bits.len() - bit_size..].into()
+                            remaining_bits -= chunk.len();
                         }
+
+                        res_bits
                     } else {
-                        input_bits
+                        // Example read 10 bits u32 [0xAB, 0b11_000000]
+                        // => [00000000, 00000000, 00000010, 10101111]
+                        input_bits[input_bits.len() - bit_size..].into()
                     }
                 };
 
                 Ok(res_bits)
             }
         }
+
+        // Only have `endian`, return all input
+        impl DekuWrite<Endian> for $typ {
+            fn write(&self, endian: Endian) -> Result<BitVec<Msb0, u8>, DekuError> {
+                let input = if endian.is_le() {
+                    self.to_le_bytes()
+                } else {
+                    self.to_be_bytes()
+                };
+
+                Ok(input.to_vec().into())
+            }
+        }
+
+        // Only have `bit_size`, set `endian` to `Endian::default`.
+        impl DekuWrite<BitSize> for $typ {
+            fn write(&self, bit_size: BitSize) -> Result<BitVec<Msb0, u8>, DekuError> {
+                <$typ>::write(self, (Endian::default(), bit_size))
+            }
+        }
+
+        impl DekuWrite for $typ {
+            fn write(&self, _: ()) -> Result<BitVec<Msb0, u8>, DekuError> {
+                <$typ>::write(self, Endian::default())
+            }
+        }
     };
 }
 
-impl<T: DekuRead> DekuRead for Vec<T> {
+impl<T: DekuRead<Ctx>, Ctx: Copy> DekuRead<(Count, Ctx)> for Vec<T> {
+    /// Read the specified number of `T`s from input.
+    /// * `count` - the number of `T`s you want to read.
+    /// * `inner_ctx` - The context required by `T`. It will be passed to every `T`s in constructing.
+    /// # Examples
+    /// ```rust
+    /// # use deku::ctx::*;
+    /// # use deku::DekuRead;
+    /// # use bitvec::slice::AsBits;
+    /// let input = vec![1u8, 2, 3, 4];
+    /// let (rest, v) = Vec::<u32>::read(input.bits(), (1.into(), Endian::Little)).unwrap();
+    /// assert!(rest.is_empty());
+    /// assert_eq!(v, vec![0x04030201])
+    /// ```
     fn read(
         input: &BitSlice<Msb0, u8>,
-        input_is_le: bool,
-        bit_size: Option<usize>,
-        count: Option<usize>,
+        (count, inner_ctx): (Count, Ctx),
     ) -> Result<(&BitSlice<Msb0, u8>, Self), DekuError>
     where
         Self: Sized,
     {
-        let count = count.expect("Dev error: `count` should always be Some");
+        let count: usize = count.into();
 
         let mut res = Vec::with_capacity(count);
         let mut rest = input;
         for _i in 0..count {
-            let (new_rest, val) = <T>::read(rest, input_is_le, bit_size, None)?;
+            let (new_rest, val) = <T>::read(rest, inner_ctx)?;
             res.push(val);
             rest = new_rest;
         }
@@ -424,16 +480,35 @@ impl<T: DekuRead> DekuRead for Vec<T> {
     }
 }
 
-impl<T: DekuWrite> DekuWrite for Vec<T> {
-    fn write(
-        &self,
-        output_is_le: bool,
-        bit_size: Option<usize>,
-    ) -> Result<BitVec<Msb0, u8>, DekuError> {
+impl<T: DekuRead> DekuRead<Count> for Vec<T> {
+    /// Read the specified number of `T`s from input for types don't require context.
+    fn read(
+        input: &BitSlice<Msb0, u8>,
+        count: Count,
+    ) -> Result<(&BitSlice<Msb0, u8>, Self), DekuError>
+    where
+        Self: Sized,
+    {
+        Vec::read(input, (count, ()))
+    }
+}
+
+impl<T: DekuWrite<Ctx>, Ctx: Copy> DekuWrite<Ctx> for Vec<T> {
+    /// Write all `T`s in a `Vec` to bits.
+    /// * **inner_ctx** - The context required by `T`.
+    /// # Examples
+    /// ```rust
+    /// # use deku::{ctx::Endian, DekuWrite};
+    /// # use bitvec::bitvec;
+    /// let data = vec![1u8];
+    /// let output = data.write(Endian::Big).unwrap();
+    /// assert_eq!(output, bitvec![0, 0, 0, 0, 0, 0, 0, 1])
+    /// ```
+    fn write(&self, inner_ctx: Ctx) -> Result<BitVec<Msb0, u8>, DekuError> {
         let mut acc = BitVec::new();
 
         for v in self {
-            let r = v.write(output_is_le, bit_size)?;
+            let r = v.write(inner_ctx)?;
             acc.extend(r);
         }
 
@@ -457,71 +532,65 @@ ImplDekuTraits!(f32);
 ImplDekuTraits!(f64);
 
 #[cfg(feature = "std")]
-impl DekuRead for Ipv4Addr {
-    fn read(
-        input: &BitSlice<Msb0, u8>,
-        input_is_le: bool,
-        bit_size: Option<usize>,
-        count: Option<usize>,
-    ) -> Result<(&BitSlice<Msb0, u8>, Self), DekuError>
+impl<Ctx> DekuRead<Ctx> for Ipv4Addr
+where
+    u32: DekuRead<Ctx>,
+{
+    fn read(input: &BitSlice<Msb0, u8>, ctx: Ctx) -> Result<(&BitSlice<Msb0, u8>, Self), DekuError>
     where
         Self: Sized,
     {
-        let (rest, ip) = u32::read(input, input_is_le, bit_size, count)?;
+        let (rest, ip) = u32::read(input, ctx)?;
         Ok((rest, ip.into()))
     }
 }
 
 #[cfg(feature = "std")]
-impl DekuWrite for Ipv4Addr {
-    fn write(
-        &self,
-        output_is_le: bool,
-        bit_size: Option<usize>,
-    ) -> Result<BitVec<Msb0, u8>, DekuError> {
+impl<Ctx> DekuWrite<Ctx> for Ipv4Addr
+where
+    u32: DekuWrite<Ctx>,
+{
+    fn write(&self, ctx: Ctx) -> Result<BitVec<Msb0, u8>, DekuError> {
         let ip: u32 = (*self).into();
-        ip.write(output_is_le, bit_size)
+        ip.write(ctx)
     }
 }
 
 #[cfg(feature = "std")]
-impl DekuRead for Ipv6Addr {
-    fn read(
-        input: &BitSlice<Msb0, u8>,
-        input_is_le: bool,
-        bit_size: Option<usize>,
-        count: Option<usize>,
-    ) -> Result<(&BitSlice<Msb0, u8>, Self), DekuError>
+impl<Ctx> DekuRead<Ctx> for Ipv6Addr
+where
+    u128: DekuRead<Ctx>,
+{
+    fn read(input: &BitSlice<Msb0, u8>, ctx: Ctx) -> Result<(&BitSlice<Msb0, u8>, Self), DekuError>
     where
         Self: Sized,
     {
-        let (rest, ip) = u128::read(input, input_is_le, bit_size, count)?;
+        let (rest, ip) = u128::read(input, ctx)?;
         Ok((rest, ip.into()))
     }
 }
 
 #[cfg(feature = "std")]
-impl DekuWrite for Ipv6Addr {
-    fn write(
-        &self,
-        output_is_le: bool,
-        bit_size: Option<usize>,
-    ) -> Result<BitVec<Msb0, u8>, DekuError> {
+impl<Ctx> DekuWrite<Ctx> for Ipv6Addr
+where
+    u128: DekuWrite<Ctx>,
+{
+    fn write(&self, ctx: Ctx) -> Result<BitVec<Msb0, u8>, DekuError> {
         let ip: u128 = (*self).into();
-        ip.write(output_is_le, bit_size)
+        ip.write(ctx)
     }
 }
 
 #[cfg(feature = "std")]
-impl DekuWrite for IpAddr {
-    fn write(
-        &self,
-        output_is_le: bool,
-        bit_size: Option<usize>,
-    ) -> Result<BitVec<Msb0, u8>, DekuError> {
+impl<Ctx> DekuWrite<Ctx> for IpAddr
+where
+    Ipv6Addr: DekuWrite<Ctx>,
+    Ipv4Addr: DekuWrite<Ctx>,
+{
+    fn write(&self, ctx: Ctx) -> Result<BitVec<Msb0, u8>, DekuError> {
         match self {
-            IpAddr::V4(ipv4) => ipv4.write(output_is_le, bit_size),
-            IpAddr::V6(ipv6) => ipv6.write(output_is_le, bit_size),
+            IpAddr::V4(ipv4) => ipv4.write(ctx),
+            IpAddr::V6(ipv6) => ipv6.write(ctx),
         }
     }
 }
@@ -538,16 +607,18 @@ mod tests {
     #[cfg(target_endian = "big")]
     static IS_LE: bool = false;
 
+    static ENDIAN: Endian = Endian::new();
+
     macro_rules! TestPrimitive {
         ($test_name:ident, $typ:ty, $input:expr, $expected:expr) => {
             #[test]
             fn $test_name() {
                 let input = $input;
                 let bit_slice = input.bits::<Msb0>();
-                let (_rest, res_read) = <$typ>::read(bit_slice, IS_LE, None, None).unwrap();
+                let (_rest, res_read) = <$typ>::read(bit_slice, ENDIAN).unwrap();
                 assert_eq!($expected, res_read);
 
-                let res_write = res_read.write(IS_LE, None).unwrap().into_vec();
+                let res_write = res_read.write(ENDIAN).unwrap().into_vec();
                 assert_eq!(input, res_write);
             }
         };
@@ -617,37 +688,42 @@ mod tests {
         -0.006
     );
 
-    #[rstest(input,input_is_le,bit_size,count,expected,expected_rest,
-        case::normal([0xDD, 0xCC, 0xBB, 0xAA].as_ref(), IS_LE, Some(32), None, 0xAABB_CCDD, bits![Msb0, u8;]),
-        case::normal_bits_12_le([0b1001_0110, 0b1110_0000, 0xCC, 0xDD ].as_ref(), IS_LE, Some(12), None, 0b1110_1001_0110, bits![Msb0, u8; 0,0,0,0, 1,1,0,0,1,1,0,0, 1,1,0,1,1,1,0,1]),
-        case::normal_bits_12_be([0b1001_0110, 0b1110_0000, 0xCC, 0xDD ].as_ref(), !IS_LE, Some(12), None, 0b1001_0110_1110, bits![Msb0, u8; 0,0,0,0, 1,1,0,0,1,1,0,0, 1,1,0,1,1,1,0,1]),
-        case::normal_bit_6([0b1001_0110].as_ref(), IS_LE, Some(6), None, 0b1001_01, bits![Msb0, u8; 1,0,]),
-
-        #[should_panic(expected="Parse(\"not enough data: expected 32 got 0\")")]
-        case::not_enough_data([].as_ref(), IS_LE, Some(32), None, 0xFF, bits![Msb0, u8;]),
-        #[should_panic(expected="Parse(\"not enough data: expected 32 got 16\")")]
-        case::not_enough_data([0xAA, 0xBB].as_ref(), IS_LE, Some(32), None, 0xFF, bits![Msb0, u8;]),
-        #[should_panic(expected="Parse(\"too much data: container of 32 cannot hold 64\")")]
-        case::too_much_data([0xAA, 0xBB, 0xCC, 0xDD, 0xAA, 0xBB, 0xCC, 0xDD].as_ref(), IS_LE, Some(64), None, 0xFF, bits![Msb0, u8;]),
-        #[should_panic(expected="Dev error: `count` should always be None")]
-        case::dev_err_count_some([].as_ref(), IS_LE, Some(64), Some(1), 0xFF, bits![Msb0, u8;]),
+    #[rstest(input, input_is_le, bit_size, expected, expected_rest,
+        case::normal([0xDD, 0xCC, 0xBB, 0xAA].as_ref(), IS_LE, Some(32), 0xAABB_CCDD, bits![Msb0, u8;]),
+        case::normal_bits_12_le([0b1001_0110, 0b1110_0000, 0xCC, 0xDD ].as_ref(), IS_LE, Some(12), 0b1110_1001_0110, bits![Msb0, u8; 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1]),
+        case::normal_bits_12_be([0b1001_0110, 0b1110_0000, 0xCC, 0xDD ].as_ref(), !IS_LE, Some(12), 0b1001_0110_1110, bits![Msb0, u8; 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1]),
+        case::normal_bit_6([0b1001_0110].as_ref(), IS_LE, Some(6), 0b1001_01, bits![Msb0, u8; 1, 0,]),
+        #[should_panic(expected = "Parse(\"not enough data: expected 32 got 0\")")]
+        case::not_enough_data([].as_ref(), IS_LE, Some(32), 0xFF, bits![Msb0, u8;]),
+        #[should_panic(expected = "Parse(\"not enough data: expected 32 got 16\")")]
+        case::not_enough_data([0xAA, 0xBB].as_ref(), IS_LE, Some(32), 0xFF, bits![Msb0, u8;]),
+        #[should_panic(expected = "Parse(\"too much data: container of 32 cannot hold 64\")")]
+        case::too_much_data([0xAA, 0xBB, 0xCC, 0xDD, 0xAA, 0xBB, 0xCC, 0xDD].as_ref(), IS_LE, Some(64), 0xFF, bits![Msb0, u8;]),
     )]
     fn test_bit_read(
         input: &[u8],
         input_is_le: bool,
         bit_size: Option<usize>,
-        count: Option<usize>,
         expected: u32,
         expected_rest: &BitSlice<Msb0, u8>,
     ) {
         let bit_slice = input.bits::<Msb0>();
+        let endian = if input_is_le {
+            Endian::Little
+        } else {
+            Endian::Big
+        };
+
+        let (rest, res_read) = match bit_size {
+            Some(bit_size) => u32::read(bit_slice, (endian, BitSize(bit_size))).unwrap(),
+            None => u32::read(bit_slice, endian).unwrap(),
+        };
 
-        let (rest, res_read) = u32::read(bit_slice, input_is_le, bit_size, count).unwrap();
         assert_eq!(expected, res_read);
         assert_eq!(expected_rest, rest);
     }
 
-    #[rstest(input,output_is_le,bit_size,expected,
+    #[rstest(input, output_is_le, bit_size, expected,
         case::normal_le(0xDDCC_BBAA, IS_LE, None, vec![0xAA, 0xBB, 0xCC, 0xDD]),
         case::normal_be(0xDDCC_BBAA, !IS_LE, None, vec![0xDD, 0xCC, 0xBB, 0xAA]),
         case::bit_size_le_smaller(0x03AB, IS_LE, Some(10), vec![0xAB, 0b11_000000]),
@@ -656,11 +732,20 @@ mod tests {
         case::bit_size_le_bigger(0x03AB, IS_LE, Some(100), vec![0xAB, 0b11_000000]),
     )]
     fn test_bit_write(input: u32, output_is_le: bool, bit_size: Option<usize>, expected: Vec<u8>) {
-        let res_write = input.write(output_is_le, bit_size).unwrap().into_vec();
+        let endian = if output_is_le {
+            Endian::Little
+        } else {
+            Endian::Big
+        };
+
+        let res_write = match bit_size {
+            Some(bit_size) => input.write((endian, BitSize(bit_size))).unwrap().into_vec(),
+            None => input.write(endian).unwrap().into_vec(),
+        };
         assert_eq!(expected, res_write);
     }
 
-    #[rstest(input,is_le,bit_size,expected,expected_rest,expected_write,
+    #[rstest(input, is_le, bit_size, expected, expected_rest, expected_write,
         case::normal([0xDD, 0xCC, 0xBB, 0xAA].as_ref(), IS_LE, Some(32), 0xAABB_CCDD, bits![Msb0, u8;], vec![0xDD, 0xCC, 0xBB, 0xAA]),
     )]
     fn test_bit_read_write(
@@ -672,142 +757,163 @@ mod tests {
         expected_write: Vec<u8>,
     ) {
         let bit_slice = input.bits::<Msb0>();
+        let endian = if is_le { Endian::Little } else { Endian::Big };
 
-        let (rest, res_read) = u32::read(bit_slice, is_le, bit_size, None).unwrap();
+        let (rest, res_read) = match bit_size {
+            Some(bit_size) => u32::read(bit_slice, (endian, BitSize(bit_size))).unwrap(),
+            None => u32::read(bit_slice, endian).unwrap(),
+        };
         assert_eq!(expected, res_read);
         assert_eq!(expected_rest, rest);
 
-        let res_write = res_read.write(is_le, bit_size).unwrap().into_vec();
+        let res_write = match bit_size {
+            Some(bit_size) => res_read
+                .write((endian, BitSize(bit_size)))
+                .unwrap()
+                .into_vec(),
+            None => res_read.write(endian).unwrap().into_vec(),
+        };
+
         assert_eq!(expected_write, res_write);
     }
 
     #[rstest(input,input_is_le,bit_size,count,expected,expected_rest,
-        case::count_0([0xAA].as_ref(), IS_LE, Some(8), Some(0), vec![], bits![Msb0, u8; 1,0,1,0,1,0,1,0]),
-        case::count_1([0xAA, 0xBB].as_ref(), IS_LE, Some(8), Some(1), vec![0xAA], bits![Msb0, u8; 1,0,1,1,1,0,1,1]),
-        case::count_2([0xAA, 0xBB, 0xCC].as_ref(), IS_LE, Some(8), Some(2), vec![0xAA, 0xBB], bits![Msb0, u8; 1,1,0,0,1,1,0,0]),
-
-        case::bits_6([0b0110_1001, 0b1110_1001].as_ref(), IS_LE, Some(6), Some(2), vec![0b00_011010, 0b00_011110], bits![Msb0, u8; 1,0,0,1]),
-
-        #[should_panic(expected="Parse(\"too much data: container of 8 cannot hold 9\")")]
-        case::not_enough_data([].as_ref(), IS_LE, Some(9), Some(1), vec![], bits![Msb0, u8;]),
-        #[should_panic(expected="Parse(\"too much data: container of 8 cannot hold 9\")")]
-        case::not_enough_data([0xAA].as_ref(), IS_LE, Some(9), Some(1), vec![], bits![Msb0, u8;]),
-        #[should_panic(expected="Parse(\"not enough data: expected 8 got 0\")")]
-        case::not_enough_data([0xAA].as_ref(), IS_LE, Some(8), Some(2), vec![], bits![Msb0, u8;]),
-        #[should_panic(expected="Parse(\"too much data: container of 8 cannot hold 9\")")]
-        case::too_much_data([0xAA, 0xBB].as_ref(), IS_LE, Some(9), Some(1), vec![], bits![Msb0, u8;]),
-        #[should_panic(expected="Dev error: `count` should always be Some")]
-        case::dev_err_count_none([].as_ref(), IS_LE, Some(0), None, vec![], bits![Msb0, u8;]),
+        case::count_0([0xAA].as_ref(), IS_LE, Some(8), 0, vec![], bits![Msb0, u8; 1, 0, 1, 0, 1, 0, 1, 0]),
+        case::count_1([0xAA, 0xBB].as_ref(), IS_LE, Some(8), 1, vec![0xAA], bits![Msb0, u8; 1, 0, 1, 1, 1, 0, 1, 1]),
+        case::count_2([0xAA, 0xBB, 0xCC].as_ref(), IS_LE, Some(8), 2, vec![0xAA, 0xBB], bits![Msb0, u8; 1, 1, 0, 0, 1, 1, 0, 0]),
+        case::bits_6([0b0110_1001, 0b1110_1001].as_ref(), IS_LE, Some(6), 2, vec![0b00_011010, 0b00_011110], bits![Msb0, u8; 1, 0, 0, 1]),
+        #[should_panic(expected = "Parse(\"too much data: container of 8 cannot hold 9\")")]
+        case::not_enough_data([].as_ref(), IS_LE, Some(9), 1, vec![], bits![Msb0, u8;]),
+        #[should_panic(expected = "Parse(\"too much data: container of 8 cannot hold 9\")")]
+        case::not_enough_data([0xAA].as_ref(), IS_LE, Some(9), 1, vec![], bits![Msb0, u8;]),
+        #[should_panic(expected = "Parse(\"not enough data: expected 8 got 0\")")]
+        case::not_enough_data([0xAA].as_ref(), IS_LE, Some(8), 2, vec![], bits![Msb0, u8;]),
+        #[should_panic(expected = "Parse(\"too much data: container of 8 cannot hold 9\")")]
+        case::too_much_data([0xAA, 0xBB].as_ref(), IS_LE, Some(9), 1, vec![], bits![Msb0, u8;]),
     )]
     fn test_vec_read(
         input: &[u8],
         input_is_le: bool,
         bit_size: Option<usize>,
-        count: Option<usize>,
+        count: usize,
         expected: Vec<u8>,
         expected_rest: &BitSlice<Msb0, u8>,
     ) {
         let bit_slice = input.bits::<Msb0>();
+        let endian = if input_is_le {
+            Endian::Little
+        } else {
+            Endian::Big
+        };
+
+        let (rest, res_read) = match bit_size {
+            Some(bit_size) => {
+                Vec::<u8>::read(bit_slice, (Count(count), (endian, BitSize(bit_size)))).unwrap()
+            }
+            None => Vec::<u8>::read(bit_slice, (Count(count), (endian))).unwrap(),
+        };
 
-        let (rest, res_read) = Vec::<u8>::read(bit_slice, input_is_le, bit_size, count).unwrap();
         assert_eq!(expected, res_read);
         assert_eq!(expected_rest, rest);
     }
 
-    #[rstest(input,output_is_le,bit_size,expected,
-        case::normal(vec![0xAABB, 0xCCDD], IS_LE, None, vec![0xBB, 0xAA, 0xDD, 0xCC]),
+    #[rstest(input, output_is_le, expected,
+        case::normal(vec![0xAABB, 0xCCDD], IS_LE, vec![0xBB, 0xAA, 0xDD, 0xCC]),
     )]
-    fn test_vec_write(
-        input: Vec<u16>,
-        output_is_le: bool,
-        bit_size: Option<usize>,
-        expected: Vec<u8>,
-    ) {
-        let res_write = input.write(output_is_le, bit_size).unwrap().into_vec();
+    fn test_vec_write(input: Vec<u16>, output_is_le: bool, expected: Vec<u8>) {
+        let endian = if output_is_le {
+            Endian::Little
+        } else {
+            Endian::Big
+        };
+
+        let res_write = input.write(endian).unwrap().into_vec();
         assert_eq!(expected, res_write);
     }
 
-    #[rstest(input,is_le,bit_size,count,expected,expected_rest,expected_write,
-        case::normal_le([0xAA, 0xBB, 0xCC, 0xDD].as_ref(), IS_LE, Some(16), Some(2), vec![0xBBAA, 0xDDCC], bits![Msb0, u8;], vec![0xAA, 0xBB, 0xCC, 0xDD]),
-        case::normal_be([0xAA, 0xBB, 0xCC, 0xDD].as_ref(), !IS_LE, Some(16), Some(2), vec![0xAABB, 0xCCDD], bits![Msb0, u8;], vec![0xAA, 0xBB, 0xCC, 0xDD]),
+    #[rstest(input, is_le, bit_size, count, expected, expected_rest, expected_write,
+        case::normal_le([0xAA, 0xBB, 0xCC, 0xDD].as_ref(), IS_LE, Some(16), 2, vec![0xBBAA, 0xDDCC], bits![Msb0, u8;], vec![0xAA, 0xBB, 0xCC, 0xDD]),
+        case::normal_be([0xAA, 0xBB, 0xCC, 0xDD].as_ref(), !IS_LE, Some(16), 2, vec![0xAABB, 0xCCDD], bits![Msb0, u8;], vec![0xAA, 0xBB, 0xCC, 0xDD]),
     )]
     fn test_vec_read_write(
         input: &[u8],
         is_le: bool,
         bit_size: Option<usize>,
-        count: Option<usize>,
+        count: usize,
         expected: Vec<u16>,
         expected_rest: &BitSlice<Msb0, u8>,
         expected_write: Vec<u8>,
     ) {
         let bit_slice = input.bits::<Msb0>();
+        let endian = if is_le { Endian::Little } else { Endian::Big };
 
-        let (rest, res_read) = Vec::<u16>::read(bit_slice, is_le, bit_size, count).unwrap();
+        // Unwrap here because all test cases are `Some`.
+        let bit_size = bit_size.unwrap();
+
+        let (rest, res_read) =
+            Vec::<u16>::read(bit_slice, (Count(count), (endian, BitSize(bit_size)))).unwrap();
         assert_eq!(expected, res_read);
         assert_eq!(expected_rest, rest);
 
-        let res_write: Vec<u8> = res_read.write(is_le, bit_size).unwrap().into_vec();
+        let res_write: Vec<u8> = res_read
+            .write((endian, BitSize(bit_size)))
+            .unwrap()
+            .into_vec();
         assert_eq!(expected_write, res_write);
 
         assert_eq!(input[..expected_write.len()].to_vec(), expected_write);
     }
 
-    #[rstest(input,is_le,bit_size,count,expected,expected_rest,
-        case::normal_le([237,160,254,145].as_ref(), IS_LE, None, None, Ipv4Addr::new(145,254,160,237), bits![Msb0, u8;]),
-        case::normal_be([145,254,160,237].as_ref(), !IS_LE, None, None, Ipv4Addr::new(145,254,160,237), bits![Msb0, u8;]),
+    #[rstest(input, is_le, expected, expected_rest,
+        case::normal_le([237, 160, 254, 145].as_ref(), IS_LE, Ipv4Addr::new(145, 254, 160, 237), bits![Msb0, u8;]),
+        case::normal_be([145, 254, 160, 237].as_ref(), !IS_LE, Ipv4Addr::new(145, 254, 160, 237), bits![Msb0, u8;]),
     )]
     fn test_ipv4(
         input: &[u8],
         is_le: bool,
-        bit_size: Option<usize>,
-        count: Option<usize>,
         expected: Ipv4Addr,
         expected_rest: &BitSlice<Msb0, u8>,
     ) {
         let bit_slice = input.bits::<Msb0>();
+        let endian = if is_le { Endian::Little } else { Endian::Big };
 
-        let (rest, res_read) = Ipv4Addr::read(bit_slice, is_le, bit_size, count).unwrap();
+        let (rest, res_read) = Ipv4Addr::read(bit_slice, endian).unwrap();
         assert_eq!(expected, res_read);
         assert_eq!(expected_rest, rest);
 
-        let res_write: Vec<u8> = res_read.write(is_le, bit_size).unwrap().into_vec();
+        let res_write: Vec<u8> = res_read.write(endian).unwrap().into_vec();
         assert_eq!(input.to_vec(), res_write);
     }
 
-    #[rstest(input,is_le,bit_size,count,expected,expected_rest,
-        case::normal_le([0xFF, 0x02, 0x0A, 0xC0, 0xFF, 0xFF,
-                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00].as_ref(),
-                        IS_LE, None, None, Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x02ff), bits![Msb0, u8;]),
-        case::normal_be([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                        0xFF, 0xFF, 0xC0, 0x0A, 0x02, 0xFF].as_ref(),
-                        !IS_LE, None, None, Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x02ff), bits![Msb0, u8;]),
+    #[rstest(input, is_le, expected, expected_rest,
+        case::normal_le([0xFF, 0x02, 0x0A, 0xC0, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00].as_ref(), IS_LE, Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x02ff), bits![Msb0, u8;]),
+        case::normal_be([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x0A, 0x02, 0xFF].as_ref(), !IS_LE, Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x02ff), bits![Msb0, u8;]),
     )]
     fn test_ipv6(
         input: &[u8],
         is_le: bool,
-        bit_size: Option<usize>,
-        count: Option<usize>,
         expected: Ipv6Addr,
         expected_rest: &BitSlice<Msb0, u8>,
     ) {
         let bit_slice = input.bits::<Msb0>();
+        let endian = if is_le { Endian::Little } else { Endian::Big };
 
-        let (rest, res_read) = Ipv6Addr::read(bit_slice, is_le, bit_size, count).unwrap();
+        let (rest, res_read) = Ipv6Addr::read(bit_slice, endian).unwrap();
         assert_eq!(expected, res_read);
         assert_eq!(expected_rest, rest);
 
-        let res_write: Vec<u8> = res_read.write(is_le, bit_size).unwrap().into_vec();
+        let res_write: Vec<u8> = res_read.write(endian).unwrap().into_vec();
         assert_eq!(input.to_vec(), res_write);
     }
 
     #[test]
     fn test_ip_addr_write() {
         let ip_addr = IpAddr::V4(Ipv4Addr::new(145, 254, 160, 237));
-        let ret_write = ip_addr.write(true, None).unwrap().into_vec();
+        let ret_write = ip_addr.write(Endian::Little).unwrap().into_vec();
         assert_eq!(vec![237, 160, 254, 145], ret_write);
 
         let ip_addr = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x02ff));
-        let ret_write = ip_addr.write(true, None).unwrap().into_vec();
+        let ret_write = ip_addr.write(Endian::Little).unwrap().into_vec();
         assert_eq!(
             vec![
                 0xFF, 0x02, 0x0A, 0xC0, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
diff --git a/src/slice_impls.rs b/src/slice_impls.rs
index de8952d..a7a2815 100644
--- a/src/slice_impls.rs
+++ b/src/slice_impls.rs
@@ -8,24 +8,27 @@ use crate::error::DekuError;
 use bitvec::prelude::*;
 pub use deku_derive::*;
 
+/*
+Note: They are all generic because those type are not really required a context. They forward context
+to inner types.
+ */
 macro_rules! ImplDekuSliceTraits {
     ($typ:ty, $count:expr) => {
-        impl DekuRead for [$typ; $count] {
+        impl<Ctx: Copy> DekuRead<Ctx> for [$typ; $count]
+        where
+            $typ: DekuRead<Ctx>,
+        {
             fn read(
                 input: &BitSlice<Msb0, u8>,
-                input_is_le: bool,
-                bit_size: Option<usize>,
-                count: Option<usize>,
+                ctx: Ctx,
             ) -> Result<(&BitSlice<Msb0, u8>, Self), DekuError>
             where
                 Self: Sized,
             {
-                assert!(count.is_none(), "Dev error: `count` should always be None");
-
                 let mut slice: [$typ; $count] = Default::default();
                 let mut rest = input;
                 for i in 0..$count {
-                    let (new_rest, value) = <$typ>::read(rest, input_is_le, bit_size, count)?;
+                    let (new_rest, value) = <$typ>::read(rest, ctx)?;
                     slice[i] = value;
                     rest = new_rest;
                 }
@@ -34,16 +37,15 @@ macro_rules! ImplDekuSliceTraits {
             }
         }
 
-        impl DekuWrite for [$typ; $count] {
-            fn write(
-                &self,
-                output_is_le: bool,
-                bit_size: Option<usize>,
-            ) -> Result<BitVec<Msb0, u8>, DekuError> {
+        impl<Ctx: Copy> DekuWrite<Ctx> for [$typ; $count]
+        where
+            $typ: DekuWrite<Ctx>,
+        {
+            fn write(&self, ctx: Ctx) -> Result<BitVec<Msb0, u8>, DekuError> {
                 let mut acc = BitVec::new();
 
                 for v in self {
-                    let r = v.write(output_is_le, bit_size)?;
+                    let r = v.write(ctx)?;
                     acc.extend(r);
                 }
 
@@ -531,36 +533,39 @@ mod tests {
     #[cfg(target_endian = "big")]
     static IS_LE: bool = false;
 
-    #[rstest(input,input_is_le,bit_size,count,expected,expected_rest,
-        case::normal_le([0xDD, 0xCC, 0xBB, 0xAA].as_ref(), IS_LE, None, None, [0xCCDD, 0xAABB], bits![Msb0, u8;]),
-        case::normal_be([0xDD, 0xCC, 0xBB, 0xAA].as_ref(), !IS_LE, None, None, [0xDDCC, 0xBBAA], bits![Msb0, u8;]),
+    #[rstest(input,input_is_le,expected,expected_rest,
+        case::normal_le([0xDD, 0xCC, 0xBB, 0xAA].as_ref(), IS_LE, [0xCCDD, 0xAABB], bits![Msb0, u8;]),
+        case::normal_be([0xDD, 0xCC, 0xBB, 0xAA].as_ref(), !IS_LE, [0xDDCC, 0xBBAA], bits![Msb0, u8;]),
     )]
     fn test_bit_read(
         input: &[u8],
         input_is_le: bool,
-        bit_size: Option<usize>,
-        count: Option<usize>,
         expected: [u16; 2],
         expected_rest: &BitSlice<Msb0, u8>,
     ) {
         let bit_slice = input.bits::<Msb0>();
+        let endian = if input_is_le {
+            crate::ctx::Endian::Little
+        } else {
+            crate::ctx::Endian::Big
+        };
 
-        let (rest, res_read) = <[u16; 2]>::read(bit_slice, input_is_le, bit_size, count).unwrap();
+        let (rest, res_read) = <[u16; 2]>::read(bit_slice, endian).unwrap();
         assert_eq!(expected, res_read);
         assert_eq!(expected_rest, rest);
     }
 
-    #[rstest(input,output_is_le,bit_size,expected,
-        case::normal_le([0xDDCC, 0xBBAA], IS_LE, None, vec![0xCC, 0xDD, 0xAA, 0xBB]),
-        case::normal_be([0xDDCC, 0xBBAA], !IS_LE, None, vec![0xDD, 0xCC, 0xBB, 0xAA]),
+    #[rstest(input,output_is_le,expected,
+        case::normal_le([0xDDCC, 0xBBAA], IS_LE, vec![0xCC, 0xDD, 0xAA, 0xBB]),
+        case::normal_be([0xDDCC, 0xBBAA], !IS_LE, vec![0xDD, 0xCC, 0xBB, 0xAA]),
     )]
-    fn test_bit_write(
-        input: [u16; 2],
-        output_is_le: bool,
-        bit_size: Option<usize>,
-        expected: Vec<u8>,
-    ) {
-        let res_write = input.write(output_is_le, bit_size).unwrap().into_vec();
+    fn test_bit_write(input: [u16; 2], output_is_le: bool, expected: Vec<u8>) {
+        let endian = if output_is_le {
+            crate::ctx::Endian::Little
+        } else {
+            crate::ctx::Endian::Big
+        };
+        let res_write = input.write(endian).unwrap().into_vec();
         assert_eq!(expected, res_write);
     }
 }


Test patch:
diff --git a/tests/macro_read/bits_bytes_conflict.rs b/tests/macro_read/bits_bytes_conflict.rs
new file mode 100644
index 0000000..c1ed406
--- /dev/null
+++ b/tests/macro_read/bits_bytes_conflict.rs
@@ -0,0 +1,26 @@
+use deku::prelude::*;
+
+#[derive(DekuRead)]
+#[deku(id_type = "u8", id_bits = "1", id_bytes = "2")]
+enum Test1 {}
+
+#[derive(DekuRead)]
+#[deku(id_type = "u8")]
+enum Test2 {
+    A(#[deku(bits = "1", bytes = "2")] u8),
+    B {
+        #[deku(bits = "3", bytes = "4")]
+        a: u8,
+    },
+}
+
+#[derive(DekuRead)]
+struct Test3 {
+    #[deku(bits = "5", bytes = "6")]
+    a: u8,
+}
+
+#[derive(DekuRead)]
+struct Test4(#[deku(bits = "7", bytes = "8")] u8);
+
+fn main() {}
diff --git a/tests/macro_read/bits_bytes_conflict.stderr b/tests/macro_read/bits_bytes_conflict.stderr
new file mode 100644
index 0000000..3647fca
--- /dev/null
+++ b/tests/macro_read/bits_bytes_conflict.stderr
@@ -0,0 +1,31 @@
+error: conflicting: both "id_bits" and "id_bytes" specified on field
+ --> $DIR/bits_bytes_conflict.rs:3:10
+  |
+3 | #[derive(DekuRead)]
+  |          ^^^^^^^^
+  |
+  = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: conflicting: both "bits" and "bytes" specified on field
+ --> $DIR/bits_bytes_conflict.rs:7:10
+  |
+7 | #[derive(DekuRead)]
+  |          ^^^^^^^^
+  |
+  = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: conflicting: both "bits" and "bytes" specified on field
+  --> $DIR/bits_bytes_conflict.rs:17:10
+   |
+17 | #[derive(DekuRead)]
+   |          ^^^^^^^^
+   |
+   = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: conflicting: both "bits" and "bytes" specified on field
+  --> $DIR/bits_bytes_conflict.rs:23:10
+   |
+23 | #[derive(DekuRead)]
+   |          ^^^^^^^^
+   |
+   = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/macro_read/enum_without_id_type.rs b/tests/macro_read/enum_without_id_type.rs
new file mode 100644
index 0000000..5bab571
--- /dev/null
+++ b/tests/macro_read/enum_without_id_type.rs
@@ -0,0 +1,6 @@
+use deku::prelude::*;
+
+#[derive(DekuRead)]
+enum Test {}
+
+fn main() {}
diff --git a/tests/macro_read/enum_without_id_type.stderr b/tests/macro_read/enum_without_id_type.stderr
new file mode 100644
index 0000000..f4560e8
--- /dev/null
+++ b/tests/macro_read/enum_without_id_type.stderr
@@ -0,0 +1,5 @@
+error: `id_type` must be specified on enum
+ --> $DIR/enum_without_id_type.rs:4:6
+  |
+4 | enum Test {}
+  |      ^^^^
diff --git a/tests/macro_read/unknown_endian.rs b/tests/macro_read/unknown_endian.rs
new file mode 100644
index 0000000..d4b40ce
--- /dev/null
+++ b/tests/macro_read/unknown_endian.rs
@@ -0,0 +1,26 @@
+use deku::prelude::*;
+
+#[derive(DekuRead)]
+#[deku(endian = "1")]
+struct Test1 {
+    a: u8,
+}
+
+#[derive(DekuRead)]
+struct Test2 {
+    #[deku(endian = "2")]
+    a: u8,
+}
+
+#[derive(DekuRead)]
+#[deku(id_type = "u8", endian = "3")]
+enum Test3 {}
+
+#[derive(DekuRead)]
+#[deku(id_type = "u8")]
+enum Test4 {
+    #[deku(id = "1")]
+    A(#[deku(endian = "4")] u8),
+}
+
+fn main() {}
diff --git a/tests/macro_read/unknown_endian.stderr b/tests/macro_read/unknown_endian.stderr
new file mode 100644
index 0000000..1ff1de1
--- /dev/null
+++ b/tests/macro_read/unknown_endian.stderr
@@ -0,0 +1,23 @@
+error: Unknown endian name
+ --> $DIR/unknown_endian.rs:4:17
+  |
+4 | #[deku(endian = "1")]
+  |                 ^^^
+
+error: Unknown endian name
+  --> $DIR/unknown_endian.rs:11:21
+   |
+11 |     #[deku(endian = "2")]
+   |                     ^^^
+
+error: Unknown endian name
+  --> $DIR/unknown_endian.rs:16:33
+   |
+16 | #[deku(id_type = "u8", endian = "3")]
+   |                                 ^^^
+
+error: Unknown endian name
+  --> $DIR/unknown_endian.rs:23:23
+   |
+23 |     A(#[deku(endian = "4")] u8),
+   |                       ^^^
diff --git a/tests/test_alloc.rs b/tests/test_alloc.rs
index 10f8467..caa17ba 100644
--- a/tests/test_alloc.rs
+++ b/tests/test_alloc.rs
@@ -1,19 +1,22 @@
 use alloc_counter::AllocCounterSystem;
+use deku::ctx::Endian;
 use deku::prelude::*;
 
 #[global_allocator]
 static A: AllocCounterSystem = AllocCounterSystem;
 
 #[derive(Debug, PartialEq, DekuRead, DekuWrite)]
+#[deku(ctx = "endian: Endian")]
 struct NestedStruct {
+    #[deku(ctx = "endian")]
     pub field_a: u8,
 }
 
 #[derive(Debug, PartialEq, DekuRead, DekuWrite)]
-#[deku(id_type = "u8")]
+#[deku(id_type = "u8", ctx = "endian: Endian")]
 enum NestedEnum {
     #[deku(id = "0x01")]
-    VarA(u8),
+    VarA(#[deku(ctx = "endian")] u8),
 }
 
 #[derive(Debug, PartialEq, DekuRead, DekuWrite)]
diff --git a/tests/test_macro.rs b/tests/test_macro.rs
index ddf34e4..2511b74 100644
--- a/tests/test_macro.rs
+++ b/tests/test_macro.rs
@@ -104,35 +104,6 @@ mod tests {
             }
         }
 
-        #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
-        pub struct ReaderWriterDeku {
-            #[deku(
-                reader = "ReaderWriterDeku::read(rest, input_is_le, field_bits)",
-                writer = "ReaderWriterDeku::write(self.field_a, output_is_le, field_bits)"
-            )]
-            pub field_a: u8,
-        }
-
-        impl ReaderWriterDeku {
-            fn read(
-                rest: &BitSlice<Msb0, u8>,
-                input_is_le: bool,
-                bit_size: Option<usize>,
-            ) -> Result<(&BitSlice<Msb0, u8>, u8), DekuError> {
-                let (rest, value) = u8::read(rest, input_is_le, bit_size, None)?;
-                Ok((rest, value + 1))
-            }
-
-            fn write(
-                field_a: u8,
-                output_is_le: bool,
-                bit_size: Option<usize>,
-            ) -> Result<BitVec<Msb0, u8>, DekuError> {
-                let value = field_a - 1;
-                value.write(output_is_le, bit_size)
-            }
-        }
-
         #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
         pub struct GenericStructDeku<T: deku::DekuWrite + deku::DekuRead>
         where
@@ -166,6 +137,53 @@ mod tests {
             pub field_b: u8,
             pub field_c: u8,
         }
+
+        #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
+        #[deku(ctx = "_a: u8, _b: u8")]
+        pub struct TopLevelCtxStruct {}
+
+        #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
+        #[deku(ctx = "a: u8, b: u8")]
+        pub struct SubTypeNeedCtx {
+            #[deku(
+                reader = "(|rest|{u8::read(rest,()).map(|(slice,c)|(slice,(a+b+c) as usize))})(rest)",
+                writer = "(|c|{u8::write(&(c-a-b), ())})(self.i as u8)"
+            )]
+            pub(crate) i: usize,
+        }
+
+        #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
+        pub struct FieldLevelCtxStruct {
+            pub a: u8,
+            pub b: u8,
+            #[deku(ctx = "a + 1, *b")]
+            pub c: SubTypeNeedCtx,
+        }
+
+        #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
+        #[deku(id_type = "u8", ctx = "a: u8, b: u8")]
+        pub enum TopLevelCtxEnum {
+            #[deku(id = "1")]
+            VariantA(
+                #[deku(
+                    reader = "(|rest|{u8::read(rest,()).map(|(slice,c)|(slice,(a+b+c)))})(rest)",
+                    writer = "(|c|{u8::write(&(c-a-b), ())})(field_0)"
+                )]
+                u8,
+            ),
+        }
+
+        #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
+        #[deku(id_type = "u8")]
+        pub enum VariantLevelCtxEnum {
+            #[deku(id = "1")]
+            VariantA {
+                a: u8,
+                b: u8,
+                #[deku(ctx = "*a, *b")]
+                c: SubTypeNeedCtx,
+            },
+        }
     }
 
     #[test]
@@ -347,22 +365,6 @@ mod tests {
         );
     }
 
-    #[test]
-    fn test_reader_writer() {
-        let test_data: Vec<u8> = [0x01].to_vec();
-
-        let ret_read = samples::ReaderWriterDeku::try_from(test_data.as_ref()).unwrap();
-        assert_eq!(
-            samples::ReaderWriterDeku {
-                field_a: 0x02 // 0x01 + 1 as specified in the reader function
-            },
-            ret_read
-        );
-
-        let ret_write: Vec<u8> = ret_read.try_into().unwrap();
-        assert_eq!(test_data, ret_write);
-    }
-
     #[test]
     fn test_generic_struct_deku() {
         let test_data: Vec<u8> = [0x01].to_vec();
@@ -420,4 +422,41 @@ mod tests {
         let ret_write: Vec<u8> = ret_read.try_into().unwrap();
         assert_eq!(test_data, ret_write);
     }
+
+    #[test]
+    fn test_ctx_struct() {
+        let test_data = [0x01_u8, 0x02, 0x03];
+
+        let ret_read = samples::FieldLevelCtxStruct::try_from(&test_data[..]).unwrap();
+        assert_eq!(
+            ret_read,
+            samples::FieldLevelCtxStruct {
+                a: 0x01,
+                b: 0x02,
+                c: samples::SubTypeNeedCtx {
+                    i: 0x01 + 1 + 0x02 + 0x03
+                } // (a + 1) + b + c
+            }
+        );
+
+        let ret_write: Vec<u8> = ret_read.try_into().unwrap();
+        assert_eq!(ret_write, test_data)
+    }
+
+    #[test]
+    fn test_top_level_ctx_enum() {
+        let test_data = [0x01_u8, 0x03];
+        let (rest, ret_read) = samples::TopLevelCtxEnum::read(test_data.bits(), (1, 2)).unwrap();
+        assert!(rest.is_empty());
+        assert_eq!(ret_read, samples::TopLevelCtxEnum::VariantA(0x06));
+
+        let ret_write = ret_read.write((1, 2)).unwrap();
+        assert_eq!(ret_write.into_vec(), &test_data[..]);
+    }
+
+    #[test]
+    fn test_compile() {
+        let t = trybuild::TestCases::new();
+        t.compile_fail("tests/macro_read/*.rs");
+    }
 }