Which JSON structure that works with minimal fuss across Rust, Swift, Kotlin

Viewed 265

I need to pass data from Rust to Android(Kotlin) & iOS(Swift). I can control all the pipelines.

My problem is that different representations change how much effort is in coding the mobile side, what is the "easy/default" in one makes the other side the need to fill manual decode/encode boilerplate (this is what I wish to avoid!).

This is not scalable because I will have dozens of potential structs across the 3 languages.

My ideal is to write not more complex than:

#[derive(Debug, Deserialize, Serialize)]
pub enum Request {
    Menu { company: String },
}
enum Request: Codable {
    case Menu(company:String)
}
@Serializable
sealed class Request {
    @Serializable
    class Menu(val company: String) : Request()
}

This is mostly about enums. Exist many ways to represent enums in json:

https://serde.rs/enum-representations.html

#[derive(Serialize, Deserialize)]
enum Message {
    Request { id: String, method: String, params: Params },
    Response { id: String, result: Value },
}

Externally tagged

{"Request": {"id": "...", "method": "...", "params": {...}}}

Internally tagged

{"type": "Request", "id": "...", "method": "...", "params": {...}}

Adjacently tagged

{"t": "Para", "c": [{...}, {...}]}
{"t": "Str", "c": "the string"}

Untagged

{"id": "...", "method": "...", "params": {...}}

Kotlin serialization looks like the default is "Internally tagged" but Swift is "Externally tagged".

So, how unify all?

1 Answers

I solve it by making the switch on Rust instead with conditional compilation, to match the defaults in the mobile side:


#[cfg(not(target_os = "android"))]
#[derive(Debug, Deserialize, Serialize)]
pub enum Response {
    Menu { modules: Vec<Menu> },
    Fail(JsonError),
}

#[cfg(target_os = "android")]
#[derive(Debug, Deserialize, Serialize)]
#[serde(tag = "type")]
pub enum Response {
    Menu { modules: Vec<Menu> },
    Fail(JsonError),
}
Related