turbo_bincode/
lib.rs

1#[doc(hidden)]
2pub mod macro_helpers;
3pub mod serde_self_describing;
4
5use std::{any::Any, ptr::copy_nonoverlapping};
6
7use ::smallvec::SmallVec;
8use bincode::{
9    BorrowDecode, Decode, Encode,
10    de::{BorrowDecoder, Decoder, DecoderImpl, read::Reader},
11    enc::{Encoder, EncoderImpl, write::Writer},
12    error::{DecodeError, EncodeError},
13};
14
15pub const TURBO_BINCODE_CONFIG: bincode::config::Configuration = bincode::config::standard();
16pub type TurboBincodeBuffer = SmallVec<[u8; 16]>;
17pub type TurboBincodeEncoder<'a> =
18    EncoderImpl<TurboBincodeWriter<'a>, bincode::config::Configuration>;
19pub type TurboBincodeDecoder<'a> =
20    DecoderImpl<TurboBincodeReader<'a>, bincode::config::Configuration, ()>;
21pub type AnyEncodeFn = fn(&dyn Any, &mut TurboBincodeEncoder<'_>) -> Result<(), EncodeError>;
22pub type AnyDecodeFn<T> = fn(&mut TurboBincodeDecoder<'_>) -> Result<T, DecodeError>;
23
24fn new_turbo_bincode_encoder(buf: &mut TurboBincodeBuffer) -> TurboBincodeEncoder<'_> {
25    EncoderImpl::new(TurboBincodeWriter::new(buf), TURBO_BINCODE_CONFIG)
26}
27
28fn new_turbo_bincode_decoder(buffer: &[u8]) -> TurboBincodeDecoder<'_> {
29    DecoderImpl::new(TurboBincodeReader::new(buffer), TURBO_BINCODE_CONFIG, ())
30}
31
32/// Encode the value into a new [`SmallVec`] using a [`TurboBincodeEncoder`].
33///
34/// Note: If you can re-use a buffer, you should. That will always be cheaper than creating a new
35/// [`SmallVec`].
36pub fn turbo_bincode_encode<T: Encode>(value: &T) -> Result<TurboBincodeBuffer, EncodeError> {
37    let mut buffer = TurboBincodeBuffer::new();
38    turbo_bincode_encode_into(value, &mut buffer)?;
39    Ok(buffer)
40}
41
42pub fn turbo_bincode_encode_into<T: Encode>(
43    value: &T,
44    buffer: &mut TurboBincodeBuffer,
45) -> Result<(), EncodeError> {
46    let mut encoder = new_turbo_bincode_encoder(buffer);
47    value.encode(&mut encoder)?;
48    Ok(())
49}
50
51/// Decode using a [`TurboBincodeDecoder`] and check that the entire slice was consumed. Returns a
52/// [`DecodeError::ArrayLengthMismatch`] if some of the slice is not consumed during decoding.
53pub fn turbo_bincode_decode<T: Decode<()>>(buf: &[u8]) -> Result<T, DecodeError> {
54    let mut decoder = new_turbo_bincode_decoder(buf);
55    let val = T::decode(&mut decoder)?;
56    let remaining_buf = decoder.reader().buffer;
57    if !remaining_buf.is_empty() {
58        return Err(DecodeError::ArrayLengthMismatch {
59            required: buf.len() - remaining_buf.len(),
60            found: buf.len(),
61        });
62    }
63    Ok(val)
64}
65
66pub struct TurboBincodeWriter<'a> {
67    pub buffer: &'a mut TurboBincodeBuffer,
68}
69
70impl<'a> TurboBincodeWriter<'a> {
71    pub fn new(buffer: &'a mut TurboBincodeBuffer) -> Self {
72        Self { buffer }
73    }
74}
75
76impl Writer for TurboBincodeWriter<'_> {
77    fn write(&mut self, bytes: &[u8]) -> Result<(), EncodeError> {
78        self.buffer.extend_from_slice(bytes);
79        Ok(())
80    }
81}
82
83/// This is equivalent to [`bincode::de::read::SliceReader`], but with a little `unsafe` code to
84/// avoid some redundant bounds checks, and `pub` access to the underlying `buffer`.
85pub struct TurboBincodeReader<'a> {
86    pub buffer: &'a [u8],
87}
88
89impl<'a> TurboBincodeReader<'a> {
90    pub fn new(buffer: &'a [u8]) -> Self {
91        Self { buffer }
92    }
93}
94
95impl Reader for TurboBincodeReader<'_> {
96    fn read(&mut self, target_buffer: &mut [u8]) -> Result<(), DecodeError> {
97        let len = target_buffer.len();
98        let (head, rest) =
99            self.buffer
100                .split_at_checked(len)
101                .ok_or_else(|| DecodeError::UnexpectedEnd {
102                    additional: len - self.buffer.len(),
103                })?;
104        // SAFETY:
105        // - We already checked the bounds.
106        // - These memory ranges can't overlap because it would violate rust aliasing rules.
107        // - `u8` is `Copy`.
108        unsafe {
109            copy_nonoverlapping(head.as_ptr(), target_buffer.as_mut_ptr(), len);
110        }
111        self.buffer = rest;
112        Ok(())
113    }
114
115    fn peek_read(&mut self, n: usize) -> Option<&[u8]> {
116        self.buffer.get(..n)
117    }
118
119    fn consume(&mut self, n: usize) {
120        self.buffer = &self.buffer[n..];
121    }
122}
123
124/// Represents a type that can only be encoded with a [`TurboBincodeEncoder`].
125///
126/// All traits implementing this must also implement the more generic [`Encode`] trait, but they
127/// should panic if any other encoder is used.
128///
129/// Use [`impl_encode_for_turbo_bincode_encode`] to automatically implement the [`Encode`] trait
130/// from this one.
131pub trait TurboBincodeEncode: Encode {
132    fn encode(&self, encoder: &mut TurboBincodeEncoder) -> Result<(), EncodeError>;
133}
134
135/// Represents a type that can only be decoded with a [`TurboBincodeDecoder`] and an empty `()`
136/// context.
137///
138/// All traits implementing this must also implement the more generic [`Decode`] trait, but they
139/// should panic if any other encoder is used.
140///
141/// Use [`impl_decode_for_turbo_bincode_decode`] to automatically implement the [`Decode`] trait
142/// from this one.
143pub trait TurboBincodeDecode<Context>: Decode<Context> {
144    fn decode(decoder: &mut TurboBincodeDecoder) -> Result<Self, DecodeError>;
145}
146
147#[macro_export]
148macro_rules! impl_encode_for_turbo_bincode_encode {
149    ($ty:ty) => {
150        impl $crate::macro_helpers::bincode::Encode for $ty {
151            fn encode<'a, E: $crate::macro_helpers::bincode::enc::Encoder>(
152                &self,
153                encoder: &'a mut E,
154            ) -> ::std::result::Result<(), $crate::macro_helpers::bincode::error::EncodeError> {
155                $crate::macro_helpers::encode_for_turbo_bincode_encode_impl(self, encoder)
156            }
157        }
158    };
159}
160
161#[macro_export]
162macro_rules! impl_decode_for_turbo_bincode_decode {
163    ($ty:ty) => {
164        impl<Context> $crate::macro_helpers::bincode::Decode<Context> for $ty {
165            fn decode<D: $crate::macro_helpers::bincode::de::Decoder<Context = Context>>(
166                decoder: &mut D,
167            ) -> ::std::result::Result<Self, $crate::macro_helpers::bincode::error::DecodeError>
168            {
169                $crate::macro_helpers::decode_for_turbo_bincode_decode_impl(decoder)
170            }
171        }
172    };
173}
174
175pub mod indexmap {
176    use std::hash::{BuildHasher, Hash};
177
178    use ::indexmap::IndexMap;
179
180    use super::*;
181
182    pub fn encode<E, K, V, S>(map: &IndexMap<K, V, S>, encoder: &mut E) -> Result<(), EncodeError>
183    where
184        E: Encoder,
185        K: Encode,
186        V: Encode,
187    {
188        usize::encode(&map.len(), encoder)?;
189        for (k, v) in map {
190            K::encode(k, encoder)?;
191            V::encode(v, encoder)?;
192        }
193        Ok(())
194    }
195
196    pub fn decode<Context, D, K, V, S>(decoder: &mut D) -> Result<IndexMap<K, V, S>, DecodeError>
197    where
198        D: Decoder<Context = Context>,
199        K: Decode<Context> + Eq + Hash,
200        V: Decode<Context>,
201        S: BuildHasher + Default,
202    {
203        let len = usize::decode(decoder)?;
204        let mut map = IndexMap::with_capacity_and_hasher(len, Default::default());
205        for _i in 0..len {
206            map.insert(K::decode(decoder)?, V::decode(decoder)?);
207        }
208        Ok(map)
209    }
210
211    pub fn borrow_decode<'de, Context, D, K, V, S>(
212        decoder: &mut D,
213    ) -> Result<IndexMap<K, V, S>, DecodeError>
214    where
215        D: BorrowDecoder<'de, Context = Context>,
216        K: BorrowDecode<'de, Context> + Eq + Hash,
217        V: BorrowDecode<'de, Context>,
218        S: BuildHasher + Default,
219    {
220        let len = usize::decode(decoder)?;
221        let mut map = IndexMap::with_capacity_and_hasher(len, Default::default());
222        for _i in 0..len {
223            map.insert(K::borrow_decode(decoder)?, V::borrow_decode(decoder)?);
224        }
225        Ok(map)
226    }
227
228    #[cfg(test)]
229    mod tests {
230        use bincode::{decode_from_slice, encode_to_vec};
231
232        use super::*;
233
234        #[test]
235        fn test_roundtrip() {
236            let cfg = bincode::config::standard();
237
238            #[derive(Encode, Decode)]
239            struct Wrapper(#[bincode(with = "crate::indexmap")] IndexMap<String, u32>);
240
241            let map1 = Wrapper(IndexMap::from([
242                ("key1".to_string(), 12345u32),
243                ("key2".to_string(), 23456u32),
244            ]));
245
246            let map2: Wrapper = decode_from_slice(&encode_to_vec(&map1, cfg).unwrap(), cfg)
247                .unwrap()
248                .0;
249
250            assert_eq!(map1.0, map2.0);
251        }
252    }
253}
254
255pub mod indexset {
256    use std::hash::{BuildHasher, Hash};
257
258    use ::indexmap::IndexSet;
259
260    use super::*;
261
262    pub fn encode<E, T, S>(set: &IndexSet<T, S>, encoder: &mut E) -> Result<(), EncodeError>
263    where
264        E: Encoder,
265        T: Encode,
266    {
267        usize::encode(&set.len(), encoder)?;
268        for item in set {
269            T::encode(item, encoder)?;
270        }
271        Ok(())
272    }
273
274    pub fn decode<Context, D, T, S>(decoder: &mut D) -> Result<IndexSet<T, S>, DecodeError>
275    where
276        D: Decoder<Context = Context>,
277        T: Decode<Context> + Eq + Hash,
278        S: BuildHasher + Default,
279    {
280        let len = usize::decode(decoder)?;
281        let mut set = IndexSet::with_capacity_and_hasher(len, Default::default());
282        for _i in 0..len {
283            set.insert(T::decode(decoder)?);
284        }
285        Ok(set)
286    }
287
288    pub fn borrow_decode<'de, Context, D, T, S>(
289        decoder: &mut D,
290    ) -> Result<IndexSet<T, S>, DecodeError>
291    where
292        D: BorrowDecoder<'de, Context = Context>,
293        T: BorrowDecode<'de, Context> + Eq + Hash,
294        S: BuildHasher + Default,
295    {
296        let len = usize::decode(decoder)?;
297        let mut set = IndexSet::with_capacity_and_hasher(len, Default::default());
298        for _i in 0..len {
299            set.insert(T::borrow_decode(decoder)?);
300        }
301        Ok(set)
302    }
303
304    #[cfg(test)]
305    mod tests {
306        use bincode::{decode_from_slice, encode_to_vec};
307
308        use super::*;
309
310        #[test]
311        fn test_roundtrip() {
312            let cfg = bincode::config::standard();
313
314            #[derive(Encode, Decode)]
315            struct Wrapper(#[bincode(with = "crate::indexset")] IndexSet<String>);
316
317            let set1 = Wrapper(IndexSet::from([
318                "value1".to_string(),
319                "value2".to_string(),
320                "value3".to_string(),
321            ]));
322
323            let set2: Wrapper = decode_from_slice(&encode_to_vec(&set1, cfg).unwrap(), cfg)
324                .unwrap()
325                .0;
326
327            assert_eq!(set1.0, set2.0);
328        }
329    }
330}
331
332pub mod ringset {
333    use std::hash::{BuildHasher, Hash};
334
335    use ::ringmap::RingSet;
336
337    use super::*;
338
339    pub fn encode<E, T, S>(set: &RingSet<T, S>, encoder: &mut E) -> Result<(), EncodeError>
340    where
341        E: Encoder,
342        T: Encode,
343    {
344        usize::encode(&set.len(), encoder)?;
345        for item in set {
346            T::encode(item, encoder)?;
347        }
348        Ok(())
349    }
350
351    pub fn decode<Context, D, T, S>(decoder: &mut D) -> Result<RingSet<T, S>, DecodeError>
352    where
353        D: Decoder<Context = Context>,
354        T: Decode<Context> + Eq + Hash,
355        S: BuildHasher + Default,
356    {
357        let len = usize::decode(decoder)?;
358        let mut set = RingSet::with_capacity_and_hasher(len, Default::default());
359        for _i in 0..len {
360            set.insert(T::decode(decoder)?);
361        }
362        Ok(set)
363    }
364
365    pub fn borrow_decode<'de, Context, D, T, S>(
366        decoder: &mut D,
367    ) -> Result<RingSet<T, S>, DecodeError>
368    where
369        D: BorrowDecoder<'de, Context = Context>,
370        T: BorrowDecode<'de, Context> + Eq + Hash,
371        S: BuildHasher + Default,
372    {
373        let len = usize::decode(decoder)?;
374        let mut set = RingSet::with_capacity_and_hasher(len, Default::default());
375        for _i in 0..len {
376            set.insert(T::borrow_decode(decoder)?);
377        }
378        Ok(set)
379    }
380
381    #[cfg(test)]
382    mod tests {
383        use bincode::{decode_from_slice, encode_to_vec};
384
385        use super::*;
386
387        #[test]
388        fn test_roundtrip() {
389            let cfg = bincode::config::standard();
390
391            #[derive(Encode, Decode)]
392            struct Wrapper(#[bincode(with = "crate::ringset")] RingSet<String>);
393
394            let set1 = Wrapper(RingSet::from([
395                "value1".to_string(),
396                "value2".to_string(),
397                "value3".to_string(),
398            ]));
399
400            let set2: Wrapper = decode_from_slice(&encode_to_vec(&set1, cfg).unwrap(), cfg)
401                .unwrap()
402                .0;
403
404            assert_eq!(set1.0, set2.0);
405        }
406    }
407}
408
409pub mod mime_option {
410    use std::str::FromStr;
411
412    use mime::Mime;
413
414    use super::*;
415
416    pub fn encode<E: Encoder>(mime: &Option<Mime>, encoder: &mut E) -> Result<(), EncodeError> {
417        let mime_str: Option<&str> = mime.as_ref().map(AsRef::as_ref);
418        Encode::encode(&mime_str, encoder)
419    }
420
421    pub fn decode<Context, D: Decoder<Context = Context>>(
422        decoder: &mut D,
423    ) -> Result<Option<Mime>, DecodeError> {
424        if let Some(mime_str) = <Option<String> as Decode<Context>>::decode(decoder)? {
425            Ok(Some(
426                Mime::from_str(&mime_str).map_err(|e| DecodeError::OtherString(e.to_string()))?,
427            ))
428        } else {
429            Ok(None)
430        }
431    }
432
433    pub fn borrow_decode<'de, Context, D: BorrowDecoder<'de, Context = Context>>(
434        decoder: &mut D,
435    ) -> Result<Option<Mime>, DecodeError> {
436        decode(decoder)
437    }
438
439    #[cfg(test)]
440    mod tests {
441        use bincode::{decode_from_slice, encode_to_vec};
442
443        use super::*;
444
445        #[derive(Encode, Decode)]
446        struct Wrapper(#[bincode(with = "crate::mime_option")] Option<Mime>);
447
448        #[test]
449        fn test_roundtrip() {
450            let cfg = bincode::config::standard();
451
452            let mime1 = Wrapper(Some("text/html; charset=utf-8".parse().unwrap()));
453
454            let mime2: Wrapper = decode_from_slice(&encode_to_vec(&mime1, cfg).unwrap(), cfg)
455                .unwrap()
456                .0;
457
458            assert_eq!(mime1.0, mime2.0);
459        }
460
461        #[test]
462        fn test_roundtrip_none() {
463            let cfg = bincode::config::standard();
464
465            let mime1 = Wrapper(None);
466
467            let mime2: Wrapper = decode_from_slice(&encode_to_vec(&mime1, cfg).unwrap(), cfg)
468                .unwrap()
469                .0;
470
471            assert_eq!(mime1.0, mime2.0);
472        }
473    }
474}
475
476pub mod either {
477    use ::either::Either;
478
479    use super::*;
480
481    pub fn encode<E: Encoder, L: Encode, R: Encode>(
482        value: &Either<L, R>,
483        encoder: &mut E,
484    ) -> Result<(), EncodeError> {
485        value.is_left().encode(encoder)?;
486        ::either::for_both!(value, v => Encode::encode(v, encoder))
487    }
488
489    pub fn decode<
490        Context,
491        D: Decoder<Context = Context>,
492        L: Decode<Context>,
493        R: Decode<Context>,
494    >(
495        decoder: &mut D,
496    ) -> Result<Either<L, R>, DecodeError> {
497        let is_left = bool::decode(decoder)?;
498        Ok(if is_left {
499            Either::Left(L::decode(decoder)?)
500        } else {
501            Either::Right(R::decode(decoder)?)
502        })
503    }
504
505    pub fn borrow_decode<
506        'de,
507        Context,
508        D: BorrowDecoder<'de, Context = Context>,
509        L: BorrowDecode<'de, Context>,
510        R: BorrowDecode<'de, Context>,
511    >(
512        decoder: &mut D,
513    ) -> Result<Either<L, R>, DecodeError> {
514        let is_left = bool::borrow_decode(decoder)?;
515        Ok(if is_left {
516            Either::Left(L::borrow_decode(decoder)?)
517        } else {
518            Either::Right(R::borrow_decode(decoder)?)
519        })
520    }
521
522    #[cfg(test)]
523    mod tests {
524        use bincode::{decode_from_slice, encode_to_vec};
525
526        use super::*;
527
528        #[derive(Encode, Decode)]
529        struct Wrapper(#[bincode(with = "crate::either")] Either<String, u32>);
530
531        #[test]
532        fn test_roundtrip_left() {
533            let cfg = bincode::config::standard();
534
535            let either1 = Wrapper(Either::Left("hello".to_string()));
536
537            let either2: Wrapper = decode_from_slice(&encode_to_vec(&either1, cfg).unwrap(), cfg)
538                .unwrap()
539                .0;
540
541            assert_eq!(either1.0, either2.0);
542        }
543
544        #[test]
545        fn test_roundtrip_right() {
546            let cfg = bincode::config::standard();
547
548            let either1 = Wrapper(Either::Right(42u32));
549
550            let either2: Wrapper = decode_from_slice(&encode_to_vec(&either1, cfg).unwrap(), cfg)
551                .unwrap()
552                .0;
553
554            assert_eq!(either1.0, either2.0);
555        }
556    }
557}
558
559pub mod smallvec {
560    use ::smallvec::Array;
561
562    use super::*;
563
564    pub fn encode<E: Encoder, A: Array<Item = impl Encode>>(
565        vec: &SmallVec<A>,
566        encoder: &mut E,
567    ) -> Result<(), EncodeError> {
568        usize::encode(&vec.len(), encoder)?;
569        for item in vec {
570            Encode::encode(item, encoder)?;
571        }
572        Ok(())
573    }
574
575    pub fn decode<Context, D: Decoder<Context = Context>, A: Array<Item = impl Decode<Context>>>(
576        decoder: &mut D,
577    ) -> Result<SmallVec<A>, DecodeError> {
578        let len = usize::decode(decoder)?;
579        let mut vec = SmallVec::with_capacity(len);
580        for _ in 0..len {
581            vec.push(Decode::decode(decoder)?);
582        }
583        Ok(vec)
584    }
585
586    pub fn borrow_decode<
587        'de,
588        Context,
589        D: BorrowDecoder<'de, Context = Context>,
590        A: Array<Item = impl BorrowDecode<'de, Context>>,
591    >(
592        decoder: &mut D,
593    ) -> Result<SmallVec<A>, DecodeError> {
594        let len = usize::decode(decoder)?;
595        let mut vec = SmallVec::with_capacity(len);
596        for _ in 0..len {
597            vec.push(BorrowDecode::borrow_decode(decoder)?);
598        }
599        Ok(vec)
600    }
601
602    #[cfg(test)]
603    mod tests {
604        use bincode::{decode_from_slice, encode_to_vec};
605
606        use super::*;
607
608        #[test]
609        fn test_roundtrip() {
610            let cfg = bincode::config::standard();
611
612            #[derive(Encode, Decode)]
613            struct Wrapper(#[bincode(with = "crate::smallvec")] SmallVec<[u32; 4]>);
614
615            let vec1 = Wrapper(SmallVec::from_slice(&[1u32, 2, 3, 4, 5]));
616
617            let vec2: Wrapper = decode_from_slice(&encode_to_vec(&vec1, cfg).unwrap(), cfg)
618                .unwrap()
619                .0;
620
621            assert_eq!(vec1.0, vec2.0);
622        }
623    }
624}
625
626pub mod owned_cow {
627    //! Overrides the default [`BorrowDecode`] implementation to always use the owned representation
628    //! of [`Cow`], so that the resulting [`BorrowDecode`] type is independent of the [`Cow`]'s
629    //! lifetime.
630
631    use std::borrow::Cow;
632
633    use super::*;
634
635    #[allow(clippy::ptr_arg)]
636    pub fn encode<E, T>(cow: &Cow<'_, T>, encoder: &mut E) -> Result<(), EncodeError>
637    where
638        E: Encoder,
639        T: ToOwned + ?Sized,
640        for<'a> &'a T: Encode,
641    {
642        cow.encode(encoder)
643    }
644
645    pub fn decode<'cow, Context, D, T>(decoder: &mut D) -> Result<Cow<'cow, T>, DecodeError>
646    where
647        D: Decoder<Context = Context>,
648        T: ToOwned + ?Sized,
649        <T as ToOwned>::Owned: Decode<Context>,
650    {
651        Decode::decode(decoder)
652    }
653
654    pub fn borrow_decode<'de, 'cow, Context, D, T>(
655        decoder: &mut D,
656    ) -> Result<Cow<'cow, T>, DecodeError>
657    where
658        D: BorrowDecoder<'de, Context = Context>,
659        T: ToOwned + ?Sized,
660        <T as ToOwned>::Owned: Decode<Context>,
661    {
662        Decode::decode(decoder)
663    }
664}