diff --git a/fuzz/.gitignore b/fuzz/.gitignore
new file mode 100644
index 0000000..a092511
--- /dev/null
+++ b/fuzz/.gitignore
@@ -0,0 +1,3 @@
+target
+corpus
+artifacts
diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml
new file mode 100644
index 0000000..dece18a
--- /dev/null
+++ b/fuzz/Cargo.toml
@@ -0,0 +1,23 @@
+[package]
+name = "msgpacker-fuzz"
+version = "0.0.0"
+authors = ["Automatically generated"]
+publish = false
+edition = "2018"
+
+[package.metadata]
+cargo-fuzz = true
+
+[dependencies]
+arbitrary = { version = "1.1", features = ["derive"] }
+libfuzzer-sys = "0.4"
+msgpacker = { path = "../msgpacker" }
+
+[workspace]
+members = ["."]
+
+[[bin]]
+name = "messages"
+path = "fuzz_targets/messages.rs"
+test = false
+doc = false
diff --git a/fuzz/fuzz_targets/messages.rs b/fuzz/fuzz_targets/messages.rs
new file mode 100644
index 0000000..8f80558
--- /dev/null
+++ b/fuzz/fuzz_targets/messages.rs
@@ -0,0 +1,44 @@
+#![no_main]
+use libfuzzer_sys::fuzz_target;
+
+use arbitrary::Arbitrary;
+use msgpacker::prelude::*;
+
+#[derive(Arbitrary, MsgPacker, Debug, Clone, PartialEq, Eq)]
+pub struct AllMessages {
+    pub uint64: Option<u64>,
+    pub int64: Option<i64>,
+    pub b: Option<bool>,
+    pub f_32: Option<f32>,
+    pub f_64: Option<f64>,
+    pub string: Option<String>,
+    pub bin: Option<Vec<u8>>,
+}
+
+fuzz_target!(|m: AllMessages| {
+    let mut m = m;
+
+    let buf: Vec<u8> = vec![];
+    let mut packer = CursorPacker::new(buf);
+
+    packer.pack(m.clone()).expect("failed to pack message");
+    packer.set_position(0);
+
+    let mut p: AllMessages = packer.unpack().expect("failed to unpack message");
+
+    // NaN equality doesn't hold
+    if m.f_32.filter(|f| f.is_nan()).is_some() {
+        m.f_32.take();
+    }
+    if m.f_64.filter(|f| f.is_nan()).is_some() {
+        m.f_64.take();
+    }
+    if p.f_32.filter(|f| f.is_nan()).is_some() {
+        p.f_32.take();
+    }
+    if p.f_64.filter(|f| f.is_nan()).is_some() {
+        p.f_64.take();
+    }
+
+    assert_eq!(m, p);
+});
diff --git a/msgpacker-derive/Cargo.toml b/msgpacker-derive/Cargo.toml
index 6d0586b..13e85ca 100644
--- a/msgpacker-derive/Cargo.toml
+++ b/msgpacker-derive/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "msgpacker-derive"
-version = "0.1.0"
+version = "0.1.2"
 authors = ["Victor Lopez <victor@codx.io>"]
 categories = ["compression", "encoding", "parser-implementations"]
 edition = "2021"
diff --git a/msgpacker-derive/src/lib.rs b/msgpacker-derive/src/lib.rs
index 336f06e..e81bf6d 100644
--- a/msgpacker-derive/src/lib.rs
+++ b/msgpacker-derive/src/lib.rs
@@ -16,7 +16,7 @@ pub fn msg_packer(input: TokenStream) -> TokenStream {
     let data = input.data;
 
     let mut values: Punctuated<FieldValue, Token![,]> = Punctuated::new();
-    let block: Block = match data {
+    let (block, block_size): (Block, Block) = match data {
         Data::Struct(syn::DataStruct {
             struct_token: _,
             fields: Fields::Named(f),
@@ -25,17 +25,21 @@ pub fn msg_packer(input: TokenStream) -> TokenStream {
             .named
             .into_pairs()
             .map(|p| p.into_value())
-            .fold(syn::parse_str("{}").unwrap(), |mut block, field| {
+            .fold((syn::parse_str("{}").unwrap(), syn::parse_str("{}").unwrap()), |(mut block, mut block_size), field| {
                 let ident = field.ident.as_ref().cloned().unwrap();
                 let ty = field.ty;
 
+                block_size.stmts.push(parse_quote! {
+                    n += <#ty as msgpacker::prelude::SizeableMessage>::packed_len(&self.#ident);
+                });
+
                 block.stmts.push(parse_quote! {
                     n += <#ty as msgpacker::prelude::Packable>::pack(&self.#ident, packer.by_ref())?;
                 });
 
                 let fv = FieldValue {
                     attrs: vec![],
-                    member: Member::Named(ident.clone()),
+                    member: Member::Named(ident),
                     colon_token: Some(<Token![:]>::default()),
                     expr: parse_quote! {
                         <#ty as msgpacker::prelude::Unpackable>::unpack(unpacker.by_ref())?
@@ -43,12 +47,32 @@ pub fn msg_packer(input: TokenStream) -> TokenStream {
                 };
                 values.push(fv);
 
-                block
+                (block, block_size)
             }),
         _ => todo!(),
     };
 
     let expanded = quote! {
+        impl msgpacker::prelude::SizeableMessage for #name {
+            fn packed_len(&self) -> usize {
+                let mut n = 0;
+
+                #block_size
+
+                n
+            }
+        }
+
+        impl<'a> msgpacker::prelude::SizeableMessage for &'a #name {
+            fn packed_len(&self) -> usize {
+                let mut n = 0;
+
+                #block_size
+
+                n
+            }
+        }
+
         impl msgpacker::prelude::Packable for #name {
             fn pack<W>(&self, mut packer: W) -> std::io::Result<usize>
             where
@@ -62,6 +86,19 @@ pub fn msg_packer(input: TokenStream) -> TokenStream {
             }
         }
 
+        impl<'a> msgpacker::prelude::Packable for &'a #name {
+            fn pack<W>(&self, mut packer: W) -> std::io::Result<usize>
+            where
+                W: std::io::Write
+            {
+                let mut n = 0;
+
+                #block
+
+                Ok(n)
+            }
+        }
+
         impl msgpacker::prelude::Unpackable for #name {
             fn unpack<R>(mut unpacker: R) -> std::io::Result<Self>
             where
diff --git a/msgpacker/Cargo.toml b/msgpacker/Cargo.toml
index 46f6e91..ae7872f 100644
--- a/msgpacker/Cargo.toml
+++ b/msgpacker/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "msgpacker"
-version = "0.2.1"
+version = "0.2.2"
 authors = ["Victor Lopez <victor@codx.io>"]
 categories = ["compression", "encoding", "parser-implementations"]
 edition = "2021"
diff --git a/msgpacker/src/buffer.rs b/msgpacker/src/buffer.rs
index 5ad1580..c4d32e6 100644
--- a/msgpacker/src/buffer.rs
+++ b/msgpacker/src/buffer.rs
@@ -59,3 +59,18 @@ where
 pub const unsafe fn cast_fixed_array<const M: usize, const N: usize>(array: [u8; M]) -> [u8; N] {
     *mem::transmute::<&[u8; M], &[u8; N]>(&array)
 }
+
+#[test]
+fn take_buf_wont_panic_for_small_buf() {
+    use std::io::Read;
+
+    const LEN: usize = 10;
+
+    let mut cursor = io::Cursor::new([0u8; LEN]);
+
+    let err = unsafe { take_buf(cursor.by_ref(), LEN + 1) }
+        .err()
+        .expect("buffer isn't big enough");
+
+    assert_eq!(io::ErrorKind::UnexpectedEof, err.kind());
+}
diff --git a/msgpacker/src/consts.rs b/msgpacker/src/consts.rs
new file mode 100644
index 0000000..0243874
--- /dev/null
+++ b/msgpacker/src/consts.rs
@@ -0,0 +1,11 @@
+/// Packable representation for variant `None` of [`Option`]
+pub const OPTION_NONE: isize = 0x00;
+
+/// Packable representation for variant `Some` of [`Option`]
+pub const OPTION_SOME: isize = 0x01;
+
+/// Packable representation for variant `Ok` of [`Result`]
+pub const RESULT_OK: isize = 0x00;
+
+/// Packable representation for variant `Err` of [`Result`]
+pub const RESULT_ERR: isize = 0x01;
diff --git a/msgpacker/src/float.rs b/msgpacker/src/float.rs
index bebb5d6..d6e2984 100644
--- a/msgpacker/src/float.rs
+++ b/msgpacker/src/float.rs
@@ -1,5 +1,6 @@
 use crate::buffer;
 use crate::format::MessageFormat;
+use crate::packer::SizeableMessage;
 
 use std::io;
 
@@ -57,6 +58,18 @@ impl Float {
             }
         }
 
+        debug_assert_eq!(n, self.packed_len());
+
         Ok(n)
     }
 }
+
+impl SizeableMessage for Float {
+    fn packed_len(&self) -> usize {
+        match self {
+            Self::F32(_) => 5,
+
+            Self::F64(_) => 9,
+        }
+    }
+}
diff --git a/msgpacker/src/format.rs b/msgpacker/src/format.rs
index 1acd520..a5aa615 100644
--- a/msgpacker/src/format.rs
+++ b/msgpacker/src/format.rs
@@ -1,3 +1,5 @@
+use crate::packer::SizeableMessage;
+
 /// [specs](https://github.com/msgpack/msgpack/blob/master/spec.md#formats)
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub enum MessageFormat {
@@ -77,6 +79,12 @@ pub enum MessageFormat {
     NegativeFixInt(i8),
 }
 
+impl SizeableMessage for MessageFormat {
+    fn packed_len(&self) -> usize {
+        1
+    }
+}
+
 impl From<u8> for MessageFormat {
     fn from(b: u8) -> Self {
         use MessageFormat::*;
diff --git a/msgpacker/src/integer.rs b/msgpacker/src/integer.rs
index 4639d12..9f5e9c8 100644
--- a/msgpacker/src/integer.rs
+++ b/msgpacker/src/integer.rs
@@ -1,5 +1,6 @@
 use crate::buffer;
 use crate::format::MessageFormat;
+use crate::packer::SizeableMessage;
 
 use std::io;
 
@@ -158,10 +159,48 @@ impl Integer {
             }
         }
 
+        debug_assert_eq!(n, self.packed_len());
+
         Ok(n)
     }
 }
 
+impl SizeableMessage for Integer {
+    fn packed_len(&self) -> usize {
+        match self {
+            Self::Int64(i) if *i <= i32::MIN as i64 => 9,
+
+            Self::Int64(i) if *i <= i16::MIN as i64 => 5,
+
+            Self::Int64(i) if *i <= i8::MIN as i64 => 3,
+
+            Self::Int64(i) if *i <= -33 => 2,
+
+            Self::Int64(i) if *i <= -1 => 1,
+
+            Self::Int64(i) if *i <= 127 => 1,
+
+            Self::Uint64(i) if *i <= 127 => 1,
+
+            Self::Int64(i) if *i <= u8::MAX as i64 => 2,
+
+            Self::Uint64(i) if *i <= u8::MAX as u64 => 2,
+
+            Self::Int64(i) if *i <= u16::MAX as i64 => 3,
+
+            Self::Uint64(i) if *i <= u16::MAX as u64 => 3,
+
+            Self::Int64(i) if *i <= u32::MAX as i64 => 5,
+
+            Self::Uint64(i) if *i <= u32::MAX as u64 => 5,
+
+            Self::Int64(_) => 9,
+
+            Self::Uint64(_) => 9,
+        }
+    }
+}
+
 impl From<Integer> for i64 {
     fn from(i: Integer) -> i64 {
         match i {
diff --git a/msgpacker/src/lib.rs b/msgpacker/src/lib.rs
index ef80e82..2d06cb5 100644
--- a/msgpacker/src/lib.rs
+++ b/msgpacker/src/lib.rs
@@ -11,6 +11,9 @@ mod message;
 mod message_ref;
 mod packer;
 
+/// Preset constants
+pub mod consts;
+
 pub use message::Message;
 pub use message_ref::MessageRef;
 
@@ -27,7 +30,10 @@ pub mod types {
 pub mod prelude {
     pub use crate::message::Message;
     pub use crate::message_ref::MessageRef;
-    pub use crate::packer::{CursorPacker, MessagePacker, MessageUnpacker, Packable, Unpackable};
+    pub use crate::packer::{
+        BufferedUnpacker, CursorPacker, MessagePacker, MessageUnpacker, Packable, SizeableMessage,
+        Unpackable, UnpackableIter,
+    };
     pub use crate::types::*;
 
     #[cfg(feature = "derive")]
diff --git a/msgpacker/src/message.rs b/msgpacker/src/message.rs
index 01a1dd9..336a6d9 100644
--- a/msgpacker/src/message.rs
+++ b/msgpacker/src/message.rs
@@ -5,6 +5,7 @@ use crate::format::MessageFormat;
 use crate::integer::Integer;
 use crate::map::MapEntry;
 use crate::message_ref::MessageRef;
+use crate::packer::SizeableMessage;
 
 use std::io;
 use std::ops::Index;
@@ -112,10 +113,7 @@ impl Message {
 
     /// Return `true` if the message is nil
     pub const fn is_nil(&self) -> bool {
-        match self {
-            Self::Nil => true,
-            _ => false,
-        }
+        matches!(self, Self::Nil)
     }
 
     /// Create a new unsigned interger
@@ -215,7 +213,7 @@ impl Message {
 
             MessageFormat::Int8 => {
                 buffer::take(reader, &mut buf, 1)?;
-                let n = Integer::Int64(buf[0] as i64);
+                let n = Integer::Int64((buf[0] as i8) as i64);
 
                 Ok(Self::Integer(n))
             }
@@ -759,6 +757,8 @@ impl Message {
             )),
         }
 
+        debug_assert_eq!(n, self.packed_len());
+
         Ok(n)
     }
 }
@@ -770,11 +770,16 @@ impl<M: Into<Message>> Index<M> for Message {
         let i = i.into();
 
         self.as_map()
-            .map(|m| {
+            .and_then(|m| {
                 m.iter()
                     .find_map(|m| if m.key() == &i { Some(m.val()) } else { None })
             })
-            .flatten()
             .unwrap_or(&Message::Nil)
     }
 }
+
+impl SizeableMessage for Message {
+    fn packed_len(&self) -> usize {
+        self.to_ref().packed_len()
+    }
+}
diff --git a/msgpacker/src/message_ref.rs b/msgpacker/src/message_ref.rs
index 8741063..bbc6f5a 100644
--- a/msgpacker/src/message_ref.rs
+++ b/msgpacker/src/message_ref.rs
@@ -3,6 +3,7 @@ use crate::float::Float;
 use crate::format::MessageFormat;
 use crate::integer::Integer;
 use crate::map::MapEntryRef;
+use crate::packer::SizeableMessage;
 use crate::{buffer, Message};
 
 use std::ops::Index;
@@ -103,10 +104,7 @@ impl<'a> MessageRef<'a> {
 
     /// Return `true` if the message is nil
     pub const fn is_nil(&self) -> bool {
-        match self {
-            Self::Nil => true,
-            _ => false,
-        }
+        matches!(self, Self::Nil)
     }
 
     /// Create a new unsigned interger
@@ -173,7 +171,7 @@ impl<'a> MessageRef<'a> {
 
             MessageFormat::Int8 => {
                 let buf = buffer::take_buf(reader, 1)?;
-                let n = Integer::Int64(buf[0] as i64);
+                let n = Integer::Int64((buf[0] as i8) as i64);
 
                 Ok(Self::Integer(n))
             }
@@ -763,6 +761,8 @@ impl<'a> MessageRef<'a> {
             )),
         }
 
+        debug_assert_eq!(n, self.packed_len());
+
         Ok(n)
     }
 }
@@ -777,11 +777,108 @@ impl<'a, 'b, M: Into<MessageRef<'b>>> Index<M> for MessageRef<'a> {
         // Safety: self is bound to 'a
         let m: Option<&'a [MapEntryRef<'a>]> = unsafe { mem::transmute(m) };
 
-        m.map(|m| {
+        m.and_then(|m| {
             m.iter()
                 .find_map(|m| if m.key() == &i { Some(m.val()) } else { None })
         })
-        .flatten()
         .unwrap_or(&MessageRef::Nil)
     }
 }
+
+impl<'a> SizeableMessage for MessageRef<'a> {
+    fn packed_len(&self) -> usize {
+        match self {
+            Self::Nil => 1,
+            Self::Boolean(true) => 1,
+            Self::Boolean(false) => 1,
+            Self::Integer(i) => i.packed_len(),
+            Self::Float(f) => f.packed_len(),
+
+            Self::String(s) if s.len() <= 31 => 1 + s.len(),
+
+            Self::String(s) if s.len() <= u8::MAX as usize => 2 + s.len(),
+
+            Self::String(s) if s.len() <= u16::MAX as usize => 3 + s.len(),
+
+            Self::String(s) => 5 + s.len(),
+
+            Self::Bin(b) if b.len() <= u8::MAX as usize => 2 + b.len(),
+
+            Self::Bin(b) if b.len() <= u16::MAX as usize => 3 + b.len(),
+
+            Self::Bin(b) => 5 + b.len(),
+
+            Self::Array(a) if a.len() <= 15 => 1 + a.iter().map(Self::packed_len).sum::<usize>(),
+
+            Self::Array(a) if a.len() <= u16::MAX as usize => {
+                3 + a.iter().map(Self::packed_len).sum::<usize>()
+            }
+
+            Self::Array(a) => 5 + a.iter().map(Self::packed_len).sum::<usize>(),
+
+            Self::Map(m) if m.len() <= 15 => {
+                1 + m
+                    .iter()
+                    .map(MapEntryRef::inner)
+                    .map(|(k, v)| k.packed_len() + v.packed_len())
+                    .sum::<usize>()
+            }
+
+            Self::Map(m) if m.len() <= u16::MAX as usize => {
+                3 + m
+                    .iter()
+                    .map(MapEntryRef::inner)
+                    .map(|(k, v)| k.packed_len() + v.packed_len())
+                    .sum::<usize>()
+            }
+
+            Self::Map(m) => {
+                4 + m
+                    .iter()
+                    .map(MapEntryRef::inner)
+                    .map(|(k, v)| k.packed_len() + v.packed_len())
+                    .sum::<usize>()
+            }
+
+            Self::Extension(ExtensionRef::FixExt1(_, _)) => 3,
+
+            Self::Extension(ExtensionRef::Ext(_, e)) if e.len() == 1 => 3,
+
+            Self::Extension(ExtensionRef::FixExt2(_, e)) => 2 + e.len(),
+
+            Self::Extension(ExtensionRef::Ext(_, e)) if e.len() == 2 => 2 + e.len(),
+
+            Self::Extension(ExtensionRef::FixExt4(_, e)) => 2 + e.len(),
+
+            Self::Extension(ExtensionRef::Ext(_, e)) if e.len() == 4 => 2 + e.len(),
+
+            Self::Extension(ExtensionRef::FixExt8(_, e)) => 2 + e.len(),
+
+            Self::Extension(ExtensionRef::Ext(_, e)) if e.len() == 8 => 2 + e.len(),
+
+            Self::Extension(ExtensionRef::FixExt16(_, e)) => 2 + e.len(),
+
+            Self::Extension(ExtensionRef::Ext(_, e)) if e.len() == 16 => 2 + e.len(),
+
+            Self::Extension(ExtensionRef::Ext(_, e)) if e.len() <= u8::MAX as usize => 3 + e.len(),
+
+            Self::Extension(ExtensionRef::Ext(_, e)) if e.len() <= u16::MAX as usize => 4 + e.len(),
+
+            Self::Extension(ExtensionRef::Ext(_, e)) => 6 + e.len(),
+
+            Self::Extension(ExtensionRef::Timestamp(d))
+                if d.as_secs() <= u32::MAX as u64 && d.subsec_nanos() == 0 =>
+            {
+                6
+            }
+
+            Self::Extension(ExtensionRef::Timestamp(d))
+                if d.as_secs() < 1u64 << 34 && d.subsec_nanos() < 1u32 << 30 =>
+            {
+                10
+            }
+
+            Self::Extension(ExtensionRef::Timestamp(_)) => 15,
+        }
+    }
+}
diff --git a/msgpacker/src/packer.rs b/msgpacker/src/packer.rs
index 6cb10aa..67be29e 100644
--- a/msgpacker/src/packer.rs
+++ b/msgpacker/src/packer.rs
@@ -1,9 +1,19 @@
+use std::fs;
 use std::io::{self, BufRead, Cursor, Read, Seek, SeekFrom, Write};
+use std::marker::PhantomData;
+use std::ops::{Deref, DerefMut};
+use std::path::Path;
 
 mod impls;
 
+/// Messages that have a defined packed length
+pub trait SizeableMessage {
+    /// Packed length of the message
+    fn packed_len(&self) -> usize;
+}
+
 /// Define a type that can be packed into a writer.
-pub trait Packable: Sized {
+pub trait Packable: Sized + SizeableMessage {
     /// Pack the type into a writer
     fn pack<W>(&self, packer: W) -> io::Result<usize>
     where
@@ -24,6 +34,32 @@ pub trait MessagePacker {
     fn pack<P>(&mut self, package: P) -> io::Result<usize>
     where
         P: Packable;
+
+    /// Use the packer by ref
+    fn by_ref(&mut self) -> &mut Self {
+        self
+    }
+
+    /// Pack all items of the iterator
+    fn pack_all<I, P>(&mut self, mut iter: I) -> io::Result<usize>
+    where
+        P: Packable,
+        I: Iterator<Item = P>,
+    {
+        iter.try_fold(0, |n, p| Ok(n + self.pack(p)?))
+    }
+}
+
+impl<M> MessagePacker for &mut M
+where
+    M: MessagePacker,
+{
+    fn pack<P>(&mut self, package: P) -> io::Result<usize>
+    where
+        P: Packable,
+    {
+        <M as MessagePacker>::pack(self, package)
+    }
 }
 
 /// An unpacker implementation that can output messages
@@ -32,6 +68,237 @@ pub trait MessageUnpacker {
     fn unpack<P>(&mut self) -> io::Result<P>
     where
         P: Unpackable;
+
+    /// Use the unpacker by ref
+    fn by_ref(&mut self) -> &mut Self {
+        self
+    }
+}
+
+impl<M> MessageUnpacker for &mut M
+where
+    M: MessageUnpacker,
+{
+    fn unpack<P>(&mut self) -> io::Result<P>
+    where
+        P: Unpackable,
+    {
+        <M as MessageUnpacker>::unpack(self)
+    }
+}
+
+impl<R> MessageUnpacker for io::BufReader<R>
+where
+    R: io::Read,
+{
+    fn unpack<P>(&mut self) -> io::Result<P>
+    where
+        P: Unpackable,
+    {
+        P::unpack(self)
+    }
+}
+
+/// A buffered packer implementation
+#[derive(Debug)]
+pub struct BufferedUnpacker<R> {
+    buffer: io::BufReader<R>,
+}
+
+impl<R> BufferedUnpacker<R>
+where
+    R: io::Read,
+{
+    /// Create a new instance from an implementation of [`io::Read`]
+    pub fn from_reader(reader: R) -> Self {
+        io::BufReader::new(reader).into()
+    }
+}
+
+impl<R> From<io::BufReader<R>> for BufferedUnpacker<R> {
+    fn from(buffer: io::BufReader<R>) -> Self {
+        Self { buffer }
+    }
+}
+
+impl<R> Deref for BufferedUnpacker<R> {
+    type Target = io::BufReader<R>;
+
+    fn deref(&self) -> &Self::Target {
+        &self.buffer
+    }
+}
+
+impl<R> DerefMut for BufferedUnpacker<R> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.buffer
+    }
+}
+
+impl<R> Read for BufferedUnpacker<R>
+where
+    R: io::Read,
+{
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        self.buffer.read(buf)
+    }
+}
+
+impl<R> io::Seek for BufferedUnpacker<R>
+where
+    R: io::Seek,
+{
+    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
+        self.buffer.seek(pos)
+    }
+}
+
+impl<R> io::BufRead for BufferedUnpacker<R>
+where
+    R: io::Read,
+{
+    fn fill_buf(&mut self) -> io::Result<&[u8]> {
+        self.buffer.fill_buf()
+    }
+
+    fn consume(&mut self, amt: usize) {
+        self.buffer.consume(amt)
+    }
+}
+
+impl<R> MessageUnpacker for BufferedUnpacker<R>
+where
+    R: io::Read,
+{
+    fn unpack<P>(&mut self) -> io::Result<P>
+    where
+        P: Unpackable,
+    {
+        P::unpack(self)
+    }
+}
+
+/// Iterator helper of unpackable items
+///
+/// # Warning
+///
+/// The iterator will provide messages until [`io::ErrorKind::UnexpectedEof`].
+///
+/// If EOF happens in the middle of a valid message, this case will be ignored and the iterator
+/// will return `None`. This exception doesn't build a strong enough rule to compromise the
+/// ergonomics of the struct.
+///
+/// We might, in the future, create a `SizedMessageUnpacker` so we can trivially check if EOF
+/// corresponds to the expected EOF. However, in most use-cases, the underlying buffer will be of
+/// unknown size so this might not be used at all.
+pub struct UnpackableIter<I, P>
+where
+    I: MessageUnpacker,
+    P: Unpackable,
+{
+    unpacker: I,
+    _package: PhantomData<P>,
+}
+
+impl<I, P> From<I> for UnpackableIter<I, P>
+where
+    I: MessageUnpacker,
+    P: Unpackable,
+{
+    fn from(unpacker: I) -> Self {
+        Self {
+            unpacker,
+            _package: PhantomData,
+        }
+    }
+}
+
+impl<R, P> From<R> for UnpackableIter<io::BufReader<R>, P>
+where
+    R: Read,
+    P: Unpackable,
+{
+    fn from(reader: R) -> Self {
+        io::BufReader::new(reader).into()
+    }
+}
+
+impl<I, P> UnpackableIter<I, P>
+where
+    I: MessageUnpacker,
+    P: Unpackable,
+{
+    /// Unpack messages until EOF is hit
+    pub fn unpack_until_eof(&mut self) -> io::Result<Vec<P>>
+    where
+        P: Unpackable,
+    {
+        self.try_fold(vec![], |mut v, p| {
+            v.push(p?);
+
+            Ok(v)
+        })
+    }
+}
+
+impl<P> UnpackableIter<io::BufReader<fs::File>, P>
+where
+    P: Unpackable,
+{
+    /// Open a file as read-only to extract unpackable items
+    pub fn open_file<F>(path: F) -> io::Result<Self>
+    where
+        F: AsRef<Path>,
+    {
+        fs::OpenOptions::new().read(true).open(path).map(Self::from)
+    }
+}
+
+impl<I, P> Deref for UnpackableIter<I, P>
+where
+    I: MessageUnpacker,
+    P: Unpackable,
+{
+    type Target = I;
+
+    fn deref(&self) -> &Self::Target {
+        &self.unpacker
+    }
+}
+
+impl<I, P> DerefMut for UnpackableIter<I, P>
+where
+    I: MessageUnpacker,
+    P: Unpackable,
+{
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.unpacker
+    }
+}
+
+impl<I, P> Iterator for UnpackableIter<I, P>
+where
+    I: MessageUnpacker,
+    P: Unpackable,
+{
+    type Item = io::Result<P>;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        match self.unpack::<P>() {
+            Ok(p) => Some(Ok(p)),
+            Err(e) if e.kind() == io::ErrorKind::UnexpectedEof => None,
+            Err(e) => Some(Err(e)),
+        }
+    }
+}
+
+impl MessagePacker for fs::File {
+    fn pack<P>(&mut self, package: P) -> io::Result<usize>
+    where
+        P: Packable,
+    {
+        package.pack(self)
+    }
 }
 
 /// A packer/unpacker implementation with an underlying [`Cursor`]
@@ -40,6 +307,20 @@ pub struct CursorPacker<B> {
     cursor: Cursor<B>,
 }
 
+impl<B> Deref for CursorPacker<B> {
+    type Target = Cursor<B>;
+
+    fn deref(&self) -> &Self::Target {
+        &self.cursor
+    }
+}
+
+impl<B> DerefMut for CursorPacker<B> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.cursor
+    }
+}
+
 impl<B> From<Cursor<B>> for CursorPacker<B> {
     fn from(cursor: Cursor<B>) -> Self {
         Self { cursor }
@@ -59,6 +340,16 @@ impl<B> CursorPacker<B> {
     }
 }
 
+impl CursorPacker<Vec<u8>> {
+    /// Read file into buffer
+    pub fn from_file<P>(path: P) -> io::Result<Self>
+    where
+        P: AsRef<Path>,
+    {
+        fs::read(path).map(Self::new)
+    }
+}
+
 impl<B> Read for CursorPacker<B>
 where
     B: AsRef<[u8]>,
diff --git a/msgpacker/src/packer/impls.rs b/msgpacker/src/packer/impls.rs
index bcc8351..1cd9ba9 100644
--- a/msgpacker/src/packer/impls.rs
+++ b/msgpacker/src/packer/impls.rs
@@ -1,11 +1,21 @@
+use crate::consts::*;
 use crate::packer::{Packable, Unpackable};
 use crate::types::{Extension, ExtensionRef, Float, Integer, MapEntry, MapEntryRef};
 use crate::{Message, MessageRef};
 
 use std::io;
+use std::marker::PhantomData;
+
+use super::SizeableMessage;
 
 macro_rules! packable {
     ($t:ty) => {
+        impl SizeableMessage for $t {
+            fn packed_len(&self) -> usize {
+                MessageRef::from(self).packed_len()
+            }
+        }
+
         impl Packable for $t {
             fn pack<W>(&self, mut packer: W) -> io::Result<usize>
             where
@@ -28,6 +38,35 @@ macro_rules! packable {
 }
 
 macro_rules! packable_copy {
+    ($t:ty) => {
+        impl SizeableMessage for $t {
+            fn packed_len(&self) -> usize {
+                MessageRef::from(*self).packed_len()
+            }
+        }
+
+        impl Packable for $t {
+            fn pack<W>(&self, mut packer: W) -> io::Result<usize>
+            where
+                W: io::Write,
+            {
+                MessageRef::from(*self).pack(packer.by_ref())
+            }
+        }
+
+        impl Unpackable for $t {
+            fn unpack<R>(mut unpacker: R) -> io::Result<Self>
+            where
+                R: io::BufRead,
+            {
+                // Safety: The temporary message reference lives long enough until deserialize
+                unsafe { MessageRef::unpack(unpacker.by_ref()) }.and_then(MessageRef::try_into)
+            }
+        }
+    };
+}
+
+macro_rules! packable_copy_without_sizeable {
     ($t:ty) => {
         impl Packable for $t {
             fn pack<W>(&self, mut packer: W) -> io::Result<usize>
@@ -50,15 +89,77 @@ macro_rules! packable_copy {
     };
 }
 
+macro_rules! packable_vec_copy {
+    ($t:ty) => {
+        impl SizeableMessage for Vec<$t> {
+            fn packed_len(&self) -> usize {
+                let arr = self
+                    .iter()
+                    .map(|i| MessageRef::from(*i))
+                    .collect::<Vec<MessageRef<'_>>>();
+
+                MessageRef::Array(arr).packed_len()
+            }
+        }
+
+        impl Packable for Vec<$t> {
+            fn pack<W>(&self, mut packer: W) -> io::Result<usize>
+            where
+                W: io::Write,
+            {
+                let arr = self
+                    .iter()
+                    .map(|i| MessageRef::from(*i))
+                    .collect::<Vec<MessageRef<'_>>>();
+
+                MessageRef::Array(arr).pack(packer.by_ref())
+            }
+        }
+
+        impl Unpackable for Vec<$t> {
+            fn unpack<R>(mut unpacker: R) -> io::Result<Self>
+            where
+                R: io::BufRead,
+            {
+                // Safety: The temporary message reference lives long enough until deserialize
+                unsafe { MessageRef::unpack(unpacker.by_ref()) }?
+                    .as_array()
+                    .ok_or_else(|| {
+                        io::Error::new(io::ErrorKind::InvalidData, "expected vector of messages")
+                    })?
+                    .into_iter()
+                    .cloned()
+                    .map(MessageRef::try_into)
+                    .collect()
+            }
+        }
+    };
+}
+
 macro_rules! packable_vec {
     ($t:ty) => {
+        impl SizeableMessage for Vec<$t> {
+            fn packed_len(&self) -> usize {
+                let arr = self
+                    .iter()
+                    .map(MessageRef::from)
+                    .collect::<Vec<MessageRef<'_>>>();
+
+                MessageRef::Array(arr).packed_len()
+            }
+        }
+
         impl Packable for Vec<$t> {
             fn pack<W>(&self, mut packer: W) -> io::Result<usize>
             where
                 W: io::Write,
             {
-                self.iter()
-                    .try_fold(0, |s, m| Ok(s + m.pack(packer.by_ref())?))
+                let arr = self
+                    .iter()
+                    .map(MessageRef::from)
+                    .collect::<Vec<MessageRef<'_>>>();
+
+                MessageRef::Array(arr).pack(packer.by_ref())
             }
         }
 
@@ -82,7 +183,6 @@ macro_rules! packable_vec {
     };
 }
 
-packable_copy!(Integer);
 packable_copy!(u8);
 packable_copy!(u16);
 packable_copy!(u32);
@@ -94,29 +194,30 @@ packable_copy!(i32);
 packable_copy!(i64);
 packable_copy!(isize);
 packable_copy!(bool);
-packable_copy!(Float);
 packable_copy!(f32);
 packable_copy!(f64);
 packable_copy!(&str);
 packable_copy!(&[u8]);
+packable_copy_without_sizeable!(Integer);
+packable_copy_without_sizeable!(Float);
 packable!(String);
 packable!(Vec<u8>);
 packable!(Extension);
 
-packable_vec!(Integer);
-packable_vec!(u16);
-packable_vec!(u32);
-packable_vec!(u64);
-packable_vec!(usize);
-packable_vec!(i8);
-packable_vec!(i16);
-packable_vec!(i32);
-packable_vec!(i64);
-packable_vec!(isize);
-packable_vec!(bool);
-packable_vec!(Float);
-packable_vec!(f32);
-packable_vec!(f64);
+packable_vec_copy!(Integer);
+packable_vec_copy!(u16);
+packable_vec_copy!(u32);
+packable_vec_copy!(u64);
+packable_vec_copy!(usize);
+packable_vec_copy!(i8);
+packable_vec_copy!(i16);
+packable_vec_copy!(i32);
+packable_vec_copy!(i64);
+packable_vec_copy!(isize);
+packable_vec_copy!(bool);
+packable_vec_copy!(Float);
+packable_vec_copy!(f32);
+packable_vec_copy!(f64);
 packable_vec!(String);
 packable_vec!(Vec<u8>);
 packable_vec!(Extension);
@@ -139,13 +240,28 @@ impl Unpackable for Message {
     }
 }
 
+impl SizeableMessage for Vec<Message> {
+    fn packed_len(&self) -> usize {
+        let arr = self
+            .iter()
+            .map(Message::to_ref)
+            .collect::<Vec<MessageRef<'_>>>();
+
+        MessageRef::Array(arr).packed_len()
+    }
+}
+
 impl Packable for Vec<Message> {
     fn pack<W>(&self, mut packer: W) -> io::Result<usize>
     where
         W: io::Write,
     {
-        self.iter()
-            .try_fold(0, |s, m| Ok(s + m.pack(packer.by_ref())?))
+        let arr = self
+            .iter()
+            .map(Message::to_ref)
+            .collect::<Vec<MessageRef<'_>>>();
+
+        MessageRef::Array(arr).pack(packer.by_ref())
     }
 }
 
@@ -160,7 +276,7 @@ impl Unpackable for Vec<Message> {
                 .ok_or_else(|| {
                     io::Error::new(io::ErrorKind::InvalidData, "expected vector of messages")
                 })?
-                .into_iter()
+                .iter()
                 .cloned()
                 .map(|m| m.into_owned())
                 .collect()
@@ -458,152 +574,88 @@ impl<'a> From<ExtensionRef<'a>> for MessageRef<'a> {
     }
 }
 
-macro_rules! packable_array {
-    ($n:expr) => {
-        impl From<[u8; $n]> for Message {
-            fn from(b: [u8; $n]) -> Self {
-                Self::from(b.to_vec())
-            }
-        }
+impl<const N: usize> From<[u8; N]> for Message {
+    fn from(b: [u8; N]) -> Self {
+        Self::from(b.to_vec())
+    }
+}
 
-        impl<'a> From<&'a [u8; $n]> for MessageRef<'a> {
-            fn from(b: &'a [u8; $n]) -> Self {
-                MessageRef::from(&b[..])
-            }
-        }
+impl<'a, const N: usize> From<&'a [u8; N]> for MessageRef<'a> {
+    fn from(b: &'a [u8; N]) -> Self {
+        MessageRef::from(&b[..])
+    }
+}
 
-        impl TryFrom<Message> for [u8; $n] {
-            type Error = io::Error;
+impl<const N: usize> TryFrom<Message> for [u8; N] {
+    type Error = io::Error;
 
-            fn try_from(m: Message) -> Result<[u8; $n], Self::Error> {
-                m.as_bin()
-                    .ok_or_else(|| {
-                        io::Error::new(io::ErrorKind::InvalidData, "expected fixed array message")
-                    })
-                    .and_then(|b| {
-                        <[u8; $n]>::try_from(b).map_err(|_| {
-                            io::Error::new(
-                                io::ErrorKind::InvalidData,
-                                "expected fixed array message - invalid len",
-                            )
-                        })
-                    })
-            }
-        }
+    fn try_from(m: Message) -> Result<[u8; N], Self::Error> {
+        m.as_bin()
+            .ok_or_else(|| {
+                io::Error::new(io::ErrorKind::InvalidData, "expected fixed array message")
+            })
+            .and_then(|b| {
+                <[u8; N]>::try_from(b).map_err(|_| {
+                    io::Error::new(
+                        io::ErrorKind::InvalidData,
+                        "expected fixed array message - invalid len",
+                    )
+                })
+            })
+    }
+}
 
-        impl<'a> TryFrom<MessageRef<'a>> for [u8; $n] {
-            type Error = io::Error;
+impl<'a, const N: usize> TryFrom<MessageRef<'a>> for [u8; N] {
+    type Error = io::Error;
 
-            fn try_from(m: MessageRef<'a>) -> Result<[u8; $n], Self::Error> {
-                m.as_bin()
-                    .ok_or_else(|| {
-                        io::Error::new(io::ErrorKind::InvalidData, "expected fixed array message")
-                    })
-                    .and_then(|b| {
-                        <[u8; $n]>::try_from(b).map_err(|_| {
-                            io::Error::new(
-                                io::ErrorKind::InvalidData,
-                                "expected fixed array message - invalid len",
-                            )
-                        })
-                    })
-            }
-        }
+    fn try_from(m: MessageRef<'a>) -> Result<[u8; N], Self::Error> {
+        m.as_bin()
+            .ok_or_else(|| {
+                io::Error::new(io::ErrorKind::InvalidData, "expected fixed array message")
+            })
+            .and_then(|b| {
+                <[u8; N]>::try_from(b).map_err(|_| {
+                    io::Error::new(
+                        io::ErrorKind::InvalidData,
+                        "expected fixed array message - invalid len",
+                    )
+                })
+            })
+    }
+}
 
-        impl Packable for [u8; $n] {
-            fn pack<W>(&self, mut packer: W) -> io::Result<usize>
-            where
-                W: io::Write,
-            {
-                MessageRef::from(&self[..]).pack(packer.by_ref())
-            }
-        }
+impl<const N: usize> SizeableMessage for [u8; N] {
+    fn packed_len(&self) -> usize {
+        MessageRef::from(&self[..]).packed_len()
+    }
+}
 
-        impl Unpackable for [u8; $n] {
-            fn unpack<R>(mut unpacker: R) -> io::Result<Self>
-            where
-                R: io::BufRead,
-            {
-                // Safety: The temporary message reference lives long enough until deserialize
-                unsafe { MessageRef::unpack(unpacker.by_ref()) }.and_then(MessageRef::try_into)
-            }
-        }
-    };
+impl<const N: usize> Packable for [u8; N] {
+    fn pack<W>(&self, mut packer: W) -> io::Result<usize>
+    where
+        W: io::Write,
+    {
+        MessageRef::from(&self[..]).pack(packer.by_ref())
+    }
 }
 
-packable_array!(1);
-packable_array!(2);
-packable_array!(3);
-packable_array!(4);
-packable_array!(5);
-packable_array!(6);
-packable_array!(7);
-packable_array!(8);
-packable_array!(9);
-packable_array!(10);
-packable_array!(11);
-packable_array!(12);
-packable_array!(13);
-packable_array!(14);
-packable_array!(15);
-packable_array!(16);
-packable_array!(17);
-packable_array!(18);
-packable_array!(19);
-packable_array!(20);
-packable_array!(21);
-packable_array!(22);
-packable_array!(23);
-packable_array!(24);
-packable_array!(25);
-packable_array!(26);
-packable_array!(27);
-packable_array!(28);
-packable_array!(29);
-packable_array!(30);
-packable_array!(31);
-packable_array!(32);
-packable_array!(33);
-packable_array!(34);
-packable_array!(35);
-packable_array!(36);
-packable_array!(37);
-packable_array!(38);
-packable_array!(39);
-packable_array!(40);
-packable_array!(41);
-packable_array!(42);
-packable_array!(43);
-packable_array!(44);
-packable_array!(45);
-packable_array!(46);
-packable_array!(47);
-packable_array!(48);
-packable_array!(49);
-packable_array!(50);
-packable_array!(51);
-packable_array!(52);
-packable_array!(53);
-packable_array!(54);
-packable_array!(55);
-packable_array!(56);
-packable_array!(57);
-packable_array!(58);
-packable_array!(59);
-packable_array!(60);
-packable_array!(61);
-packable_array!(62);
-packable_array!(63);
-packable_array!(64);
+impl<const N: usize> Unpackable for [u8; N] {
+    fn unpack<R>(mut unpacker: R) -> io::Result<Self>
+    where
+        R: io::BufRead,
+    {
+        // Safety: The temporary message reference lives long enough until deserialize
+        unsafe { MessageRef::unpack(unpacker.by_ref()) }.and_then(MessageRef::try_into)
+    }
+}
 
 impl TryFrom<Message> for Integer {
     type Error = io::Error;
 
     fn try_from(message: Message) -> Result<Self, Self::Error> {
-        message.as_integer().ok_or(io::Error::new(
-            io::ErrorKind::InvalidData,
-            "expected integer message",
-        ))
+        message
+            .as_integer()
+            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "expected integer message"))
     }
 }
 
@@ -611,10 +663,9 @@ impl<'a> TryFrom<MessageRef<'a>> for Integer {
     type Error = io::Error;
 
     fn try_from(message: MessageRef<'a>) -> Result<Self, Self::Error> {
-        message.as_integer().ok_or(io::Error::new(
-            io::ErrorKind::InvalidData,
-            "expected integer message",
-        ))
+        message
+            .as_integer()
+            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "expected integer message"))
     }
 }
 
@@ -625,10 +676,7 @@ impl TryFrom<Message> for u8 {
         message
             .as_integer()
             .map(|i| i.as_unsigned() as u8)
-            .ok_or(io::Error::new(
-                io::ErrorKind::InvalidData,
-                "expected byte message",
-            ))
+            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "expected byte message"))
     }
 }
 
@@ -639,10 +687,7 @@ impl<'a> TryFrom<MessageRef<'a>> for u8 {
         message
             .as_integer()
             .map(|i| i.as_unsigned() as u8)
-            .ok_or(io::Error::new(
-                io::ErrorKind::InvalidData,
-                "expected byte message",
-            ))
+            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "expected byte message"))
     }
 }
 
@@ -653,10 +698,7 @@ impl TryFrom<Message> for u16 {
         message
             .as_integer()
             .map(|i| i.as_unsigned() as u16)
-            .ok_or(io::Error::new(
-                io::ErrorKind::InvalidData,
-                "expected u16 message",
-            ))
+            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "expected u16 message"))
     }
 }
 
@@ -667,10 +709,7 @@ impl<'a> TryFrom<MessageRef<'a>> for u16 {
         message
             .as_integer()
             .map(|i| i.as_unsigned() as u16)
-            .ok_or(io::Error::new(
-                io::ErrorKind::InvalidData,
-                "expected u16 message",
-            ))
+            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "expected u16 message"))
     }
 }
 
@@ -681,10 +720,7 @@ impl TryFrom<Message> for u32 {
         message
             .as_integer()
             .map(|i| i.as_unsigned() as u32)
-            .ok_or(io::Error::new(
-                io::ErrorKind::InvalidData,
-                "expected u32 message",
-            ))
+            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "expected u32 message"))
     }
 }
 
@@ -695,10 +731,7 @@ impl<'a> TryFrom<MessageRef<'a>> for u32 {
         message
             .as_integer()
             .map(|i| i.as_unsigned() as u32)
-            .ok_or(io::Error::new(
-                io::ErrorKind::InvalidData,
-                "expected u32 message",
-            ))
+            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "expected u32 message"))
     }
 }
 
@@ -709,10 +742,7 @@ impl TryFrom<Message> for u64 {
         message
             .as_integer()
             .map(|i| i.as_unsigned() as u64)
-            .ok_or(io::Error::new(
-                io::ErrorKind::InvalidData,
-                "expected u64 message",
-            ))
+            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "expected u64 message"))
     }
 }
 
@@ -723,10 +753,7 @@ impl<'a> TryFrom<MessageRef<'a>> for u64 {
         message
             .as_integer()
             .map(|i| i.as_unsigned() as u64)
-            .ok_or(io::Error::new(
-                io::ErrorKind::InvalidData,
-                "expected u64 message",
-            ))
+            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "expected u64 message"))
     }
 }
 
