Help using serde-yaml to deserialize value with very many possible types

So, I'm brand new to Rust, and I'm trying to use serde_yaml to deserialize YAML files that represent data from a binary file format (AAMP if anyone cares). It contains parameter fields which can have values of about a dozen types, and the type information must be preserved. The types are specified as YAML type tags, like !color or !str256 or !vec4. For example:

Cloud2_InnerName: !str32 BrightCloud
Cloud2_IntencityShadow: !float 0.03
Cloud2_ColorBackLight: !color [0.497, 1.178, 0.655, 0.0]

So, naturally, I made a Parameter enum for to represent these values, which looks like this (ignore the casing; I plan to fix that):

#[derive(Debug, Deserialize)]
enum Parameter {
    vec2(ArrayVec<[f32; 2]>),
    vec3(ArrayVec<[f32; 3]>),
    vec4(ArrayVec<[f32; 4]>),
    boolean(bool),
    int(i32),
    float(f32),
    curve(Vec<CurveVal>),
    color(Color),
    quat(Quat),
    u(U32),
    str32(String),
    str64(String),
    str256(String),
    string(String),
}

So, what I've found is that this seems to work for parsing some types, but not for any of the sequence types. Types like vec2, vec3, and the rest always lead to a panic with the message "invalid type: sequence, expected string or singleton map." Yet if I manually trim up the test YAML data to only have, say, Vec3 types, and then I replace the reference to the Parameter enum with just ArrayVec<[f32; 3>, it parses fine. It seems specifically to object to mixing the sequences and single types in my one enum, which I don't really understand. Any ideas?

It appears that this is due to a hole in the existing YAML crate ecosystem. Basically, yaml_rust only emits tags on Scalar events, not on SequenceStart or MappingStart, and so serde_yaml is only able to support tags on scalar types.

I created two issues:


For now, you will need to use singleton mappings as a workaround:

- !vec3 [1.0, 0.5, 0.3]  # not currently supported
- vec3: [1.0, 0.5, 0.3]  # valid workaround

Ah, that does clarify things. I don't have the ability to modify the format used originally in the YAML, but I can try working with this by some preprocessing. Thanks.

Hmm, when I try to change it this way (for example, just replacing all instances of !vec3 with vec3: I get "mapping values are not allowed in this context". Is there something else I'm missing?

I'll need to see what the offending piece of yaml looks like.

I think it may have to do with the fact that this occurs itself in a map and not a list, as the sample in your response. For example, after preprocessing, I have a line like this:

  FeatureColor: color: [1.0, 1.0, 1.0, 1.0]

The parameters themselves go inside a map to begin with, like so:

#[derive(Debug, Deserialize)]
struct ParameterObject(HashMap<String, Parameter>);

Ah. Yep, block-style mappings cannot be nested in that manner. You need to do one of the following:

# nested block mapping
FeatureColor:
  color: [1.0, 1.0, 1.0, 1.0]

# flow mapping in block mapping
FeatureColor: { color: [1.0, 1.0, 1.0, 1.0] }

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.