Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SavedStruct: Introduce saved_struct_get_metadata #3392

Merged
merged 4 commits into from
Mar 25, 2024

Conversation

CookiePLMonster
Copy link
Contributor

@CookiePLMonster CookiePLMonster commented Jan 24, 2024

What's new

This PR makes two changes to the SavedStruct toolbox lib:

  1. Replaced saved_struct_get_payload_size with saved_struct_get_metadata. While the original function compared the magic and version, and only returned the size of the saved data, my replacement obtains the magic and version alongside size.
    • All 3 parameters became optional, as the user might not necessarily care about them all.
    • The functionality of saved_struct_get_payload_size is entirely superseded, so I felt like it's appropriate to replace it instead of adding a new API call.
  2. saved_struct_save gets its data parameter const-qualified. This change needs no further explanation, and since I bumped up the API version with the other change anyway, I went for it. I also const-qualified all the functions in other modules that exclusively called saved_struct_save.

This change allows applications to easier handle backwards compatibility if they desire so. Now, users can obtain the version number from saved_struct_get_metadata and fall back to legacy file handling with a pattern like:

#define VERSION_CURRENT 2

uint8_t version = 0;
saved_struct_get_metadata(file, NULL, &version, NULL);
if (version == VERSION_CURRENT) {
   // Normal load...
} else if (version == 1) {
   // Legacy load...
}

Verification

The following sample app verifies the functionality:

#include <furi.h>

#include <storage/storage.h>
#include <lib/toolbox/saved_struct.h>

#define TAG "SavedStructDemo"

#define SETTINGS_PATH APP_DATA_PATH("save.sav")

#define SETTINGS_VERSION 4
#define SETTINGS_MAGIC 0x95

typedef struct SaveStruct {
    uint32_t saveme1;
    char saveme2[128];

} SaveStruct;

static void save_test(const SaveStruct* data) {
    furi_check(
        saved_struct_save(SETTINGS_PATH, data, sizeof(*data), SETTINGS_MAGIC, SETTINGS_VERSION));
    FURI_LOG_I(TAG, "save_test passed");
}

static void get_metadata_test() {
    size_t size = 0;
    uint8_t magic = 0, version = 0;
    furi_check(
        saved_struct_get_metadata(SETTINGS_PATH, &magic, &version, &size));
    furi_check(magic == SETTINGS_MAGIC && version == SETTINGS_VERSION && size == sizeof(SaveStruct));

    FURI_LOG_I(TAG, "get_metadata_test passed");
}

int32_t saved_struct_demo_app(void* p) {
    UNUSED(p);

    SaveStruct save;
    memset(&save, 0, sizeof(save));

    strlcpy(save.saveme2, "This is saved!", sizeof(save.saveme2));
    save_test(&save);
    get_metadata_test();

    return 0;
}

Checklist (For Reviewer)

  • PR has description of feature/bug or link to Confluence/Jira task
  • Description contains actions to verify feature/bugfix
  • I've built this code, uploaded it to the device and verified feature/bugfix

@CookiePLMonster
Copy link
Contributor Author

Rebased on 0.98.2 and its API level - should be good to go.

@CookiePLMonster
Copy link
Contributor Author

Note: The merge incrementing the minor API version is probably wrong due to the removal of saved_struct_get_payload_size. It should probably become level 56.0.

@skotopes
Copy link
Member

That is true. To be honest I'm still thinking what to do with this PR.

@CookiePLMonster
Copy link
Contributor Author

CookiePLMonster commented Feb 12, 2024

To be honest I'm still thinking what to do with this PR.

The const-correctness change should be unambiguously an improvement, since as far as I can tell it's currently an outlier, and all the other write-esque functions in Furi are const-qualified like this.

I see the metadata function as an improvement over the existing function, because it preserves all the functionality that is currently possible, while also accommodating for additional backwards compatibility-related use cases*. Getters with optional output arguments are also quite common AFAIK (e.g. this approach is used by splitpath).

* Aside from the custom apps (saved struct seems ideal for storing progression/saves in apps), I can foresee this being relevant for example for the Dolphin State - once dolphin's serialized state needs to (IMO inevitably) be expanded, you might not necessarily want to reset everyone's progress, especially if potential future additions end up just adding some extra fields at the end of the state structure.

@skotopes
Copy link
Member

Do you mind if we move this PR to next release?

@CookiePLMonster
Copy link
Contributor Author

Do you mind if we move this PR to next release?

That's fine! It's not a high priority change at all.

@CookiePLMonster
Copy link
Contributor Author

Updated for 0.99.1.

…get_metadata

This new function can obtain the magic value, version and payload size
all at once. This makes the function useful e.g.
for backwards compatibility.
@skotopes skotopes merged commit 8ec1c74 into flipperdevices:dev Mar 25, 2024
11 checks passed
@CookiePLMonster CookiePLMonster deleted the saved-struct-refactor branch May 11, 2024 10:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants