🏡 index : ~doyle/serde_bson.git

Diff

 Cargo.toml                                           |  15 ++++++++++-----
 README.md                                            |  38 +++++++++-----------------------------
 benches/borrowed.rs                                  |  58 ----------------------------------------------------------
 benches/deserialize.rs                               |  51 +++++++++++++++++++++++++++++++++++++++++++++++++++
 benches/owned.rs                                     |  60 ------------------------------------------------------------
 benches/serialize.rs                                 |  60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/byte.rs                                          |   4 ++--
 src/de.rs                                            | 398 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/lib.rs                                           |  14 +++++++++-----
 src/ser.rs                                           |  44 ++++++++++++++++++--------------------------
 test/test.bin                                        |   0 
 src/snapshots/serde_bson__de__test__deserialize.snap | 207 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 12 files changed, 764 insertions(+), 185 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index 0854375..f40f601 100644
--- a/Cargo.toml
+++ a/Cargo.toml
@@ -12,19 +12,24 @@
[dependencies]
serde = "1"
bytes = "1"
itoa = "0.4"
itoa = "1.0"
simdutf8 = "0.1"
memchr = "2.7"
thiserror = "1"
bumpalo = { version = "3.16", features = ["collections"] }

[dev-dependencies]
serde = { version = "1", features = ["derive"] }
serde_bytes = "0.11"
bson = "1.2"
criterion = "0.3"
bson = "2.13"
criterion = "0.5"
rand = "0.8"
insta = "1.4"

[[bench]]
name = "borrowed"
name = "serialize"
harness = false

[[bench]]
name = "owned"
name = "deserialize"
harness = false
diff --git a/README.md b/README.md
index b7899bd..5875fd2 100644
--- a/README.md
+++ a/README.md
@@ -1,38 +1,18 @@
## serde_bson

Originally implemented as a workaround to the `bson` crate cloning every value it
comes across and it's looking like it shows significant improvement across the board
for serialisation (~80% improvement).
comes across. The `bson` crate has since improved in this aspect, however this
clean room implementation of the spec still shows significant speedup in both
serialisation and deserialisation.

```

borrowed: mongodb's bson  time:   [1.1160 us 1.1171 us 1.1183 us]
Found 2 outliers among 100 measurements (2.00%)
  2 (2.00%) high mild
deserialize: mongodb's bson
                        time:   [867.32 ns 867.62 ns 867.97 ns]


borrowed: serde_bson      time:   [201.99 ns 202.17 ns 202.38 ns]                                 
Found 10 outliers among 100 measurements (10.00%)
  4 (4.00%) low mild
  4 (4.00%) high mild
  2 (2.00%) high severe
```


Even on owned data it shows a significant improvement:
deserialize: serde_bson time:   [468.41 ns 470.12 ns 472.06 ns]

```

owned: mongodb's bson	time:   [1.0740 us 1.0762 us 1.0794 us]                                   
Found 6 outliers among 100 measurements (6.00%)
  4 (4.00%) low mild
  1 (1.00%) high mild
  1 (1.00%) high severe
serialize: mongodb's bson
                        time:   [684.01 ns 686.48 ns 689.57 ns]


owned: serde_bson	time:   [209.67 ns 210.18 ns 211.06 ns]                              
Found 9 outliers among 100 measurements (9.00%)
  5 (5.00%) high mild
  4 (4.00%) high severe
serialize: serde_bson   time:   [136.42 ns 136.86 ns 137.36 ns]
```


There's a few pieces missing such as arrays and nested documents but they're not
too difficult to add, it's just that it's 2:38am and I've smashed this out in an
hour.

Pull requests welcome as always.
diff --git a/benches/borrowed.rs b/benches/borrowed.rs
deleted file mode 100644
index 44f382a..0000000 100644
--- a/benches/borrowed.rs
+++ /dev/null
@@ -1,58 +1,0 @@
use bytes::BufMut;
use criterion::{black_box, criterion_group, criterion_main, Criterion};

#[derive(serde::Serialize)]
pub struct A<'a> {
    a: &'a str,
    b: &'a str,
    c: &'a str,
    d: i64,
    e: f64,
    #[serde(with = "serde_bytes")]
    f: &'a [u8],
}

fn benchmark(c: &mut Criterion) {
    let val = A {
        a: "Now this is a story all about how
            My life got flipped turned upside down
            And I'd like to take a minute, just sit right there
            I'll tell you how I became the prince of a town called Bel-Air",
        b: "In West Philadelphia born and raised
            On the playground is where I spent most of my days
            Chillin' out, maxin', relaxin' all cool
            And all shootin' some b-ball outside of the school
            When a couple of guys who were up to no good
            Started makin' trouble in my neighborhood",
        c: "I got in one little fight and my mom got scared
            And said 'You're movin' with your auntie and uncle in Bel-Air'",
        d: 420,
        e: 420.69696969696969,
        f: "Above are some popular 'pop culture' references for your perusal and enjoyment"
            .as_bytes(),
    };

    c.bench_function("borrowed: mongodb's bson", |b| {
        let mut theirs = Vec::new();

        b.iter(|| {
            bson::ser::to_document(black_box(&val))
                .unwrap()
                .to_writer(&mut theirs)
                .unwrap();
            theirs.clear();
        })
    });

    c.bench_function("borrowed: serde_bson", |b| {
        let mut out = bytes::BytesMut::new();

        b.iter(|| {
            serde_bson::to_string(black_box(&val), &mut out).unwrap();
            drop(out.split());
        });
    });
}

criterion_group!(benches, benchmark);
criterion_main!(benches);
diff --git a/benches/deserialize.rs b/benches/deserialize.rs
new file mode 100644
index 0000000..194fc38 100644
--- /dev/null
+++ a/benches/deserialize.rs
@@ -1,0 +1,51 @@
use bytes::BufMut;
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
pub struct A<'a> {
    cool: i32,
    #[serde(with = "serde_bytes")]
    beans: &'a [u8],
    bro: &'a str,
    b: B<'a>,
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
pub enum Test {
    Abc,
    Def(i32),
    Ghi(i32, i32, i32),
    Jkl { a: i32, b: i32 },
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
pub struct Tup(i32, i32);

#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
pub struct B<'a> {
    s: &'a str,
    a: Vec<&'a str>,
    e: Test,
    e2: Test,
    e3: Test,
    e4: Test,
    t: (i32, i32, i32),
    ts: Tup,
    y: bool,
}

fn benchmark(c: &mut Criterion) {
    let data = include_bytes!("../test/test.bin");

    c.bench_function("deserialize: mongodb's bson", |b| {
        b.iter(|| bson::de::from_slice::<A>(black_box(data)))
    });

    c.bench_function("deserialize: serde_bson", |b| {
        b.iter(|| serde_bson::de::from_bytes::<A>(black_box(data)));
    });
}

criterion_group!(benches, benchmark);
criterion_main!(benches);
diff --git a/benches/owned.rs b/benches/owned.rs
deleted file mode 100644
index 773567e..0000000 100644
--- a/benches/owned.rs
+++ /dev/null
@@ -1,60 +1,0 @@
use bytes::BufMut;
use criterion::{black_box, criterion_group, criterion_main, Criterion};

#[derive(serde::Serialize)]
pub struct A {
    a: String,
    b: String,
    c: String,
    d: i64,
    e: f64,
    #[serde(with = "serde_bytes")]
    f: Vec<u8>,
}

fn benchmark(c: &mut Criterion) {
    let val = A {
        a: "Now this is a story all about how
            My life got flipped turned upside down
            And I'd like to take a minute, just sit right there
            I'll tell you how I became the prince of a town called Bel-Air"
            .to_string(),
        b: "In West Philadelphia born and raised
            On the playground is where I spent most of my days
            Chillin' out, maxin', relaxin' all cool
            And all shootin' some b-ball outside of the school
            When a couple of guys who were up to no good
            Started makin' trouble in my neighborhood"
            .to_string(),
        c: "I got in one little fight and my mom got scared
            And said 'You're movin' with your auntie and uncle in Bel-Air'"
            .to_string(),
        d: 420,
        e: 420.69696969696969,
        f: "Above are some popular 'pop culture' references for your perusal and enjoyment".into(),
    };

    c.bench_function("owned: mongodb's bson", |b| {
        let mut theirs = Vec::new();

        b.iter(|| {
            bson::ser::to_document(black_box(&val))
                .unwrap()
                .to_writer(&mut theirs)
                .unwrap();
            theirs.clear();
        })
    });

    c.bench_function("owned: serde_bson", |b| {
        let mut out = bytes::BytesMut::new();

        b.iter(|| {
            serde_bson::to_string(black_box(&val), &mut out).unwrap();
            drop(out.split());
        });
    });
}

criterion_group!(benches, benchmark);
criterion_main!(benches);
diff --git a/benches/serialize.rs b/benches/serialize.rs
new file mode 100644
index 0000000..ba8fb02 100644
--- /dev/null
+++ a/benches/serialize.rs
@@ -1,0 +1,60 @@
use bytes::BufMut;
use criterion::{black_box, criterion_group, criterion_main, Criterion};

#[derive(serde::Serialize)]
pub struct A {
    a: String,
    b: String,
    c: String,
    d: i64,
    e: f64,
    #[serde(with = "serde_bytes")]
    f: Vec<u8>,
}

fn benchmark(c: &mut Criterion) {
    let val = A {
        a: "Now this is a story all about how
            My life got flipped turned upside down
            And I'd like to take a minute, just sit right there
            I'll tell you how I became the prince of a town called Bel-Air"
            .to_string(),
        b: "In West Philadelphia born and raised
            On the playground is where I spent most of my days
            Chillin' out, maxin', relaxin' all cool
            And all shootin' some b-ball outside of the school
            When a couple of guys who were up to no good
            Started makin' trouble in my neighborhood"
            .to_string(),
        c: "I got in one little fight and my mom got scared
            And said 'You're movin' with your auntie and uncle in Bel-Air'"
            .to_string(),
        d: 420,
        e: 420.69696969696969,
        f: "Above are some popular 'pop culture' references for your perusal and enjoyment".into(),
    };

    c.bench_function("serialize: mongodb's bson", |b| {
        let mut theirs = Vec::new();

        b.iter(|| {
            bson::ser::to_document(black_box(&val))
                .unwrap()
                .to_writer(&mut theirs)
                .unwrap();
            theirs.clear();
        })
    });

    c.bench_function("serialize: serde_bson", |b| {
        let mut out = bytes::BytesMut::new();

        b.iter(|| {
            serde_bson::to_string(black_box(&val), &mut out).unwrap();
            drop(out.split());
        });
    });
}

criterion_group!(benches, benchmark);
criterion_main!(benches);
diff --git a/src/byte.rs b/src/byte.rs
index 595d30f..82ae942 100644
--- a/src/byte.rs
+++ a/src/byte.rs
@@ -49,7 +49,7 @@
    }
);

impl<'a, B: BytesLikeBuf> BytesLikeBuf for &mut B {
impl<B: BytesLikeBuf> BytesLikeBuf for &mut B {
    type Out = <B as BytesLikeBuf>::Out;

    fn put_u8(&mut self, v: u8) {
@@ -115,7 +115,7 @@
    }

    fn put_slice(&mut self, s: &[u8]) {
        self.bytes += std::mem::size_of::<u8>() * s.len();
        self.bytes += std::mem::size_of_val(s);
    }

    fn split_off(&mut self, _at: usize) -> Self {
diff --git a/src/de.rs b/src/de.rs
new file mode 100644
index 0000000..61a3f1a 100644
--- /dev/null
+++ a/src/de.rs
@@ -1,0 +1,398 @@
use memchr::memchr;
use std::{cell::RefCell, convert::TryInto, fmt::Display};

use serde::{
    de::{
        value::BorrowedStrDeserializer, EnumAccess, IntoDeserializer, MapAccess, SeqAccess,
        VariantAccess, Visitor,
    },
    forward_to_deserialize_any, Deserializer,
};

#[derive(thiserror::Error, Debug)]
pub enum Error {
    #[error("unexpected map end")]
    UnexpectedMapEnd,
    #[error("unexpected key")]
    UnexpectedKey,
    #[error("end of file")]
    EndOfFile,
    #[error("custom: {0}")]
    Custom(String),
    #[error("malformed map, missing key or document end")]
    MalformedMapMissingKey,
    #[error("unexpected enum")]
    UnexpectedEnum,
}

impl serde::de::Error for Error {
    fn custom<T>(msg: T) -> Self
    where
        T: Display,
    {
        Self::Custom(msg.to_string())
    }
}

thread_local! {
    static ALLOCATOR: RefCell<bumpalo::Bump> = RefCell::new(bumpalo::Bump::new());
}

pub fn from_bytes<'de, D: serde::de::Deserialize<'de>>(data: &'de [u8]) -> Result<D, Error> {
    ALLOCATOR.with_borrow_mut(|allocator| {
        allocator.reset();

        let mut tape = bumpalo::collections::Vec::new_in(allocator);
        to_tape(data, &mut tape);
        D::deserialize(&mut BsonDeserializer { tape: &tape })
    })
}

struct BsonDeserializer<'a, 'de> {
    tape: &'a [Tape<'de>],
}

impl<'a, 'de> BsonDeserializer<'a, 'de> {
    fn next_item(&mut self) -> Option<&'a Tape<'de>> {
        let (next, rest) = self.tape.split_first()?;
        self.tape = rest;
        Some(next)
    }
}

impl<'de> Deserializer<'de> for &mut BsonDeserializer<'_, 'de> {
    type Error = Error;

    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: Visitor<'de>,
    {
        match self.next_item() {
            Some(Tape::DocumentStart) => visitor.visit_map(self),
            Some(Tape::DocumentEnd) => Err(Error::UnexpectedMapEnd),
            Some(Tape::Key(_)) => Err(Error::UnexpectedKey),
            Some(Tape::Double(value)) => visitor.visit_f64(*value),
            Some(Tape::String(value)) => visitor.visit_borrowed_str(value),
            Some(Tape::ArrayStart) => self.deserialize_seq(visitor),
            Some(Tape::Binary(value, _)) => visitor.visit_borrowed_bytes(value),
            Some(Tape::Boolean(value)) => visitor.visit_bool(*value),
            Some(Tape::UtcDateTime(value)) => visitor.visit_i64(*value),
            Some(Tape::Null) => visitor.visit_none(),
            Some(Tape::I32(value)) => visitor.visit_i32(*value),
            Some(Tape::Timestamp(value)) => visitor.visit_u64(*value),
            Some(Tape::I64(value)) => visitor.visit_i64(*value),
            None => Err(Error::EndOfFile),
        }
    }

    fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: Visitor<'de>,
    {
        if let Some(Tape::ArrayStart) = self.tape.first() {
            self.tape = &self.tape[1..];
        }

        let res = visitor.visit_seq(&mut *self)?;

        let Some(Tape::DocumentEnd) = self.next_item() else {
            return Err(Error::UnexpectedMapEnd);
        };

        Ok(res)
    }

    fn deserialize_enum<V>(
        self,
        _name: &'static str,
        _variants: &'static [&'static str],
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: Visitor<'de>,
    {
        match self.next_item() {
            Some(Tape::String(s)) => visitor.visit_enum(s.into_deserializer()),
            Some(Tape::DocumentStart) => {
                let data = visitor.visit_enum(&mut EnumDeserializer { deser: &mut *self })?;

                let Some(Tape::DocumentEnd) = self.next_item() else {
                    return Err(Error::UnexpectedMapEnd);
                };

                Ok(data)
            }
            Some(Tape::ArrayStart) => {
                let data = visitor.visit_enum(&mut EnumDeserializer { deser: &mut *self })?;

                let Some(Tape::DocumentEnd) = self.next_item() else {
                    return Err(Error::UnexpectedMapEnd);
                };

                Ok(data)
            }
            _ => Err(Error::UnexpectedEnum),
        }
    }

    forward_to_deserialize_any! {
        bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
        byte_buf option unit unit_struct newtype_struct tuple tuple_struct
        map struct identifier ignored_any
    }
}

struct EnumDeserializer<'a, 'b, 'de> {
    deser: &'b mut BsonDeserializer<'a, 'de>,
}

impl<'de> Deserializer<'de> for &mut EnumDeserializer<'_, '_, 'de> {
    type Error = Error;

    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: Visitor<'de>,
    {
        if let Some(Tape::Key(key)) = self.deser.tape.first() {
            self.deser.tape = &self.deser.tape[1..];
            visitor.visit_borrowed_str(key)
        } else {
            self.deser.deserialize_any(visitor)
        }
    }

    forward_to_deserialize_any! {
        bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
        byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct
        map struct enum identifier ignored_any
    }
}

impl<'de> VariantAccess<'de> for &mut EnumDeserializer<'_, '_, 'de> {
    type Error = Error;

    fn unit_variant(self) -> Result<(), Self::Error> {
        unreachable!()
    }

    fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Self::Error>
    where
        T: serde::de::DeserializeSeed<'de>,
    {
        seed.deserialize(self)
    }

    fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: Visitor<'de>,
    {
        self.deserialize_seq(visitor)
    }

    fn struct_variant<V>(
        self,
        _fields: &'static [&'static str],
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: Visitor<'de>,
    {
        self.deserialize_map(visitor)
    }
}

impl<'de> EnumAccess<'de> for &mut EnumDeserializer<'_, '_, 'de> {
    type Error = Error;
    type Variant = Self;

    fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
    where
        V: serde::de::DeserializeSeed<'de>,
    {
        let value = seed.deserialize(&mut *self)?;

        Ok((value, self))
    }
}

impl<'de> MapAccess<'de> for BsonDeserializer<'_, 'de> {
    type Error = Error;

    fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
    where
        K: serde::de::DeserializeSeed<'de>,
    {
        let data = match self.next_item() {
            Some(Tape::DocumentEnd) => return Ok(None),
            Some(Tape::Key(key)) => key,
            _ => return Err(Error::MalformedMapMissingKey),
        };

        seed.deserialize(BorrowedStrDeserializer::new(data))
            .map(Some)
    }

    fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
    where
        V: serde::de::DeserializeSeed<'de>,
    {
        seed.deserialize(self)
    }
}

impl<'de> SeqAccess<'de> for BsonDeserializer<'_, 'de> {
    type Error = Error;

    fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
    where
        T: serde::de::DeserializeSeed<'de>,
    {
        if let Some(Tape::DocumentEnd) = self.tape.first() {
            return Ok(None);
        }

        let Some(Tape::Key(_)) = self.next_item() else {
            return Err(Error::MalformedMapMissingKey);
        };

        seed.deserialize(self).map(Some)
    }
}

#[derive(Debug)]
pub enum Tape<'a> {
    DocumentStart,        // start of input or 0x03
    DocumentEnd,          // 0x00
    Key(&'a str),         //
    Double(f64),          // 0x01
    String(&'a str),      // 0x02
    ArrayStart,           // 0x04
    Binary(&'a [u8], u8), // 0x05
    Boolean(bool),        // 0x08
    UtcDateTime(i64),     // 0x09
    Null,                 // 0x0a
    I32(i32),             // 0x10
    Timestamp(u64),       // 0x11
    I64(i64),             // 0x12
}

fn to_tape<'a>(input: &'a [u8], tape: &mut bumpalo::collections::Vec<'_, Tape<'a>>) {
    let length = u32::from_le_bytes([input[0], input[1], input[2], input[3]]) as usize;

    let input = &input[4..length];

    let mut position = 0;
    tape.push(Tape::DocumentStart);

    let take_cstring = |position: &mut usize| {
        let idx = memchr(b'\0', &input[*position..]).expect("unterminated c-string");
        let s = simdutf8::basic::from_utf8(&input[*position..*position + idx]).unwrap();
        *position += idx + 1;
        s
    };

    let take_bytes = |position: &mut usize, n| {
        let res = &input[*position..*position + n];
        *position += n;
        res
    };

    while position < length - 4 {
        position += 1;
        match input[position - 1] {
            0x00 => {
                tape.push(Tape::DocumentEnd);
            }
            0x01 => {
                let key = take_cstring(&mut position);
                let value = f64::from_le_bytes(take_bytes(&mut position, 8).try_into().unwrap());
                tape.push(Tape::Key(key));
                tape.push(Tape::Double(value));
            }
            0x02 => {
                let key = take_cstring(&mut position);
                let length =
                    u32::from_le_bytes(take_bytes(&mut position, 4).try_into().unwrap()) as usize;
                let value =
                    simdutf8::basic::from_utf8(&input[position..position + length - 1]).unwrap();
                position += length;
                tape.push(Tape::Key(key));
                tape.push(Tape::String(value));
            }
            0x03 => {
                let key = take_cstring(&mut position);
                let _length = take_bytes(&mut position, 4);
                tape.push(Tape::Key(key));
                tape.push(Tape::DocumentStart);
            }
            0x04 => {
                let key = take_cstring(&mut position);
                let _length = take_bytes(&mut position, 4);
                tape.push(Tape::Key(key));
                tape.push(Tape::ArrayStart);
            }
            0x05 => {
                let key = take_cstring(&mut position);
                let length =
                    u32::from_le_bytes(take_bytes(&mut position, 4).try_into().unwrap()) as usize;
                let subtype = input[position];
                position += 1;
                let value = &input[position..position + length];
                position += length;
                tape.push(Tape::Key(key));
                tape.push(Tape::Binary(value, subtype));
            }
            0x08 => {
                let key = take_cstring(&mut position);
                let value = input[position] == 1;
                position += 1;
                tape.push(Tape::Key(key));
                tape.push(Tape::Boolean(value));
            }
            0x09 => {
                let key = take_cstring(&mut position);
                let value = i64::from_le_bytes(take_bytes(&mut position, 8).try_into().unwrap());
                tape.push(Tape::Key(key));
                tape.push(Tape::UtcDateTime(value));
            }
            0x0a => {
                let key = take_cstring(&mut position);
                tape.push(Tape::Key(key));
                tape.push(Tape::Null);
            }
            0x10 => {
                let key = take_cstring(&mut position);
                let value = i32::from_le_bytes(take_bytes(&mut position, 4).try_into().unwrap());
                tape.push(Tape::Key(key));
                tape.push(Tape::I32(value));
            }
            0x11 => {
                let key = take_cstring(&mut position);
                let value = u64::from_le_bytes(take_bytes(&mut position, 8).try_into().unwrap());
                tape.push(Tape::Key(key));
                tape.push(Tape::Timestamp(value));
            }
            0x12 => {
                let key = take_cstring(&mut position);
                let value = i64::from_le_bytes(take_bytes(&mut position, 8).try_into().unwrap());
                tape.push(Tape::Key(key));
                tape.push(Tape::I64(value));
            }
            _ => {}
        };
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn deserialize() {
        let f = std::fs::read("test/test.bin").unwrap();

        let bump = bumpalo::Bump::new();
        let mut tape = bumpalo::collections::Vec::new_in(&bump);

        super::to_tape(&f, &mut tape);
        insta::assert_debug_snapshot!(tape);
    }
}
diff --git a/src/lib.rs b/src/lib.rs
index aeefa00..74c59da 100644
--- a/src/lib.rs
+++ a/src/lib.rs
@@ -1,4 +1,5 @@
mod byte;
pub mod de;
mod error;
pub mod ser;

@@ -29,11 +30,11 @@
mod test {
    use super::{serialised_size_of, to_string};
    use bytes::{BufMut, BytesMut};
    use serde::Serialize;
    use serde::{Deserialize, Serialize};

    #[test]
    pub fn test_basic() {
        #[derive(Serialize)]
        #[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
        pub struct A<'a> {
            cool: i32,
            #[serde(with = "serde_bytes")]
@@ -42,7 +43,7 @@
            b: B<'a>,
        }

        #[derive(Serialize)]
        #[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
        pub enum Test {
            Abc,
            Def(i32),
@@ -50,10 +51,10 @@
            Jkl { a: i32, b: i32 },
        }

        #[derive(Serialize)]
        #[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
        pub struct Tup(i32, i32);

        #[derive(Serialize)]
        #[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
        pub struct B<'a> {
            s: &'a str,
            a: Vec<&'a str>,
@@ -98,5 +99,8 @@
        let calculated_size = serialised_size_of(&test).unwrap();
        assert_eq!(calculated_size, ours.len());
        assert_eq!(calculated_size, theirs.len());

        let deserialized: A = crate::de::from_bytes(&ours).unwrap();
        assert_eq!(&deserialized, test);
    }
}
diff --git a/src/ser.rs b/src/ser.rs
index adb7afc..ac7bc70 100644
--- a/src/ser.rs
+++ a/src/ser.rs
@@ -106,9 +106,9 @@
        Ok(())
    }

    fn serialize_some<T: ?Sized>(self, value: &T) -> Result<Self::Ok, Self::Error>
    fn serialize_some<T>(self, value: &T) -> Result<Self::Ok, Self::Error>
    where
        T: Serialize,
        T: ?Sized + Serialize,
    {
        value.serialize(self)
    }
@@ -130,18 +130,18 @@
        self.serialize_str(variant)
    }

    fn serialize_newtype_struct<T: ?Sized>(
    fn serialize_newtype_struct<T>(
        self,
        _name: &'static str,
        value: &T,
    ) -> Result<Self::Ok, Self::Error>
    where
        T: Serialize,
        T: ?Sized + Serialize,
    {
        value.serialize(self)
    }

    fn serialize_newtype_variant<T: ?Sized>(
    fn serialize_newtype_variant<T>(
        self,
        _name: &'static str,
        _variant_index: u32,
@@ -149,7 +149,7 @@
        value: &T,
    ) -> Result<Self::Ok, Self::Error>
    where
        T: Serialize,
        T: ?Sized + Serialize,
    {
        let mut struct_serializer = self.serialize_struct("", 0)?;
        struct_serializer.serialize_field(variant, value)?;
@@ -294,9 +294,9 @@
    type Ok = ();
    type Error = <Serializer<'a, B> as serde::Serializer>::Error;

    fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
    fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
    where
        T: Serialize,
        T: ?Sized + Serialize,
    {
        self.inner.serialize_element(value)
    }
@@ -317,9 +317,9 @@
    type Ok = ();
    type Error = <Serializer<'a, B> as serde::Serializer>::Error;

    fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
    fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
    where
        T: Serialize,
        T: ?Sized + Serialize,
    {
        // we're basically inside a SeqSerializer here, but we can't instantiate one
        // so we'll duplicate the functionality instead
@@ -350,13 +350,9 @@
    type Ok = ();
    type Error = <Serializer<'a, B> as serde::Serializer>::Error;

    fn serialize_field<T: ?Sized>(
        &mut self,
        key: &'static str,
        value: &T,
    ) -> Result<(), Self::Error>
    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error>
    where
        T: Serialize,
        T: ?Sized + Serialize,
    {
        // we're basically inside a nested StructSerializer here, but we can't
        // instantiate one so we'll duplicate the functionality instead. this
@@ -386,9 +382,9 @@
    type Ok = ();
    type Error = <Serializer<'a, B> as serde::Serializer>::Error;

    fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
    fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
    where
        T: Serialize,
        T: ?Sized + Serialize,
    {
        self.inner.serialize_element(value)
    }
@@ -408,9 +404,9 @@
    type Ok = ();
    type Error = <Serializer<'a, B> as serde::Serializer>::Error;

    fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
    fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
    where
        T: Serialize,
        T: ?Sized + Serialize,
    {
        value.serialize(Serializer {
            key: Some(DocumentKey::Int(self.key)),
@@ -435,13 +431,9 @@
    type Ok = ();
    type Error = <Serializer<'a, B> as serde::Serializer>::Error;

    fn serialize_field<T: ?Sized>(
        &mut self,
        key: &'static str,
        value: &T,
    ) -> Result<(), Self::Error>
    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error>
    where
        T: Serialize,
        T: ?Sized + Serialize,
    {
        value.serialize(Serializer {
            key: Some(DocumentKey::Str(key)),
diff --git a/test/test.bin b/test/test.bin
new file mode 100644
index 0000000000000000000000000000000000000000..a4e8a4a1fe97844f1cf0aeffbf8008510a8c2761 100644
Binary files /dev/null and a/test/test.bin differdiff --git a/src/snapshots/serde_bson__de__test__deserialize.snap b/src/snapshots/serde_bson__de__test__deserialize.snap
new file mode 100644
index 0000000..7ba31a9 100644
--- /dev/null
+++ a/src/snapshots/serde_bson__de__test__deserialize.snap
@@ -1,0 +1,207 @@
---
source: src/de.rs
expression: x
---
[
    DocumentStart,
    Key(
        "cool",
    ),
    I32(
        999,
    ),
    Key(
        "beans",
    ),
    Binary(
        [
            115,
            111,
            32,
            116,
            104,
            101,
            114,
            101,
            32,
            119,
            97,
            115,
            32,
            116,
            104,
            105,
            115,
            32,
            111,
            110,
            101,
            32,
            116,
            105,
            109,
            101,
            32,
            97,
            116,
            32,
            98,
            97,
            110,
            100,
            99,
            97,
            109,
            112,
        ],
        0,
    ),
    Key(
        "bro",
    ),
    String(
        "the craziest thing happened",
    ),
    Key(
        "b",
    ),
    DocumentStart,
    Key(
        "s",
    ),
    String(
        "dddd",
    ),
    Key(
        "a",
    ),
    ArrayStart,
    Key(
        "0",
    ),
    String(
        "yooo",
    ),
    Key(
        "1",
    ),
    String(
        "mayn",
    ),
    DocumentEnd,
    Key(
        "e",
    ),
    String(
        "Abc",
    ),
    Key(
        "e2",
    ),
    DocumentStart,
    Key(
        "Def",
    ),
    I32(
        1999,
    ),
    DocumentEnd,
    Key(
        "e3",
    ),
    DocumentStart,
    Key(
        "Ghi",
    ),
    ArrayStart,
    Key(
        "0",
    ),
    I32(
        16,
    ),
    Key(
        "1",
    ),
    I32(
        7,
    ),
    Key(
        "2",
    ),
    I32(
        1999,
    ),
    DocumentEnd,
    DocumentEnd,
    Key(
        "e4",
    ),
    DocumentStart,
    Key(
        "Jkl",
    ),
    DocumentStart,
    Key(
        "a",
    ),
    I32(
        16,
    ),
    Key(
        "b",
    ),
    I32(
        7,
    ),
    DocumentEnd,
    DocumentEnd,
    Key(
        "t",
    ),
    ArrayStart,
    Key(
        "0",
    ),
    I32(
        16,
    ),
    Key(
        "1",
    ),
    I32(
        7,
    ),
    Key(
        "2",
    ),
    I32(
        1999,
    ),
    DocumentEnd,
    Key(
        "ts",
    ),
    ArrayStart,
    Key(
        "0",
    ),
    I32(
        99,
    ),
    Key(
        "1",
    ),
    I32(
        100,
    ),
    DocumentEnd,
    Key(
        "y",
    ),
    Boolean(
        false,
    ),
    DocumentEnd,
    DocumentEnd,
]