@@ -737,10 +764,7 @@ impl TryFrom<Message> for usize {
         message
             .as_integer()
             .map(|i| i.as_unsigned() as usize)
-            .ok_or(io::Error::new(
-                io::ErrorKind::InvalidData,
-                "expected usize message",
-            ))
+            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "expected usize message"))
     }
 }
 
@@ -751,10 +775,7 @@ impl<'a> TryFrom<MessageRef<'a>> for usize {
         message
             .as_integer()
             .map(|i| i.as_unsigned() as usize)
-            .ok_or(io::Error::new(
-                io::ErrorKind::InvalidData,
-                "expected usize message",
-            ))
+            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "expected usize message"))
     }
 }
 
@@ -765,10 +786,9 @@ impl TryFrom<Message> for i8 {
         message
             .as_integer()
             .map(|i| i.as_signed() as i8)
-            .ok_or(io::Error::new(
-                io::ErrorKind::InvalidData,
-                "expected signed byte message",
-            ))
+            .ok_or_else(|| {
+                io::Error::new(io::ErrorKind::InvalidData, "expected signed byte message")
+            })
     }
 }
 
@@ -779,10 +799,9 @@ impl<'a> TryFrom<MessageRef<'a>> for i8 {
         message
             .as_integer()
             .map(|i| i.as_signed() as i8)
-            .ok_or(io::Error::new(
-                io::ErrorKind::InvalidData,
-                "expected signed byte message",
-            ))
+            .ok_or_else(|| {
+                io::Error::new(io::ErrorKind::InvalidData, "expected signed byte message")
+            })
     }
 }
 
@@ -793,10 +812,7 @@ impl TryFrom<Message> for i16 {
         message
             .as_integer()
             .map(|i| i.as_signed() as i16)
-            .ok_or(io::Error::new(
-                io::ErrorKind::InvalidData,
-                "expected i16 message",
-            ))
+            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "expected i16 message"))
     }
 }
 
@@ -807,10 +823,7 @@ impl<'a> TryFrom<MessageRef<'a>> for i16 {
         message
             .as_integer()
             .map(|i| i.as_signed() as i16)
-            .ok_or(io::Error::new(
-                io::ErrorKind::InvalidData,
-                "expected i16 message",
-            ))
+            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "expected i16 message"))
     }
 }
 
@@ -821,10 +834,7 @@ impl TryFrom<Message> for i32 {
         message
             .as_integer()
             .map(|i| i.as_signed() as i32)
-            .ok_or(io::Error::new(
-                io::ErrorKind::InvalidData,
-                "expected i32 message",
-            ))
+            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "expected i32 message"))
     }
 }
 
@@ -835,10 +845,7 @@ impl<'a> TryFrom<MessageRef<'a>> for i32 {
         message
             .as_integer()
             .map(|i| i.as_signed() as i32)
-            .ok_or(io::Error::new(
-                io::ErrorKind::InvalidData,
-                "expected i32 message",
-            ))
+            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "expected i32 message"))
     }
 }
 
