Skip to content
This repository has been archived by the owner on Mar 25, 2024. It is now read-only.

Crash with Custom Type Deserializer #373

Closed
FishArmy100 opened this issue May 11, 2023 · 2 comments
Closed

Crash with Custom Type Deserializer #373

FishArmy100 opened this issue May 11, 2023 · 2 comments

Comments

@FishArmy100
Copy link

This code crashes with serde_yaml, but not with serde_json. The original example for this code was here

use serde::ser::SerializeMap;
use serde::{Serialize, Serializer, de::Visitor, de::MapAccess, Deserialize, Deserializer};
use std::fmt;

#[derive(Debug)]
struct Custom(String, u32);

impl Serialize for Custom {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut seq = serializer.serialize_map(Some(2))?;
        seq.serialize_entry("first", &self.0)?;
        seq.serialize_entry("second", &self.1)?;
        seq.end()
    }
}

impl<'de> Deserialize<'de> for Custom {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where
            D: Deserializer<'de>
    {
        //deserializer.deserialize_any(CustomVisitor)
        deserializer.deserialize_map(CustomVisitor)
    }
}

struct CustomVisitor;

impl<'de> Visitor<'de> for CustomVisitor {
    type Value = Custom;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "a map with keys 'first' and 'second'")
    }

    fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
    where
        M: MapAccess<'de>
    {
        let mut first = None;
        let mut second = None;

        while let Some(k) = map.next_key::<&str>()? {
            if k == "first" {
                first = Some(map.next_value()?);
            }
            else if k == "second" {
                second = Some(map.next_value()?);
            }
            else {
                return Err(serde::de::Error::custom(&format!("Invalid key: {}", k)));
            }
        }

        if first.is_none() || second.is_none() {
            return Err(serde::de::Error::custom("Missing first or second"));
        }

        Ok(Custom(first.unwrap(), second.unwrap()))
    }
}


fn main() {
    let stru = Custom("lala".to_string(), 123);
    println!("Orig {:?}", stru);

    let serialized = serde_yaml::to_string(&stru).expect("err ser");

    println!("Seri {}", serialized);

    let unse : Custom = serde_yaml::from_str(&serialized).expect("err unser");
    println!("New {:?}", unse);
}

Error message:

thread 'main' panicked at 'err unser: Message("invalid type: string \"first\", expected a borrowed string", Some(Pos { marker: Marker { index: 4, line: 2, cker { index: 4, line: 2, col: 0 }, path: "." }))', src\main.rs:75:59
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
@dtolnay
Copy link
Owner

dtolnay commented May 11, 2023

Seems to work for me. Here is the output I get:

Orig Custom("lala", 123)
Seri first: lala
second: 123

New Custom("lala", 123)

@dtolnay dtolnay closed this as completed May 11, 2023
@mpalmer
Copy link

mpalmer commented May 21, 2023

In case it helps anyone who comes across this issue, I was having the same error reported in this issue, and it turned out that I was using serde_yaml 0.8 (because that was what was listed in the example I was starting from). Upgrading to serde_yaml 0.9 fixed the problem.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants