Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deserializing with serde yields invalid type error #167

Closed
Nelarius opened this issue Mar 20, 2022 · 1 comment 路 Fixed by #185
Closed

Deserializing with serde yields invalid type error #167

Nelarius opened this issue Mar 20, 2022 · 1 comment 路 Fixed by #185

Comments

@Nelarius
Copy link

Hello!

I just started using bitvec, thanks for the really cool project! I learned a great deal by reading the documentation. 馃檶

As a fairly novice user of Rust still, I'm stumped with the following behaviour I ran into. Serializing a BitVec to a file, and deserializing from the file yields an invalid type: string "order", expected a borrowed string at ... error. Here's the smallest program that reproduces the issue for me:

use anyhow::{Context, Result};
use bitvec::prelude::*;
use serde::{Deserialize, Serialize};
use std::fs::File;
use std::path::Path;

#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Bits(BitVec);

impl Bits {
    fn new() -> Self {
        let bits = bitvec![0, 1, 1, 0, 1, 0, 0, 1];
        Self(bits)
    }
}

fn main() -> Result<()> {
    let bits = Bits::new();
    let file_path = Path::new("bits.json");

    {
        let writer = File::create(&file_path).unwrap();

        serde_json::to_writer(writer, &bits).unwrap();
    }

    {
        let reader = File::open(file_path).unwrap();
        let decoded: Bits = serde_json::from_reader(reader)
            .with_context(|| format!("Deserializing from {}", file_path.display()))?;

        assert_eq!(bits, decoded);
    }

    Ok(())
}

I expected the deserialization to succeed, yielding an identical Bits instance as the one serialized. I've tried this with both serde_json and bincode, and observed the same result.

I'm still getting smacked around the compiler a lot, so I am actually not quite sure if the issue is on my end or not 馃槄

@jsdw
Copy link

jsdw commented May 4, 2022

This is a "real" bug I think.

I've run into this as well, both using serde_json and serde_value. The minimal reproduction is something like:

use bitvec::{ bitvec, order::Lsb0, vec::BitVec };
use serde::Deserialize;

let original = bitvec![u8, Lsb0; 0, 1, 1, 0, 0, 1, 1, 1, 0];
let json = serde_json::to_value(&original).unwrap();
let out = BitVec::<u8, Lsb0>::deserialize(json);

assert_eq!(out.unwrap(), original);

And the error encountered is:

'serde_impls::serialize::test::serialize_bitvec' panicked at 'called `Result::unwrap()` on an `Err` value: Error("invalid type: string \"bits\", expected a borrowed string", line: 0, column: 0)

Serializing is fine.

When we come to deserialize, I think that thw following happens, leading to the error:

  • The JSON deserializer is handed a BitSeqVisitor.
  • The JSON deserializer calls bitseq_visitor.visit_map(serde_json::MapDeserializer::new(..)) on it.
  • The bitseq_visitor calls map.next_key::<&'de str>()? when it gets this MapDeserializer thing given to it.
  • This ultimately uses serde's StrVisitor to attempt to deserialize to &'de str (and only supports visit_borrowed_string(). This blows up because MapDeserializer calls visit_string() and not visit_borrowed_string().

I wonder whether the fix is as simple as changing the next_key to something like map.next_key::<Cow<'de,str>>()? (although Cows deserializer seems to just deserialize an owned variant and wrap it in Cow::Owned) or just explicitly taking the allocation hit with map.next_key::<String>()? (which still beats not being able to deserialize), or alternately providing a custom type and Deserialize impl for it whose visitor accepts owned or borrowed strings.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants