diff --git a/bitcode_derive/src/decode.rs b/bitcode_derive/src/decode.rs index c95f813..4e8e930 100644 --- a/bitcode_derive/src/decode.rs +++ b/bitcode_derive/src/decode.rs @@ -321,6 +321,9 @@ impl crate::shared::Derive<{ Item::COUNT }> for Decode { #[allow(clippy::pedantic)] const _: () = { impl #impl_generics #private::Decode<#de> for #input_ty #where_clause { + #[cfg(debug_assertions)] + type Decoder = #private::BoxDecoder<#decoder_ty>; + #[cfg(not(debug_assertions))] type Decoder = #decoder_ty; } diff --git a/bitcode_derive/src/encode.rs b/bitcode_derive/src/encode.rs index 0ddbdbc..9f47fea 100644 --- a/bitcode_derive/src/encode.rs +++ b/bitcode_derive/src/encode.rs @@ -274,6 +274,9 @@ impl crate::shared::Derive<{ Item::COUNT }> for Encode { #[allow(clippy::pedantic)] const _: () = { impl #impl_generics #private::Encode for #input_ty #where_clause { + #[cfg(debug_assertions)] + type Encoder = #private::BoxEncoder<#encoder_ty>; + #[cfg(not(debug_assertions))] type Encoder = #encoder_ty; } diff --git a/src/derive/debug_box.rs b/src/derive/debug_box.rs new file mode 100644 index 0000000..69350da --- /dev/null +++ b/src/derive/debug_box.rs @@ -0,0 +1,88 @@ +//! [`Box`] indirection for derived encoders/decoders, used only in debug mode +//! to avoid stack overflow. + +use crate::coder::{Buffer, Decoder, Encoder, Result, View}; +use crate::fast::{SliceImpl, Unaligned, VecImpl}; +use alloc::boxed::Box; +use alloc::vec::Vec; +use core::mem::MaybeUninit; +use core::num::NonZeroUsize; + +/// Wraps a derived [`Encoder`] in a [`Box`] and delegates to it. +pub struct BoxEncoder(Box); + +impl Default for BoxEncoder { + #[inline(never)] + fn default() -> Self { + Self(Box::default()) + } +} + +impl Buffer for BoxEncoder { + #[inline(never)] + fn collect_into(&mut self, out: &mut Vec) { + self.0.collect_into(out); + } + + #[inline(never)] + fn reserve(&mut self, additional: NonZeroUsize) { + self.0.reserve(additional); + } +} + +impl> Encoder for BoxEncoder { + #[inline(never)] + fn as_primitive(&mut self) -> Option<&mut VecImpl> + where + T: Sized, + { + self.0.as_primitive() + } + + #[inline(never)] + fn encode(&mut self, t: &T) { + self.0.encode(t); + } + + #[inline(never)] + fn encode_vectored<'a>(&mut self, i: impl Iterator + Clone) + where + T: 'a, + { + self.0.encode_vectored(i); + } +} + +/// Wraps a derived [`Decoder`] in a [`Box`] and delegates to it. +pub struct BoxDecoder(Box); + +impl Default for BoxDecoder { + #[inline(never)] + fn default() -> Self { + Self(Box::default()) + } +} + +impl<'a, D: View<'a>> View<'a> for BoxDecoder { + #[inline(never)] + fn populate(&mut self, input: &mut &'a [u8], length: usize) -> Result<()> { + self.0.populate(input, length) + } +} + +impl<'a, T, D: Decoder<'a, T>> Decoder<'a, T> for BoxDecoder { + #[inline(never)] + fn as_primitive(&mut self) -> Option<&mut SliceImpl<'_, Unaligned>> { + self.0.as_primitive() + } + + #[inline(never)] + fn decode(&mut self) -> T { + self.0.decode() + } + + #[inline(never)] + fn decode_in_place(&mut self, out: &mut MaybeUninit) { + self.0.decode_in_place(out); + } +} diff --git a/src/derive/mod.rs b/src/derive/mod.rs index 235d711..10854ef 100644 --- a/src/derive/mod.rs +++ b/src/derive/mod.rs @@ -7,6 +7,8 @@ use core::num::NonZeroUsize; mod array; mod atomic; pub(crate) mod convert; +#[cfg(feature = "derive")] +mod debug_box; mod duration; mod empty; mod impls; @@ -27,6 +29,7 @@ pub(crate) mod vec; pub mod __private { extern crate alloc; pub use crate::coder::{uninit_field, Buffer, Decoder, Encoder, Result, View}; + pub use crate::derive::debug_box::{BoxDecoder, BoxEncoder}; pub use crate::derive::variant::{VariantDecoder, VariantEncoder}; pub use crate::derive::{Decode, Encode}; pub fn invalid_enum_variant() -> Result {