@@ -849,10 +856,7 @@ impl TryFrom<Message> for i64 {
         message
             .as_integer()
             .map(|i| i.as_signed() as i64)
-            .ok_or(io::Error::new(
-                io::ErrorKind::InvalidData,
-                "expected i64 message",
-            ))
+            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "expected i64 message"))
     }
 }
 
@@ -863,10 +867,7 @@ impl<'a> TryFrom<MessageRef<'a>> for i64 {
         message
             .as_integer()
             .map(|i| i.as_signed() as i64)
-            .ok_or(io::Error::new(
-                io::ErrorKind::InvalidData,
-                "expected i64 message",
-            ))
+            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "expected i64 message"))
     }
 }
 
@@ -877,10 +878,7 @@ impl TryFrom<Message> for isize {
         message
             .as_integer()
             .map(|i| i.as_signed() as isize)
-            .ok_or(io::Error::new(
-                io::ErrorKind::InvalidData,
-                "expected isize message",
-            ))
+            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "expected isize message"))
     }
 }
 
@@ -891,10 +889,7 @@ impl<'a> TryFrom<MessageRef<'a>> for isize {
         message
             .as_integer()
             .map(|i| i.as_signed() as isize)
-            .ok_or(io::Error::new(
-                io::ErrorKind::InvalidData,
-                "expected isize message",
-            ))
+            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "expected isize message"))
     }
 }
 
@@ -902,10 +897,9 @@ impl TryFrom<Message> for bool {
     type Error = io::Error;
 
     fn try_from(message: Message) -> Result<Self, Self::Error> {
-        message.as_boolean().ok_or(io::Error::new(
-            io::ErrorKind::InvalidData,
-            "expected bool message",
-        ))
+        message
+            .as_boolean()
+            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "expected bool message"))
     }
 }
 
@@ -913,10 +907,9 @@ impl<'a> TryFrom<MessageRef<'a>> for bool {
     type Error = io::Error;
 
     fn try_from(message: MessageRef<'a>) -> Result<Self, Self::Error> {
-        message.as_boolean().ok_or(io::Error::new(
-            io::ErrorKind::InvalidData,
-            "expected bool message",
-        ))
+        message
+            .as_boolean()
+            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "expected bool message"))
     }
 }
 
@@ -924,10 +917,9 @@ impl TryFrom<Message> for Float {
     type Error = io::Error;
 
     fn try_from(message: Message) -> Result<Self, Self::Error> {
-        message.as_float().ok_or(io::Error::new(
-            io::ErrorKind::InvalidData,
-            "expected float message",
-        ))
+        message
+            .as_float()
+            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "expected float message"))
     }
 }
 
@@ -935,10 +927,9 @@ impl<'a> TryFrom<MessageRef<'a>> for Float {
     type Error = io::Error;
 
     fn try_from(message: MessageRef<'a>) -> Result<Self, Self::Error> {
-        message.as_float().ok_or(io::Error::new(
-            io::ErrorKind::InvalidData,
-            "expected float message",
-        ))
+        message
+            .as_float()
+            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "expected float message"))
     }
 }
 
@@ -949,10 +940,7 @@ impl TryFrom<Message> for f32 {
         message
             .as_float()
             .and_then(|f| f.as_f32())
-            .ok_or(io::Error::new(
-                io::ErrorKind::InvalidData,
-                "expected f32 message",
-            ))
+            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "expected f32 message"))
     }
 }
 
@@ -963,10 +951,7 @@ impl<'a> TryFrom<MessageRef<'a>> for f32 {
         message
             .as_float()
             .and_then(|f| f.as_f32())
-            .ok_or(io::Error::new(
-                io::ErrorKind::InvalidData,
-                "expected f32 message",
-            ))
+            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "expected f32 message"))
     }
 }
 
@@ -977,10 +962,7 @@ impl TryFrom<Message> for f64 {
         message
             .as_float()
             .and_then(|f| f.as_f64())
-            .ok_or(io::Error::new(
-                io::ErrorKind::InvalidData,
-                "expected f64 message",
-            ))
+            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "expected f64 message"))
     }
 }
 
@@ -991,10 +973,7 @@ impl<'a> TryFrom<MessageRef<'a>> for f64 {
         message
             .as_float()
             .and_then(|f| f.as_f64())
-            .ok_or(io::Error::new(
-                io::ErrorKind::InvalidData,
-                "expected f64 message",
-            ))
+            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "expected f64 message"))
     }
 }
 
@@ -1005,10 +984,7 @@ impl TryFrom<Message> for String {
         message
             .as_string()
             .map(|s| s.to_owned())
-            .ok_or(io::Error::new(
-                io::ErrorKind::InvalidData,
-                "expected string message",
-            ))
+            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "expected string message"))
     }
 }
 
@@ -1016,10 +992,9 @@ impl<'a> TryFrom<MessageRef<'a>> for &'a str {
     type Error = io::Error;
 
     fn try_from(message: MessageRef<'a>) -> Result<Self, Self::Error> {
-        message.as_string().ok_or(io::Error::new(
-            io::ErrorKind::InvalidData,
-            "expected string message",
-        ))
+        message
+            .as_string()
+            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "expected string message"))
     }
 }
 
@@ -1030,10 +1005,7 @@ impl<'a> TryFrom<MessageRef<'a>> for String {
         message
             .as_string()
             .map(|s| s.to_owned())
-            .ok_or(io::Error::new(
-                io::ErrorKind::InvalidData,
-                "expected string message",
-            ))
+            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "expected string message"))
     }
 }
 
@@ -1041,10 +1013,10 @@ impl TryFrom<Message> for Vec<u8> {
     type Error = io::Error;
 
     fn try_from(message: Message) -> Result<Self, Self::Error> {
-        message.as_bin().map(|s| s.to_owned()).ok_or(io::Error::new(
-            io::ErrorKind::InvalidData,
-            "expected binary message",
-        ))
+        message
+            .as_bin()
+            .map(|s| s.to_owned())
+            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "expected binary message"))
     }
 }
 
@@ -1052,10 +1024,9 @@ impl<'a> TryFrom<MessageRef<'a>> for &'a [u8] {
     type Error = io::Error;
 
     fn try_from(message: MessageRef<'a>) -> Result<Self, Self::Error> {
-        message.as_bin().ok_or(io::Error::new(
-            io::ErrorKind::InvalidData,
-            "expected binary message",
-        ))
+        message
+            .as_bin()
+            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "expected binary message"))
     }
 }
 
@@ -1063,10 +1034,10 @@ impl<'a> TryFrom<MessageRef<'a>> for Vec<u8> {
     type Error = io::Error;
 
     fn try_from(message: MessageRef<'a>) -> Result<Self, Self::Error> {
-        message.as_bin().map(|s| s.to_owned()).ok_or(io::Error::new(
-            io::ErrorKind::InvalidData,
-            "expected binary message",
-        ))
+        message
+            .as_bin()
+            .map(|s| s.to_owned())
+            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "expected binary message"))
     }
 }
 
@@ -1115,3 +1086,204 @@ impl<'a> FromIterator<MapEntryRef<'a>> for MessageRef<'a> {
         iter.into_iter().collect::<Vec<MapEntryRef<'a>>>().into()
     }
 }
+
+impl SizeableMessage for () {
+    fn packed_len(&self) -> usize {
+        0
+    }
+}
+
+impl Packable for () {
+    fn pack<W>(&self, _packer: W) -> io::Result<usize>
+    where
+        W: io::Write,
+    {
+        Ok(0)
+    }
+}
+
+impl<T> SizeableMessage for PhantomData<T> {
+    fn packed_len(&self) -> usize {
+        0
+    }
+}
+
+impl<T> Packable for PhantomData<T> {
+    fn pack<W>(&self, _packer: W) -> io::Result<usize>
+    where
+        W: io::Write,
+    {
+        Ok(0)
+    }
+}
+
+impl<T> SizeableMessage for Option<T>
+where
+    T: SizeableMessage,
+{
+    fn packed_len(&self) -> usize {
+        match self {
+            Some(t) => OPTION_SOME.packed_len() + t.packed_len(),
+            None => OPTION_NONE.packed_len(),
+        }
+    }
+}
+
+impl<T> Packable for Option<T>
+where
+    T: Packable,
+{
+    fn pack<W>(&self, mut packer: W) -> io::Result<usize>
+    where
+        W: io::Write,
+    {
+        match self {
+            Some(t) => Ok(OPTION_SOME.pack(packer.by_ref())? + t.pack(packer.by_ref())?),
+            None => OPTION_NONE.pack(packer.by_ref()),
+        }
+    }
+}
+
+impl<T, E> SizeableMessage for Result<T, E>
+where
+    T: SizeableMessage,
+    E: SizeableMessage,
+{
+    fn packed_len(&self) -> usize {
+        match self {
+            Ok(t) => RESULT_OK.packed_len() + t.packed_len(),
+            Err(e) => RESULT_ERR.packed_len() + e.packed_len(),
+        }
+    }
+}
+
+impl<T, E> Packable for Result<T, E>
+where
+    T: Packable,
+    E: Packable,
+{
+    fn pack<W>(&self, mut packer: W) -> io::Result<usize>
+    where
+        W: io::Write,
+    {
+        match self {
+            Ok(t) => Ok(RESULT_OK.pack(packer.by_ref())? + t.pack(packer.by_ref())?),
+            Err(e) => Ok(RESULT_ERR.pack(packer.by_ref())? + e.pack(packer.by_ref())?),
+        }
+    }
+}
+
+impl Unpackable for () {
+    fn unpack<R>(_unpacker: R) -> io::Result<Self>
+    where
+        R: io::BufRead,
+    {
+        Ok(())
+    }
+}
+
+impl<T> Unpackable for PhantomData<T> {
+    fn unpack<R>(_unpacker: R) -> io::Result<Self>
+    where
+        R: io::BufRead,
+    {
+        Ok(PhantomData)
+    }
+}
+
+impl<T> Unpackable for Option<T>
+where
+    T: Unpackable,
+{
+    fn unpack<R>(mut unpacker: R) -> io::Result<Self>
+    where
+        R: io::BufRead,
+    {
+        <isize as Unpackable>::unpack(unpacker.by_ref()).and_then(|r| match r {
+            OPTION_SOME => Some(T::unpack(unpacker.by_ref())).transpose(),
+            OPTION_NONE => Ok(None),
+            _ => Err(io::Error::new(
+                io::ErrorKind::InvalidData,
+                "expected option representation",
+            )),
+        })
+    }
+}
+
+impl<T, E> Unpackable for Result<T, E>
+where
+    T: Unpackable,
+    E: Unpackable,
+{
+    fn unpack<R>(mut unpacker: R) -> io::Result<Self>
+    where
+        R: io::BufRead,
+    {
+        <isize as Unpackable>::unpack(unpacker.by_ref()).and_then(|r| match r {
+            RESULT_OK => T::unpack(unpacker.by_ref()).map(|t| Ok(t)),
+            RESULT_ERR => E::unpack(unpacker.by_ref()).map(|e| Err(e)),
+            _ => Err(io::Error::new(
+                io::ErrorKind::InvalidData,
+                "expected result representation",
+            )),
+        })
+    }
+}
+
+macro_rules! tuple {
+    ( $($name:ident)+) => (
+        #[allow(non_snake_case)]
+        impl<$($name,)+> SizeableMessage for ($($name,)+)
+        where $($name: SizeableMessage,)+
+        {
+            fn packed_len(&self) -> usize {
+                let ($(ref $name,)+) = *self;
+
+                0 $( + $name.packed_len())+
+            }
+        }
+
+        #[allow(non_snake_case)]
+        impl<$($name,)+> Packable for ($($name,)+)
+        where $($name: Packable,)+
+        {
+            fn pack<W>(&self, mut packer: W) -> io::Result<usize>
+            where
+                W: io::Write,
+            {
+                let ($(ref $name,)+) = *self;
+
+                Ok(0 $( + $name.pack(packer.by_ref())?)+)
+            }
+        }
+
+        #[allow(non_snake_case)]
+        impl<$($name,)+> Unpackable for ($($name,)+)
+        where $($name: Unpackable,)+
+        {
+            fn unpack<R>(mut unpacker: R) -> io::Result<Self>
+            where
+                R: io::BufRead,
+            {
+                Ok(($($name::unpack(unpacker.by_ref())?,)+))
+            }
+        }
+    );
+}
+
+tuple! { A }
+tuple! { A B }
+tuple! { A B C }
+tuple! { A B C D }
+tuple! { A B C D E }
+tuple! { A B C D E F }
+tuple! { A B C D E F G }
+tuple! { A B C D E F G H }
+tuple! { A B C D E F G H I }
+tuple! { A B C D E F G H I J }
+tuple! { A B C D E F G H I J K }
+tuple! { A B C D E F G H I J K L }
+tuple! { A B C D E F G H I J K L M }
+tuple! { A B C D E F G H I J K L M N }
+tuple! { A B C D E F G H I J K L M N O }
+tuple! { A B C D E F G H I J K L M N O P }
diff --git a/msgpacker/tests/pack_unpack.rs b/msgpacker/tests/pack_unpack.rs
index bbb98f7..4de5aeb 100644
--- a/msgpacker/tests/pack_unpack.rs
+++ b/msgpacker/tests/pack_unpack.rs
@@ -19,6 +19,7 @@ fn pack_unpack() -> io::Result<()> {
         Message::Integer(Integer::signed(i16::MIN as i64)),
         Message::Integer(Integer::signed(i8::MIN as i64 - 1)),
         Message::Integer(Integer::signed(i8::MIN as i64)),
+        Message::Integer(Integer::signed(-33)),
         Message::Integer(Integer::signed(-32)),
         Message::Integer(Integer::signed(-1)),
         Message::Integer(Integer::unsigned(0u64)),
