diff --git a/benches/encoding.rs b/benches/encoding.rs
index 6e0fc43649f706d421b64d722f87d06642d4d55a..9eb02b355db134ccc268c2dd34c0fbf622f06a6d 100644
--- a/benches/encoding.rs
+++ b/benches/encoding.rs
@@ -21,7 +21,7 @@ fn benchmark_encoding(c: &mut Criterion) {
 
     group.bench_function("encode_rle", |b| {
         b.iter(|| {
-            let encoded = encode_rle(black_box(&data));
+            let encoded = encode_rle(black_box(&data)).unwrap();
             black_box(encoded);
         })
     });
@@ -39,7 +39,7 @@ fn benchmark_encoding(c: &mut Criterion) {
 fn benchmark_decoding(c: &mut Criterion) {
     let data = generate_data(10_000_000_usize);
     let encoded_huffman = encode_huffman(black_box(&data)).unwrap();
-    let encoded_rle = encode_rle(black_box(&data));
+    let encoded_rle = encode_rle(black_box(&data)).unwrap();
     let encoded_zippy = encode_zippy(black_box(&data), None, None).unwrap();
 
     let mut group = c.benchmark_group("decoding");
@@ -54,7 +54,7 @@ fn benchmark_decoding(c: &mut Criterion) {
 
     group.bench_function("decode_rle", |b| {
         b.iter(|| {
-            let decoded = decode_rle(black_box(&encoded_rle));
+            let decoded = decode_rle(black_box(&encoded_rle)).unwrap();
             black_box(decoded);
         })
     });
diff --git a/crates/encoding/src/cipher.rs b/crates/encoding/src/cipher.rs
index f4776f4f24a20ca4ab7cedb3812110c4b4208719..cb35d4806539cb286f6f1d10791e4c8b550fadc0 100644
--- a/crates/encoding/src/cipher.rs
+++ b/crates/encoding/src/cipher.rs
@@ -1,7 +1,9 @@
+use boytacean_common::error::Error;
+
 pub trait Cipher {
     type EncryptOptions;
     type DecryptOptions;
 
-    fn encrypt(data: &mut [u8], key: &[u8], options: &Self::EncryptOptions);
-    fn decrypt(data: &mut [u8], key: &[u8], options: &Self::DecryptOptions);
+    fn encrypt(data: &mut [u8], key: &[u8], options: &Self::EncryptOptions) -> Result<(), Error>;
+    fn decrypt(data: &mut [u8], key: &[u8], options: &Self::DecryptOptions) -> Result<(), Error>;
 }
diff --git a/crates/encoding/src/codec.rs b/crates/encoding/src/codec.rs
index ec6a30510919b52ff8738170bf5799c12138c31d..7c80d48b4edc14e98d2555b3e3c846834ec14e40 100644
--- a/crates/encoding/src/codec.rs
+++ b/crates/encoding/src/codec.rs
@@ -1,7 +1,9 @@
+use boytacean_common::error::Error;
+
 pub trait Codec {
     type EncodeOptions;
     type DecodeOptions;
 
-    fn encode(data: &[u8], options: &Self::EncodeOptions) -> Vec<u8>;
-    fn decode(data: &[u8], options: &Self::DecodeOptions) -> Vec<u8>;
+    fn encode(data: &[u8], options: &Self::EncodeOptions) -> Result<Vec<u8>, Error>;
+    fn decode(data: &[u8], options: &Self::DecodeOptions) -> Result<Vec<u8>, Error>;
 }
diff --git a/crates/encoding/src/huffman.rs b/crates/encoding/src/huffman.rs
index b75e6fcf3d75ee7e7af8120f0ee543f427634197..9ee530f3a4361b2c841fd9c647b05a95f63d5fc7 100644
--- a/crates/encoding/src/huffman.rs
+++ b/crates/encoding/src/huffman.rs
@@ -6,6 +6,8 @@ use std::{
     mem::size_of,
 };
 
+use crate::codec::Codec;
+
 #[derive(Debug, Eq, PartialEq)]
 struct Node {
     frequency: u32,
@@ -26,210 +28,227 @@ impl PartialOrd for Node {
     }
 }
 
-pub fn encode_huffman(data: &[u8]) -> Result<Vec<u8>, Error> {
-    let frequency_map = build_frequency(data);
-    let tree = build_tree(&frequency_map)
-        .ok_or(Error::CustomError(String::from("Failed to build tree")))?;
-
-    let mut codes = vec![Vec::new(); 256];
-    build_codes(&tree, Vec::new(), &mut codes);
+pub struct Huffman;
 
-    let encoded_tree = encode_tree(&tree);
-    let encoded_data = encode_data(data, &codes);
-    let tree_length = encoded_tree.len() as u32;
-    let data_length = data.len() as u64;
+impl Huffman {
+    fn build_frequency(data: &[u8]) -> [u32; 256] {
+        let mut frequency_map = [0_u32; 256];
+        for &byte in data {
+            frequency_map[byte as usize] += 1;
+        }
+        frequency_map
+    }
 
-    let mut result = Vec::new();
-    result.extend(tree_length.to_be_bytes());
-    result.extend(encoded_tree);
-    result.extend(data_length.to_be_bytes());
-    result.extend(encoded_data);
+    fn build_tree(frequency_map: &[u32; 256]) -> Option<Box<Node>> {
+        let mut heap: BinaryHeap<Box<Node>> = BinaryHeap::new();
 
-    Ok(result)
-}
+        for (byte, &frequency) in frequency_map.iter().enumerate() {
+            if frequency == 0 {
+                continue;
+            }
+            heap.push(Box::new(Node {
+                frequency,
+                character: Some(byte as u8),
+                left: None,
+                right: None,
+            }));
+        }
 
-pub fn decode_huffman(data: &[u8]) -> Result<Vec<u8>, Error> {
-    let mut reader = Cursor::new(data);
+        while heap.len() > 1 {
+            let left = heap.pop().unwrap();
+            let right = heap.pop().unwrap();
 
-    let mut buffer = [0x00; size_of::<u32>()];
-    reader.read_exact(&mut buffer)?;
-    let tree_length = u32::from_be_bytes(buffer);
+            let merged = Box::new(Node {
+                frequency: left.frequency + right.frequency,
+                character: None,
+                left: Some(left),
+                right: Some(right),
+            });
 
-    let mut buffer = vec![0; tree_length as usize];
-    reader.read_exact(&mut buffer)?;
-    let tree = decode_tree(&mut buffer.as_slice());
+            heap.push(merged);
+        }
 
-    let mut buffer = [0x00; size_of::<u64>()];
-    reader.read_exact(&mut buffer)?;
-    let data_length = u64::from_be_bytes(buffer);
+        heap.pop()
+    }
 
-    let mut buffer =
-        vec![0; data.len() - size_of::<u32>() - tree_length as usize - size_of::<u64>()];
-    reader.read_exact(&mut buffer)?;
+    fn build_codes(node: &Node, prefix: Vec<u8>, codes: &mut [Vec<u8>]) {
+        if let Some(character) = node.character {
+            codes[character as usize] = prefix;
+        } else {
+            if let Some(ref left) = node.left {
+                let mut left_prefix = prefix.clone();
+                left_prefix.push(0);
+                Self::build_codes(left, left_prefix, codes);
+            }
+            if let Some(ref right) = node.right {
+                let mut right_prefix = prefix;
+                right_prefix.push(1);
+                Self::build_codes(right, right_prefix, codes);
+            }
+        }
+    }
 
-    let result = decode_data(&buffer, &tree, data_length);
+    fn encode_data(data: &[u8], codes: &[Vec<u8>]) -> Vec<u8> {
+        let mut bit_buffer = Vec::new();
+        let mut current_byte = 0u8;
+        let mut bit_count = 0;
+
+        for &byte in data {
+            let code = &codes[byte as usize];
+            for &bit in code {
+                current_byte <<= 1;
+                if bit == 1 {
+                    current_byte |= 1;
+                }
+                bit_count += 1;
+
+                if bit_count == 8 {
+                    bit_buffer.push(current_byte);
+                    current_byte = 0;
+                    bit_count = 0;
+                }
+            }
+        }
 
-    Ok(result)
-}
+        if bit_count > 0 {
+            current_byte <<= 8 - bit_count;
+            bit_buffer.push(current_byte);
+        }
 
-fn build_frequency(data: &[u8]) -> [u32; 256] {
-    let mut frequency_map = [0_u32; 256];
-    for &byte in data {
-        frequency_map[byte as usize] += 1;
+        bit_buffer
     }
-    frequency_map
-}
 
-fn build_tree(frequency_map: &[u32; 256]) -> Option<Box<Node>> {
-    let mut heap: BinaryHeap<Box<Node>> = BinaryHeap::new();
+    fn decode_data(encoded: &[u8], root: &Node, data_length: u64) -> Vec<u8> {
+        let mut decoded = Vec::new();
+        let mut current_node = root;
+        let mut bit_index = 0;
+
+        for &byte in encoded {
+            if decoded.len() as u64 == data_length {
+                break;
+            }
 
-    for (byte, &frequency) in frequency_map.iter().enumerate() {
-        if frequency == 0 {
-            continue;
+            for bit_offset in (0..8).rev() {
+                let bit = (byte >> bit_offset) & 1;
+                current_node = if bit == 0 {
+                    current_node.left.as_deref().unwrap()
+                } else {
+                    current_node.right.as_deref().unwrap()
+                };
+
+                if let Some(character) = current_node.character {
+                    decoded.push(character);
+                    current_node = root;
+                }
+
+                if decoded.len() as u64 == data_length {
+                    break;
+                }
+
+                bit_index += 1;
+                if bit_index == encoded.len() * 8 {
+                    break;
+                }
+            }
         }
-        heap.push(Box::new(Node {
-            frequency,
-            character: Some(byte as u8),
-            left: None,
-            right: None,
-        }));
+
+        decoded
     }
 
-    while heap.len() > 1 {
-        let left = heap.pop().unwrap();
-        let right = heap.pop().unwrap();
+    fn encode_tree(node: &Node) -> Vec<u8> {
+        let mut result = Vec::new();
+        if let Some(character) = node.character {
+            result.push(1);
+            result.push(character);
+        } else {
+            result.push(0);
+            if let Some(ref left) = node.left {
+                result.extend(Self::encode_tree(left));
+            }
+            if let Some(ref right) = node.right {
+                result.extend(Self::encode_tree(right));
+            }
+        }
+        result
+    }
 
-        let merged = Box::new(Node {
-            frequency: left.frequency + right.frequency,
+    fn decode_tree(data: &mut &[u8]) -> Box<Node> {
+        let mut node = Box::new(Node {
+            frequency: 0,
             character: None,
-            left: Some(left),
-            right: Some(right),
+            left: None,
+            right: None,
         });
 
-        heap.push(merged);
-    }
-
-    heap.pop()
-}
-
-fn build_codes(node: &Node, prefix: Vec<u8>, codes: &mut [Vec<u8>]) {
-    if let Some(character) = node.character {
-        codes[character as usize] = prefix;
-    } else {
-        if let Some(ref left) = node.left {
-            let mut left_prefix = prefix.clone();
-            left_prefix.push(0);
-            build_codes(left, left_prefix, codes);
-        }
-        if let Some(ref right) = node.right {
-            let mut right_prefix = prefix;
-            right_prefix.push(1);
-            build_codes(right, right_prefix, codes);
+        if data[0] == 1 {
+            node.character = Some(data[1]);
+            *data = &data[2..];
+        } else {
+            *data = &data[1..];
+            node.left = Some(Self::decode_tree(data));
+            node.right = Some(Self::decode_tree(data));
         }
+        node
     }
 }
 
-fn encode_data(data: &[u8], codes: &[Vec<u8>]) -> Vec<u8> {
-    let mut bit_buffer = Vec::new();
-    let mut current_byte = 0u8;
-    let mut bit_count = 0;
-
-    for &byte in data {
-        let code = &codes[byte as usize];
-        for &bit in code {
-            current_byte <<= 1;
-            if bit == 1 {
-                current_byte |= 1;
-            }
-            bit_count += 1;
+impl Codec for Huffman {
+    type EncodeOptions = ();
+    type DecodeOptions = ();
 
-            if bit_count == 8 {
-                bit_buffer.push(current_byte);
-                current_byte = 0;
-                bit_count = 0;
-            }
-        }
-    }
+    fn encode(data: &[u8], _options: &Self::EncodeOptions) -> Result<Vec<u8>, Error> {
+        let frequency_map = Self::build_frequency(data);
+        let tree = Self::build_tree(&frequency_map)
+            .ok_or(Error::CustomError(String::from("Failed to build tree")))?;
+
+        let mut codes = vec![Vec::new(); 256];
+        Self::build_codes(&tree, Vec::new(), &mut codes);
 
-    if bit_count > 0 {
-        current_byte <<= 8 - bit_count;
-        bit_buffer.push(current_byte);
+        let encoded_tree = Self::encode_tree(&tree);
+        let encoded_data = Self::encode_data(data, &codes);
+        let tree_length = encoded_tree.len() as u32;
+        let data_length = data.len() as u64;
+
+        let mut result = Vec::new();
+        result.extend(tree_length.to_be_bytes());
+        result.extend(encoded_tree);
+        result.extend(data_length.to_be_bytes());
+        result.extend(encoded_data);
+
+        Ok(result)
     }
 
-    bit_buffer
-}
+    fn decode(data: &[u8], _options: &Self::DecodeOptions) -> Result<Vec<u8>, Error> {
+        let mut reader = Cursor::new(data);
 
-fn decode_data(encoded: &[u8], root: &Node, data_length: u64) -> Vec<u8> {
-    let mut decoded = Vec::new();
-    let mut current_node = root;
-    let mut bit_index = 0;
+        let mut buffer = [0x00; size_of::<u32>()];
+        reader.read_exact(&mut buffer)?;
+        let tree_length = u32::from_be_bytes(buffer);
 
-    for &byte in encoded {
-        if decoded.len() as u64 == data_length {
-            break;
-        }
+        let mut buffer = vec![0; tree_length as usize];
+        reader.read_exact(&mut buffer)?;
+        let tree = Self::decode_tree(&mut buffer.as_slice());
 
-        for bit_offset in (0..8).rev() {
-            let bit = (byte >> bit_offset) & 1;
-            current_node = if bit == 0 {
-                current_node.left.as_deref().unwrap()
-            } else {
-                current_node.right.as_deref().unwrap()
-            };
-
-            if let Some(character) = current_node.character {
-                decoded.push(character);
-                current_node = root;
-            }
+        let mut buffer = [0x00; size_of::<u64>()];
+        reader.read_exact(&mut buffer)?;
+        let data_length = u64::from_be_bytes(buffer);
 
-            if decoded.len() as u64 == data_length {
-                break;
-            }
+        let mut buffer =
+            vec![0; data.len() - size_of::<u32>() - tree_length as usize - size_of::<u64>()];
+        reader.read_exact(&mut buffer)?;
 
-            bit_index += 1;
-            if bit_index == encoded.len() * 8 {
-                break;
-            }
-        }
-    }
+        let result = Self::decode_data(&buffer, &tree, data_length);
 
-    decoded
+        Ok(result)
+    }
 }
 
-fn encode_tree(node: &Node) -> Vec<u8> {
-    let mut result = Vec::new();
-    if let Some(character) = node.character {
-        result.push(1);
-        result.push(character);
-    } else {
-        result.push(0);
-        if let Some(ref left) = node.left {
-            result.extend(encode_tree(left));
-        }
-        if let Some(ref right) = node.right {
-            result.extend(encode_tree(right));
-        }
-    }
-    result
+pub fn encode_huffman(data: &[u8]) -> Result<Vec<u8>, Error> {
+    Huffman::encode(data, &())
 }
 
-fn decode_tree(data: &mut &[u8]) -> Box<Node> {
-    let mut node = Box::new(Node {
-        frequency: 0,
-        character: None,
-        left: None,
-        right: None,
-    });
-
-    if data[0] == 1 {
-        node.character = Some(data[1]);
-        *data = &data[2..];
-    } else {
-        *data = &data[1..];
-        node.left = Some(decode_tree(data));
-        node.right = Some(decode_tree(data));
-    }
-    node
+pub fn decode_huffman(data: &[u8]) -> Result<Vec<u8>, Error> {
+    Huffman::decode(data, &())
 }
 
 #[cfg(test)]
diff --git a/crates/encoding/src/rc4.rs b/crates/encoding/src/rc4.rs
index 82effef1abcc00a28184843b876cb51f1520150f..23acf5cb4a1413a29480ef88402f49ccdd6048cc 100644
--- a/crates/encoding/src/rc4.rs
+++ b/crates/encoding/src/rc4.rs
@@ -1,6 +1,6 @@
-use crate::cipher::Cipher;
+use boytacean_common::error::Error;
 
-pub struct Rc4Options;
+use crate::cipher::Cipher;
 
 pub struct Rc4 {
     s: [u8; 256],
@@ -40,24 +40,25 @@ impl Rc4 {
 }
 
 impl Cipher for Rc4 {
-    type EncryptOptions = Rc4Options;
-    type DecryptOptions = Rc4Options;
+    type EncryptOptions = ();
+    type DecryptOptions = ();
 
-    fn encrypt(data: &mut [u8], key: &[u8], _options: &Self::EncryptOptions) {
+    fn encrypt(data: &mut [u8], key: &[u8], _options: &Self::EncryptOptions) -> Result<(), Error> {
         let mut rc4 = Rc4::new(key);
         rc4.process(data);
+        Ok(())
     }
 
-    fn decrypt(data: &mut [u8], key: &[u8], options: &Self::DecryptOptions) {
-        Self::encrypt(data, key, options);
+    fn decrypt(data: &mut [u8], key: &[u8], options: &Self::DecryptOptions) -> Result<(), Error> {
+        Self::encrypt(data, key, options)
     }
 }
 
-pub fn rc4_encrypt(data: &mut [u8], key: &[u8]) {
-    Rc4::encrypt(data, key, &(Rc4Options {}))
+pub fn rc4_encrypt(data: &mut [u8], key: &[u8]) -> Result<(), Error> {
+    Rc4::encrypt(data, key, &())
 }
 
-pub fn rc4_decrypt(data: &mut [u8], key: &[u8]) {
+pub fn rc4_decrypt(data: &mut [u8], key: &[u8]) -> Result<(), Error> {
     rc4_encrypt(data, key)
 }
 
diff --git a/crates/encoding/src/rle.rs b/crates/encoding/src/rle.rs
index a6f976a53b2e47d8792fb89e13915b4667dab6d8..b07a8b1601bf0db44f77da3f28665c41ee69da7f 100644
--- a/crates/encoding/src/rle.rs
+++ b/crates/encoding/src/rle.rs
@@ -1,3 +1,5 @@
+use boytacean_common::error::Error;
+
 use crate::codec::Codec;
 
 pub struct Rle;
@@ -6,9 +8,9 @@ impl Codec for Rle {
     type EncodeOptions = ();
     type DecodeOptions = ();
 
-    fn encode(data: &[u8], _options: &Self::EncodeOptions) -> Vec<u8> {
+    fn encode(data: &[u8], _options: &Self::EncodeOptions) -> Result<Vec<u8>, Error> {
         if data.is_empty() {
-            return Vec::new();
+            return Ok(Vec::new());
         }
 
         let mut encoded = Vec::new();
@@ -28,10 +30,10 @@ impl Codec for Rle {
         encoded.push(prev_byte);
         encoded.push(count);
 
-        encoded
+        Ok(encoded)
     }
 
-    fn decode(data: &[u8], _options: &Self::DecodeOptions) -> Vec<u8> {
+    fn decode(data: &[u8], _options: &Self::DecodeOptions) -> Result<Vec<u8>, Error> {
         let mut decoded = Vec::new();
 
         let mut iter = data.iter();
@@ -41,14 +43,14 @@ impl Codec for Rle {
             }
         }
 
-        decoded
+        Ok(decoded)
     }
 }
 
-pub fn encode_rle(data: &[u8]) -> Vec<u8> {
+pub fn encode_rle(data: &[u8]) -> Result<Vec<u8>, Error> {
     Rle::encode(data, &())
 }
 
-pub fn decode_rle(data: &[u8]) -> Vec<u8> {
+pub fn decode_rle(data: &[u8]) -> Result<Vec<u8>, Error> {
     Rle::decode(data, &())
 }
diff --git a/crates/encoding/src/zippy.rs b/crates/encoding/src/zippy.rs
index 2d1fdc6f01090277a1d7a614dc2f92afc3fc3621..552be1c634c38b43bd437da344450e12cd30beda 100644
--- a/crates/encoding/src/zippy.rs
+++ b/crates/encoding/src/zippy.rs
@@ -12,6 +12,7 @@ use boytacean_common::error::Error;
 use boytacean_hashing::crc32c::crc32c;
 
 use crate::{
+    codec::Codec,
     huffman::{decode_huffman, encode_huffman},
     rc4::{rc4_decrypt, rc4_encrypt},
     rle::{decode_rle, encode_rle},
@@ -80,6 +81,7 @@ pub struct Zippy {
     data: Vec<u8>,
 }
 
+#[derive(Clone, Debug, Eq, Hash, PartialEq)]
 pub struct ZippyOptions {
     crc32: bool,
     key: Option<String>,
@@ -100,6 +102,17 @@ impl default::Default for ZippyOptions {
     }
 }
 
+pub struct ZippyEncodeOptions {
+    name: Option<String>,
+    description: Option<String>,
+    features: Option<Vec<ZippyFeatures>>,
+    options: Option<ZippyOptions>,
+}
+
+pub struct ZippyDecodeOptions {
+    options: Option<ZippyOptions>,
+}
+
 impl Zippy {
     pub fn build(
         data: &[u8],
@@ -121,17 +134,27 @@ impl Zippy {
         })
     }
 
-    pub fn is_zippy(data: &[u8]) -> Result<bool, Error> {
-        let mut data = Cursor::new(data);
+    pub fn encode_data(&self) -> Result<Vec<u8>, Error> {
+        let mut buffer = Cursor::new(vec![]);
+        let mut encoded = encode_huffman(&encode_rle(&self.data)?)?;
 
-        let mut buffer = [0x00; size_of::<u32>()];
-        data.read_exact(&mut buffer)?;
-        let magic = u32::from_le_bytes(buffer);
+        if self.has_feature(ZippyFeatures::EncryptedRc4) {
+            rc4_encrypt(&mut encoded, self.key()?)?;
+        }
 
-        Ok(magic == ZIPPY_MAGIC_UINT)
+        Self::write_u32(&mut buffer, ZIPPY_MAGIC_UINT)?;
+
+        Self::write_string(&mut buffer, &self.name)?;
+        Self::write_string(&mut buffer, &self.description)?;
+
+        self.write_features(&mut buffer)?;
+
+        Self::write_buffer(&mut buffer, &encoded)?;
+
+        Ok(buffer.into_inner())
     }
 
-    pub fn decode(data: &[u8], options: Option<ZippyOptions>) -> Result<Zippy, Error> {
+    pub fn decode_data(data: &[u8], options: Option<ZippyOptions>) -> Result<Zippy, Error> {
         let options = options.unwrap_or_default();
 
         let mut data = Cursor::new(data);
@@ -157,33 +180,23 @@ impl Zippy {
 
         let mut buffer = Self::read_buffer(&mut data)?;
         if instance.has_feature(ZippyFeatures::EncryptedRc4) {
-            rc4_decrypt(&mut buffer, instance.key()?)
+            rc4_decrypt(&mut buffer, instance.key()?)?;
         }
 
-        let decoded = decode_rle(&decode_huffman(&buffer)?);
+        let decoded = decode_rle(&decode_huffman(&buffer)?)?;
         instance.data = decoded;
 
         Ok(instance)
     }
 
-    pub fn encode(&self) -> Result<Vec<u8>, Error> {
-        let mut buffer = Cursor::new(vec![]);
-        let mut encoded = encode_huffman(&encode_rle(&self.data))?;
-
-        if self.has_feature(ZippyFeatures::EncryptedRc4) {
-            rc4_encrypt(&mut encoded, self.key()?)
-        }
-
-        Self::write_u32(&mut buffer, ZIPPY_MAGIC_UINT)?;
-
-        Self::write_string(&mut buffer, &self.name)?;
-        Self::write_string(&mut buffer, &self.description)?;
-
-        self.write_features(&mut buffer)?;
+    pub fn is_zippy(data: &[u8]) -> Result<bool, Error> {
+        let mut data = Cursor::new(data);
 
-        Self::write_buffer(&mut buffer, &encoded)?;
+        let mut buffer = [0x00; size_of::<u32>()];
+        data.read_exact(&mut buffer)?;
+        let magic = u32::from_le_bytes(buffer);
 
-        Ok(buffer.into_inner())
+        Ok(magic == ZIPPY_MAGIC_UINT)
     }
 
     pub fn check_crc32(&self) -> bool {
@@ -255,7 +268,7 @@ impl Zippy {
     #[inline(always)]
     fn read_rc4_feature(&mut self, data: &mut Cursor<&[u8]>) -> Result<(), Error> {
         let mut test_data = Self::read_buffer(data)?;
-        rc4_decrypt(&mut test_data, self.key()?);
+        rc4_decrypt(&mut test_data, self.key()?)?;
         if test_data != ZIPPY_CIPHER_TEST {
             return Err(Error::InvalidKey);
         }
@@ -312,7 +325,7 @@ impl Zippy {
     #[inline(always)]
     fn write_rc4_feature(&self, data: &mut Cursor<Vec<u8>>) -> Result<(), Error> {
         let mut test_data = ZIPPY_CIPHER_TEST.to_vec();
-        rc4_encrypt(&mut test_data, self.key()?);
+        rc4_encrypt(&mut test_data, self.key()?)?;
         Self::write_string(data, ZippyFeatures::EncryptedRc4.into())?;
         Self::write_buffer(data, &test_data)?;
         Ok(())
@@ -335,16 +348,46 @@ impl Zippy {
     }
 }
 
+impl Codec for Zippy {
+    type EncodeOptions = ZippyEncodeOptions;
+    type DecodeOptions = ZippyDecodeOptions;
+
+    fn encode(data: &[u8], options: &Self::EncodeOptions) -> Result<Vec<u8>, Error> {
+        Self::build(
+            data,
+            options.name.clone().unwrap_or_default(),
+            options.description.clone().unwrap_or_default(),
+            options.features.clone(),
+            options.options.clone(),
+        )?
+        .encode_data()
+    }
+
+    fn decode(data: &[u8], options: &Self::DecodeOptions) -> Result<Vec<u8>, Error> {
+        Ok(Zippy::decode_data(data, options.options.clone())?
+            .data()
+            .to_vec())
+    }
+}
+
 pub fn encode_zippy(
     data: &[u8],
     features: Option<Vec<ZippyFeatures>>,
     options: Option<ZippyOptions>,
 ) -> Result<Vec<u8>, Error> {
-    Zippy::build(data, String::from(""), String::from(""), features, options)?.encode()
+    Zippy::encode(
+        data,
+        &ZippyEncodeOptions {
+            name: None,
+            description: None,
+            features,
+            options,
+        },
+    )
 }
 
 pub fn decode_zippy(data: &[u8], options: Option<ZippyOptions>) -> Result<Vec<u8>, Error> {
-    Ok(Zippy::decode(data, options)?.data().to_vec())
+    Zippy::decode(data, &ZippyDecodeOptions { options })
 }
 
 #[cfg(test)]
@@ -360,9 +403,9 @@ mod tests {
         let description = String::from("Test description");
 
         let zippy = Zippy::build(&data, name.clone(), description.clone(), None, None).unwrap();
-        let encoded = zippy.encode().unwrap();
+        let encoded = zippy.encode_data().unwrap();
 
-        let decoded = Zippy::decode(&encoded, None).unwrap();
+        let decoded = Zippy::decode_data(&encoded, None).unwrap();
         assert_eq!(decoded.name, name);
         assert_eq!(decoded.description, description);
         assert_eq!(decoded.data, data);
@@ -375,7 +418,7 @@ mod tests {
         let description = String::from("Test description");
 
         let zippy = Zippy::build(&data, name.clone(), description.clone(), None, None).unwrap();
-        let encoded = zippy.encode().unwrap();
+        let encoded = zippy.encode_data().unwrap();
 
         let decoded_data = decode_zippy(&encoded, None).unwrap();
         assert_eq!(decoded_data, data);
@@ -388,9 +431,9 @@ mod tests {
         let description = String::from("Test description");
 
         let zippy = Zippy::build(&data, name.clone(), description.clone(), None, None).unwrap();
-        let encoded = zippy.encode().unwrap();
+        let encoded = zippy.encode_data().unwrap();
 
-        let zippy = Zippy::decode(&encoded, None).unwrap();
+        let zippy = Zippy::decode_data(&encoded, None).unwrap();
         assert!(zippy.has_feature(ZippyFeatures::Crc32));
         assert!(zippy.check_crc32());
         assert_eq!(zippy.crc32(), 0x53518fab);
@@ -410,9 +453,9 @@ mod tests {
             Some(ZippyOptions::new(false, None)),
         )
         .unwrap();
-        let encoded = zippy.encode().unwrap();
+        let encoded = zippy.encode_data().unwrap();
 
-        let zippy = Zippy::decode(&encoded, None).unwrap();
+        let zippy = Zippy::decode_data(&encoded, None).unwrap();
         assert!(zippy.has_feature(ZippyFeatures::Crc32));
         assert!(!zippy.check_crc32());
         assert_eq!(zippy.crc32(), 0xffffffff);
@@ -439,9 +482,9 @@ mod tests {
             Some(ZippyOptions::new(false, None)),
         )
         .unwrap();
-        let encoded = zippy.encode().unwrap();
+        let encoded = zippy.encode_data().unwrap();
 
-        let zippy = Zippy::decode(&encoded, None).unwrap();
+        let zippy = Zippy::decode_data(&encoded, None).unwrap();
         assert!(zippy.has_feature(ZippyFeatures::Other));
         assert!(!zippy.has_feature(ZippyFeatures::Crc32));
         assert!(!zippy.check_crc32());