Fixes issue #585 -> Resolve contains() method returning false for existing string values - #588
Conversation
…ng values Fixes issue esp-rs#585 where EspNvs::contains() incorrectly returned false for string values that actually existed in NVS partitions. The root cause was that contains() only checked for u64 and blob data types, never checking for string values stored with nvs_set_str(). Changes: - Replace broken len()-based contains() with nvs_get_type() implementation - Add contains_key_of_type() method for type-specific key checking - Add find_key_type() method to retrieve key data types - Add NvsDataType enum with From<nvs_type_t> conversion - Introduce EspKeyValueStorage wrapper for consistent serialized storage behavior The new contains() implementation uses nvs_get_type() to detect any key type, ensuring consistent behavior across all NVS data types (u8, u16, u32, u64, i8, i16, i32, i64, str, blob). Fixes esp-rs#585
Added Debug, Clone, Copy, PartialEq, and Eq derives to the NvsDataType enum. Removed redundant comments from error handling branches in EspNvs methods for improved code clarity.
Refactored the logic in key existence and type checking methods to use the new find_key_type helper, reducing code duplication and improving readability.
Refactored EspKeyValueStorage to use a generic NvsPartitionId and updated its RawStorage implementation. Fixed derive attribute typo for NvsDataType and removed redundant code in contains and remove methods. Improved code clarity and reduced duplication by consolidating remove logic into EspNvs and updating field accesses.
Corrects spacing in field accesses (self.0.1 to self.0 .1) to comply with Rust's parsing rules and avoid ambiguity. No functional changes, only syntax clarification.
Corrects handle usage in NVS erase and commit operations by removing incorrect tuple field access. Updates the default build target in .cargo/config.toml to 'xtensa-esp32-espidf' and comments out the previous RISC-V target.
Replaces calls to EspNvs methods with EspKeyValueStorage methods in the StorageBase implementation, ensuring the correct struct's methods are invoked.
The NvsDataType enum now uses #[repr(u8)] to ensure its discriminants match the underlying type. The From<nvs_type_t> implementation is simplified to a direct cast, reducing boilerplate and improving maintainability.
Introduces a public remove method to EspKeyValueStorage, allowing removal of a key by name and returning a Result indicating success.
Added #[allow(non_upper_case_globals)] to suppress lint warnings in the From<nvs_type_t> implementation for NvsDataType.
Added conditional compilation attributes to the contains, contains_key_of_type, and find_key_type methods in EspNvs to restrict their availability based on esp-idf version. Also updated example to use EspKeyValueStorage instead of EspNvs for raw storage operations.
There was a problem hiding this comment.
Pull Request Overview
This pull request fixes issue #585 where the EspNvs::contains() method incorrectly returned false for string values that existed in NVS partitions. The fix involves replacing the broken length-based contains() implementation with a proper type-checking approach using ESP-IDF's nvs_find_key() API.
Key changes:
- Replaces the faulty
len()-basedcontains()method withnvs_find_key()implementation that works across all NVS data types - Introduces
EspKeyValueStoragewrapper for consistent serialized storage behavior, maintaining the original raw storage functionality - Adds comprehensive type checking utilities including
NvsDataTypeenum and related helper methods
Reviewed Changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/nvs.rs | Main implementation - fixes contains() method and adds EspKeyValueStorage wrapper with type checking utilities |
| examples/nvs_get_set_raw_storage.rs | Updates example to use new EspKeyValueStorage instead of EspNvs |
| .cargo/config.toml | Changes build target from RISC-V to Xtensa ESP32 |
ivmarkov
left a comment
There was a problem hiding this comment.
Yes, this is the direction. Some small suggestions and nits.
| /// - **Large values (>7 bytes)**: Stored as ESP-IDF blobs | ||
| /// - **Memory efficient**: No unnecessary allocations for small values | ||
| /// - **Flash efficient**: Optimized storage format reduces wear on flash memory | ||
| pub struct EspKeyValueStorage<T: NvsPartitionId>(EspNvs<T>); |
There was a problem hiding this comment.
Can you move this struct declaration right above its impl block? This is the current practice in the esp-idf-* crate.
There was a problem hiding this comment.
based on the build issue, we have to keep the old implementation for IDF v5.2 blow, since nvs_find_key is only available from v5.2+
There was a problem hiding this comment.
How about the following idea instead:
- Since
find_keywould only be available for IDF v5.3+ (or suchlike), we need an alternative implementation ofEspKeyValueStoragethat works on older IDFs - However this does not mean we necessarily need to revert to the old implementation, which used to call the raw NVS C APIs from
esp-idf-sys - We rather need an implementation that - while not relying on
find_key- calls only into safe APIs ofEspNvs - This is all possible as the old impl did exactly that. I just want the new impl to do it based on safe EspNvs APIs that's all
I think this is completely possible? We just have "simulate" the missing "contains" method by first calling EspNvs::get_u64 - and if that fails with an error - call EspNvs::get_blob.
Right?
There was a problem hiding this comment.
Let's address this ^^^ too.
There was a problem hiding this comment.
I create 2 implementations, first one v5+ uses find_key and the seconds for v5- uses the safe api and simulate the contains like the old way but this time using the safe API. So I think it should be covered.
Or do we want to keep a single version of this?
There was a problem hiding this comment.
Just keep a single version - the old one.
Updated NvsDataType to use C constant values and changed its repr to u32 for better FFI compatibility. Deprecated EspNvs::contains in favor of find_key, which now returns the type of the key. Refactored EspKeyValueStorage to use the new find_key method, simplified raw get/set logic, and improved type safety and clarity in storage operations.
Introduces conditional implementations of EspKeyValueStorage for different ESP-IDF versions, ensuring compatibility with both v4 and v5.1. Adds trait impls for StorageBase and RawStorage for references to EspKeyValueStorage, and refactors set_raw and remove methods for version-specific mutability requirements.
Simplifies the code by removing an unnecessary return statement in the None branch of the match, directly returning the result of self.0.blob_len(name).
|
Current CI fails because of a no-longer necessary Also see my earlier comment on how the EspKeyValueStorage should work - ideally, it should not rely on |
The 'storage' variable no longer needs to be mutable since it is not mutated after initialization. This simplifies the code and clarifies intent.
Deleted the EspKeyValueStorage implementation for ESP-IDF versions other than 4.x and 5.1, leaving only the version-specific implementation. This simplifies the codebase and removes conditional compilation for unsupported or unused ESP-IDF versions.
ivmarkov
left a comment
There was a problem hiding this comment.
I'll remove the impl<T: NvsPartitionId> StorageBase for &EspKeyValueStorage<T> { as well as the nvs() method, for the reasons already mentioned, but other than that, LGTM! And thanks!
Fixes issue #585 where EspNvs::contains() incorrectly returned false for string values that actually existed in NVS partitions. The root cause was that contains() only checked for u64 and blob data types, never checking for string values stored with nvs_set_str().
Changes:
The new contains() implementation uses nvs_get_type() to detect any key type, ensuring consistent behavior across all NVS data types (u8, u16, u32, u64, i8, i16, i32, i64, str, blob).
Fixes #585
Thank you for your contribution!
We appreciate the time and effort you've put into this pull request.
To help us review it efficiently, please ensure you've gone through the following checklist:
Submission Checklist 📝
cargo fmtcommand to ensure that all changed code is formatted correctly.cargo clippycommand to ensure that all changed code passes latest Clippy nightly lints.CHANGELOG.mdin the proper section.Pull Request Details 📖
Description
Please provide a clear and concise description of your changes, including the motivation behind these changes. The context is crucial for the reviewers.
Testing
Describe how you tested your changes.