Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Serde Deserialize into one of multiple structs?

Tags:

json

rust

serde

Is there a nice way to tentatively deserialize a JSON into different structs? Couldn't find anything in the docs and unfortunately the structs have "tag" to differentiate as in How to conditionally deserialize JSON to two different variants of an enum?

So far my approach has been like this:

use aws_lambda_events::event::{
    firehose::KinesisFirehoseEvent, kinesis::KinesisEvent,
    kinesis_analytics::KinesisAnalyticsOutputDeliveryEvent,
};
use lambda::{lambda, Context};
use serde_json::Value;

type Error = Box<dyn std::error::Error + Send + Sync + 'static>;
enum MultipleKinesisEvent {
    KinesisEvent(KinesisEvent),
    KinesisFirehoseEvent(KinesisFirehoseEvent),
    KinesisAnalyticsOutputDeliveryEvent(KinesisAnalyticsOutputDeliveryEvent),
    None,
}

#[lambda]
#[tokio::main]
async fn main(event: Value, _: Context) -> Result<String, Error> {
    let multi_kinesis_event = if let Ok(e) = serde_json::from_value::<KinesisEvent>(event.clone()) {
        MultipleKinesisEvent::KinesisEvent(e)
    } else if let Ok(e) = serde_json::from_value::<KinesisFirehoseEvent>(event.clone()) {
        MultipleKinesisEvent::KinesisFirehoseEvent(e)
    } else if let Ok(e) = serde_json::from_value::<KinesisAnalyticsOutputDeliveryEvent>(event) {
        MultipleKinesisEvent::KinesisAnalyticsOutputDeliveryEvent(e)
    } else {
        MultipleKinesisEvent::None
    };

    // code below is just sample

    let s = match multi_kinesis_event {
        MultipleKinesisEvent::KinesisEvent(_) => "Kinesis Data Stream!",
        MultipleKinesisEvent::KinesisFirehoseEvent(_) => "Kinesis Firehose!",
        MultipleKinesisEvent::KinesisAnalyticsOutputDeliveryEvent(_) => "Kinesis Analytics!",
        MultipleKinesisEvent::None => "Not Kinesis!",
    };
    Ok(s.to_owned())
}
like image 216
Cadu Bentzen Avatar asked Oct 29 '25 02:10

Cadu Bentzen


1 Answers

You should use the #untagged option.

use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize, Debug)]
struct KinesisFirehoseEvent {
    x: i32,
    y: i32
}

#[derive(Serialize, Deserialize, Debug)]
struct KinesisEvent(i32);

#[derive(Serialize, Deserialize, Debug)]
#[serde(untagged)]
enum MultipleKinesisEvent {
    KinesisEvent(KinesisEvent),
    KinesisFirehoseEvent(KinesisFirehoseEvent),
    None,
}

fn main() {
    let event = MultipleKinesisEvent::KinesisFirehoseEvent(KinesisFirehoseEvent { x: 1, y: 2 });

    // Convert the Event to a JSON string.
    let serialized = serde_json::to_string(&event).unwrap();

    // Prints serialized = {"x":1,"y":2}
    println!("serialized = {}", serialized);

    // Convert the JSON string back to a MultipleKinesisEvent.
    // Since it is untagged 
    let deserialized: MultipleKinesisEvent = serde_json::from_str(&serialized).unwrap();

    // Prints deserialized = KinesisFirehoseEvent(KinesisFirehoseEvent { x: 1, y: 2 })
    println!("deserialized = {:?}", deserialized);
}

See in playground

Docs for: Untagged

like image 90
Njuguna Mureithi Avatar answered Oct 30 '25 18:10

Njuguna Mureithi



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!