Skip to content

Fixes issue #585 -> Resolve contains() method returning false for existing string values - #588

Merged
ivmarkov merged 29 commits into
esp-rs:masterfrom
danielmeza:fix-nvs-contains
Jul 30, 2025
Merged

Fixes issue #585 -> Resolve contains() method returning false for existing string values#588
ivmarkov merged 29 commits into
esp-rs:masterfrom
danielmeza:fix-nvs-contains

Conversation

@danielmeza

@danielmeza danielmeza commented Jul 25, 2025

Copy link
Copy Markdown
Contributor

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:

  • 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 #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 📝

  • I have updated existing examples or added new ones (if applicable).
  • I have used cargo fmt command to ensure that all changed code is formatted correctly.
  • I have used cargo clippy command to ensure that all changed code passes latest Clippy nightly lints.
  • My changes were added to the CHANGELOG.md in 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.

…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
Copilot AI review requested due to automatic review settings July 25, 2025 19:07
@danielmeza
danielmeza marked this pull request as draft July 25, 2025 19:08

This comment was marked as outdated.

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.
@danielmeza danielmeza changed the title fix(nvs): resolve contains() method returning false for existing string values Fixes issue #585 -> Resolve contains() method returning false for existing string values Jul 25, 2025
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.
@danielmeza
danielmeza marked this pull request as ready for review July 26, 2025 01:32
@danielmeza
danielmeza requested a review from Copilot July 26, 2025 01:32

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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()-based contains() method with nvs_find_key() implementation that works across all NVS data types
  • Introduces EspKeyValueStorage wrapper for consistent serialized storage behavior, maintaining the original raw storage functionality
  • Adds comprehensive type checking utilities including NvsDataType enum 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

Comment thread src/nvs.rs Outdated
Comment thread src/nvs.rs
Comment thread src/nvs.rs

@ivmarkov ivmarkov left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is the direction. Some small suggestions and nits.

Comment thread src/nvs.rs Outdated
Comment thread src/nvs.rs
Comment thread src/nvs.rs Outdated
Comment thread src/nvs.rs
Comment thread src/nvs.rs
Comment thread src/nvs.rs
Comment thread .cargo/config.toml Outdated
Comment thread src/nvs.rs Outdated
/// - **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>);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you move this struct declaration right above its impl block? This is the current practice in the esp-idf-* crate.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes!! moved.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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+

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about the following idea instead:

  • Since find_key would only be available for IDF v5.3+ (or suchlike), we need an alternative implementation of EspKeyValueStorage that 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 of EspNvs
  • 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?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's address this ^^^ too.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just keep a single version - the old one.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!!

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.
Comment thread src/nvs.rs Outdated
Comment thread src/nvs.rs Outdated
Comment thread src/nvs.rs
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).
@ivmarkov

Copy link
Copy Markdown
Collaborator

Current CI fails because of a no-longer necessary mut in the examples. Can you fix this?

Also see my earlier comment on how the EspKeyValueStorage should work - ideally, it should not rely on find_key, and thus it should be available for earlier IDFs as well.

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.
@danielmeza
danielmeza requested a review from ivmarkov July 30, 2025 17:33

@ivmarkov ivmarkov left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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!

@ivmarkov
ivmarkov merged commit 6f6c2c8 into esp-rs:master Jul 30, 2025
20 checks passed
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.

ESP-IDF-SVC NVS contains() Bug Report - String Values Not Detected

4 participants