bincode icon indicating copy to clipboard operation
bincode copied to clipboard

Invalid BorrowDecode derive for a struct with a `Cow<'a, [Foo]>` field

Open MoSal opened this issue 1 year ago • 5 comments

use std::borrow::Cow;
use bincode::{Encode, Decode};

#[derive(Debug, Clone, Encode, Decode)]
pub enum Foo {
    A,
    B,
}

#[derive(Debug, Decode, Encode)]
pub(crate) struct FooList<'a>(Cow<'a, [Foo]>);

fn main() {
}

This fails due to the generated:

impl<'__de, 'a> ::bincode::BorrowDecode<'__de> for FooList<'a>
where
    '__de: 'a,
{
    fn borrow_decode<__D: ::bincode::de::BorrowDecoder<'__de>>(
        decoder: &mut __D,
    ) -> core::result::Result<Self, ::bincode::error::DecodeError> {
        Ok(Self {
            0: ::bincode::BorrowDecode::borrow_decode(decoder)?,
        })
    }
}

The error is obviously:

error[E0277]: the trait bound `&[Foo]: BorrowDecode<'_>` is not satisfied

This is due to the assumption that all Cow<'cow, T> uses will have a T where &'cow T: BorrowDecode<'cow> holds?!

MoSal avatar Apr 09 '23 20:04 MoSal

Can you try the lifetimes that are used in this test? https://github.com/bincode-org/bincode/blob/trunk/tests/issues/issue_431.rs

We should improve the ergonomics if this is the case

VictorKoenders avatar Apr 10 '23 07:04 VictorKoenders

Yes. Adding this line above FooList's definition fixes the issue:

#[bincode(borrow_decode_bounds = "&'__de [Foo]: ::bincode::de::BorrowDecode<'__de> + '__de, '__de: 'a")]

But, it happens to be that the real FooList in my code looks like this:


#[derive(Debug, Decode, Encode)]
pub(crate) struct FooList(Cow<'static, [Foo]>);

So a way to pass custom bounds in this case (or a way to skip the generation of BorrowDecode) is still needed. But that's maybe a separate issue.

MoSal avatar Apr 10 '23 16:04 MoSal

It might be easier for you to manually implement decode. You can check target/generated/bincode/FooList_Decode.rs for what the derive generates.

Cow is a bit of an annoying structure for how bincode is currently set up and I'm not sure how to best deal with this in the derive logic.

At the least I think bincode should properly document that anything involving Cow is weird

VictorKoenders avatar Apr 11 '23 08:04 VictorKoenders

It might be easier for you to manually implement decode. You can check target/generated/bincode/FooList_Decode.rs for what the derive generates.

Thanks for the suggestion. I actually already did that using good old cargo expand ;)

I removed the BorrowDecode impls first before reporting the issue, and kept the Decode ones.

Then I added the BorrowDecode ones back with the suggested working bounds.

MoSal avatar Apr 11 '23 22:04 MoSal

The situation of borrow_decode_bounds being ignored if a type has no lifetime param, when a BorrowDecode is going to be generated anyway, is still worth a separate consideration IMHO.

MoSal avatar Apr 11 '23 22:04 MoSal