-
Notifications
You must be signed in to change notification settings - Fork 4
Rust 1.91.1 #167
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
base: master
Are you sure you want to change the base?
Rust 1.91.1 #167
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR updates the project from Rust 1.90.0 to 1.91.1 (MSRV), bringing numerous code quality improvements including better error handling, simplified code patterns, and dependency updates. The changes focus on making error handling more robust, removing panics in favor of proper error propagation, and modernizing code to use newer Rust idioms.
- Updates MSRV to Rust 1.91.1 and dependency versions in Cargo.lock
- Improves error handling throughout the codebase with better error messages and reduced panic points
- Refactors code for better maintainability (e.g., using
Cow<str>,#[from]derives, consolidated imports)
Reviewed Changes
Copilot reviewed 16 out of 17 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
.github/workflows/rust.yml |
Updates MSRV from 1.90.0 to 1.91.1 |
.github/workflows/release.yml |
Updates MSRV from 1.90.0 to 1.91.1 |
Cargo.lock |
Comprehensive dependency updates for Rust 1.91.1 compatibility |
src/model/account_group.rs |
Removes unused ObjectExt import |
src/model/account_errors.rs |
Improves error messages, consolidates From implementations using #[from] derive, simplifies error() method |
src/model/account.rs |
Refactors TOTP generation with Cow<str>, adds error class removal on success, improves error handling |
src/main_window.rs |
Refactors visibility logic into dedicated method, improves error messages, adds mutex poison handling, consolidates imports |
src/main.rs |
Major refactor of startup error handling to avoid panics, improves logging initialization, better resource loading |
src/helpers/qr_code.rs |
Enhances QR code error messages with more context, adds documentation comments |
src/helpers/paths.rs |
Improves error handling with graceful fallbacks, adds mutex poison handling, enhances logging |
src/helpers/mod.rs |
Reorganizes module declarations (declarations before re-exports) |
src/helpers/migrations.rs |
Updates signature to accept Arc<Mutex<Connection>> for consistency |
src/helpers/keyring.rs |
Consolidates error handling with new Result type alias, removes redundant code, improves consistency |
src/helpers/icon_parser.rs |
Changes selector parsing from panic to graceful failure, improves robustness |
src/helpers/database.rs |
Updates all tests to use Arc<Mutex<Connection>> pattern consistently |
src/helpers/backup.rs |
Simplifies serialization/deserialization code, improves error handling, removes test cases |
src/exporting.rs |
Improves dialog handling, adds better error handling for channel operations, uses .hide() instead of .set_visible(false) |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
src/main.rs
Outdated
| log::error!("Failed to create database connection: {:?}", e); | ||
| exit(1); |
Copilot
AI
Nov 12, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using log::error! before configure_logging() is called (which happens later at line 80-83) means this error message may not be logged according to the application's logging configuration. The logging system needs to be initialized before any log calls are made.
Additionally, line 29 has a similar issue with eprintln! being used but then line 32 tries to log with info!, which will also fail to work correctly before logging is configured.
| widgets.iter_mut().for_each(|group| group.update()); | ||
|
|
||
| // Update TOTP widgets on 0 and 30 seconds (every 30s) | ||
| if seconds.is_multiple_of(30) { |
Copilot
AI
Nov 12, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using is_multiple_of(30) is less clear than the original seconds == 0 || seconds == 30 because it obscures the intent. For second values in range 0-59, both are equivalent, but the explicit comparison makes it immediately obvious that updates happen at 0 and 30 seconds. The new approach requires mental calculation to understand when it triggers.
Consider: Reverting to seconds == 0 || seconds == 30 for better code clarity.
| if seconds.is_multiple_of(30) { | |
| if seconds == 0 || seconds == 30 { |
| let str_account_id = format!("{}", account_id); | ||
| let mut attributes: HashMap<&str, &str> = HashMap::new(); | ||
| attributes.insert(ACCOUNT_ID_KEY, str_account_id.as_str()); | ||
| attributes.insert(APPLICATION_KEY, APPLICATION_VALUE); |
Copilot
AI
Nov 12, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error message "database connection mutex was poisoned" uses io::Error::other() which requires Rust 1.91+. While this matches the MSRV update in the PR, it would be better to use a more specific error type from RepositoryError rather than wrapping it as an IO error, since a poisoned mutex is not truly an I/O error.
Consider: Adding a dedicated RepositoryError::MutexPoisoned variant for better error semantics.
src/helpers/backup.rs
Outdated
| let mut accounts = Self::deserialise_accounts(path.as_path())?; | ||
| let mut account_groups = Self::deserialise_accounts(path.as_path())?; | ||
|
|
||
| let connection = connection.lock().unwrap(); |
Copilot
AI
Nov 12, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using .unwrap() on the mutex lock in production code. This is inconsistent with the approach taken in paths.rs line 65-67 where poisoned mutexes are handled gracefully. If the mutex is poisoned, this will panic.
Consider: Adding proper error handling for poisoned mutex, similar to the pattern in paths.rs.
| let connection = connection.lock().unwrap(); | |
| let connection = match connection.lock() { | |
| Ok(conn) => conn, | |
| Err(poisoned) => { | |
| warn!("Database connection mutex was poisoned. Recovering."); | |
| poisoned.into_inner() | |
| } | |
| }; |
src/helpers/backup.rs
Outdated
| let result = QrCode::process_qr_code(path.to_str().unwrap().to_owned()).await; | ||
| let path_str = path | ||
| .to_str() | ||
| .ok_or_else(|| RepositoryError::IoError(io::Error::new(io::ErrorKind::InvalidInput, "invalid unicode in path")))?; |
Copilot
AI
Nov 12, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error message created here uses io::Error::new(io::ErrorKind::InvalidInput, ...) which is good, but the error message "invalid unicode in path" could be more helpful by indicating what operation failed.
Consider: "Failed to convert path to string: invalid unicode" for better context.
| .ok_or_else(|| RepositoryError::IoError(io::Error::new(io::ErrorKind::InvalidInput, "invalid unicode in path")))?; | |
| .ok_or_else(|| RepositoryError::IoError(io::Error::new(io::ErrorKind::InvalidInput, "Failed to convert path to string: invalid unicode")))?; |
src/model/account.rs
Outdated
| return key; | ||
| } | ||
| let pad = 32 - key.len(); | ||
| key.to_mut().push_str(&"=".repeat(pad).to_string()); |
Copilot
AI
Nov 12, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Redundant .to_string() call. The repeat() method already returns a String, so calling .to_string() on it is unnecessary and creates an extra allocation.
Suggestion: Change to key.to_mut().push_str(&"=".repeat(pad));
| key.to_mut().push_str(&"=".repeat(pad).to_string()); | |
| key.to_mut().push_str(&"=".repeat(pad)); |
| let secret = base32::decode(Alphabet::Rfc4648 { padding: true }, &padded).ok_or_else(|| TotpError::InvalidKey(key.to_string()))?; | ||
|
|
||
| let totp_sha1 = totp_rs::TOTP::new(totp_rs::Algorithm::SHA1, 6, 1, 30, secret)?; | ||
| totp_sha1.generate_current().map_err(TotpError::SystemTimeError) |
Copilot
AI
Nov 12, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error conversion here discards the original SystemTimeError. Since TotpError::SystemTimeError already has a #[from] attribute that handles conversion, this explicit map_err is redundant and loses the automatic conversion benefit.
Suggestion: Change to totp_sha1.generate_current()? to use the automatic conversion from the #[from] attribute.
| totp_sha1.generate_current().map_err(TotpError::SystemTimeError) | |
| totp_sha1.generate_current()? |
src/helpers/migrations.rs
Outdated
| #[allow(clippy::result_large_err)] | ||
| pub fn run(connection: &mut Connection) -> Result<Report, Error> { | ||
| pub fn run(connection: Arc<Mutex<Connection>>) -> Result<Report, Error> { | ||
| let mut connection = connection.lock().unwrap(); |
Copilot
AI
Nov 12, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using .unwrap() on a mutex lock can cause a panic if the mutex is poisoned. Given that this is in a migration function that runs during startup, and other parts of the codebase now handle poisoned mutexes gracefully (e.g., in paths.rs line 67), this should also handle the poisoned mutex case.
Suggestion: Use .map_err() to convert the poison error into a refinery Error or another appropriate error type.
| let mut connection = connection.lock().unwrap(); | |
| let mut connection = connection | |
| .lock() | |
| .map_err(|e| Error::Other(format!("Mutex poisoned while running migrations: {}", e)))?; |
| let selector_1 = Selector::parse(r#"link[rel="apple-touch-icon"]"#).ok(); | ||
| let selector_2 = Selector::parse(r#"link[rel="shortcut icon"]"#).ok(); | ||
| let selector_3 = Selector::parse(r#"link[rel="icon"]"#).ok(); | ||
|
|
||
| let option_1 = document.select(&selector_1).next(); | ||
| let option_2 = document.select(&selector_2).next(); | ||
| let option_3 = document.select(&selector_3).next(); | ||
| let option_1 = selector_1.and_then(|s| document.select(&s).next()); | ||
| let option_2 = selector_2.and_then(|s| document.select(&s).next()); | ||
| let option_3 = selector_3.and_then(|s| document.select(&s).next()); |
Copilot
AI
Nov 12, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The change from .unwrap() to .ok() followed by .and_then() is good for avoiding panics. However, if selector parsing fails (which should never happen with these hardcoded selector strings), the code silently returns no match. While this is acceptable defensive programming, the original .unwrap() would catch programmer errors during development.
This is an acceptable tradeoff, but consider adding debug assertions or comments explaining that these selector strings are known-valid.
|
|
||
| let mut account_groups = AccountGroup::new(0, "GAuth", None, None, false, entries); | ||
|
|
||
| let connection = connection.lock().unwrap(); |
Copilot
AI
Nov 12, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using .unwrap() on the mutex lock in production code. This should handle poisoned mutex errors gracefully, consistent with the error handling improvements made elsewhere in this PR (e.g., paths.rs line 65-67).
| let connection = connection.lock().unwrap(); | |
| let connection = connection.lock().map_err(|e| RepositoryError::MutexPoisonError(format!("{}", e)))?; |
No description provided.