Skip to content

Serde support #56

@vitvakatu

Description

@vitvakatu

It would be nice to have ability to serialize and deserialize storages and pointers with serde. It can be useful in game when you want to save current CGS state. However, it's not easy as I thought before.
Basically, serde isn't a big problem, this test works well after a few lines added:

fn test_serde() {
    #[derive(Serialize, Deserialize)]
    struct Node {
        value: i32,
    }
    let mut storage = Storage::new();
    storage.create(Node { value: 32 });
    storage.create(Node { value: 64 });
    let pointers: Vec<Pointer<Node>> = storage
                                    .iter_all()
                                    .map(|v| storage.pin(&v))
                                    .collect();
    let storage_serialized = serde_json::to_string(&storage).unwrap();
    let storage_deserialized: Storage<Node> = serde_json::from_str(&storage_serialized).unwrap();

    let pointers_serialized = serde_json::to_string(&pointers).unwrap();
    let pointers_deserialized: Vec<Pointer<Node>> = serde_json::from_str(&pointers_serialized).unwrap();

    assert_eq!(storage_deserialized.iter_all().count(), 2);
    assert_eq!(storage_deserialized.iter().count(), 2);
    assert_eq!(storage_deserialized[&pointers_deserialized[0]].value, 32);
}

It's definitely safe to deserialize Storage and pointers. But there is one condition - you must not have any Storage in memory before deserializing.
Each Storage has unique identifier, that is used by pointers to link with specific storage. Identifier is controlled by static AtomicUsize. So, deserialized Storage uses "old" identifier, that isn't valid in the new program state. Pointers to deserialised Storage will be able to retrieve data from user's Storage and vise versa.

How to solve this challenge?

My idea is to provide procedural macro for user-defined structs.
Rough code:

#[derive(FroggySerialize)]
struct MyWorld {
    storage1: Storage<MyType>,
    storage2: Storage<MyAnotherType>,
    pointers: Vec<Pointer>,
    #[serde(skip)] // ability to use serde's attributes
    unnecessary_data: i32,
    necessary_user_data: MyAwesomeType,
}

This macro will provide custom serde::Serialize and serde::Deserialize traits implementation.

  • Serializing
    • sync pending
    • serialize data (we don't even need meta, for example)
  • Deserializing
    • deserialize data
    • update all unique ids both in Storage and Pointer according to current program state
    • deserialize pointers and sync pending

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions