Skip to content

Commit d78f656

Browse files
authored
chore: bump MSRV to 1.88, fix warnings and clippy errors (#1902)
#1899 requires a bump to MSRV 1.88. This version is within the policy of this project, and since the README mentions `MSRV is updated when we release iceberg-rust` and we're preparing 0.8, here's a PR for just MSRV 1.88. ## Which issue does this PR close? <!-- We generally require a GitHub issue to be filed for all bug fixes and enhancements and this helps us generate change logs for our releases. You can link an issue to this PR using the GitHub syntax. For example `Closes #123` indicates that this PR will close issue #123. --> N/A. ## What changes are included in this PR? <!-- Provide a summary of the modifications in this PR. List the main changes such as new features, bug fixes, refactoring, or any other updates. --> - Bump MSRV to 1.88 - Fix warnings - Fix errors found by `make check-clippy` - Format ## Are these changes tested? <!-- Specify what test covers (unit test, integration test, etc.). If tests are not included in your PR, please explain why (for example, are they covered by existing tests)? --> Existing tests
1 parent d973fef commit d78f656

35 files changed

+315
-335
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ version = "0.7.0"
3636
license = "Apache-2.0"
3737
repository = "https://github.com/apache/iceberg-rust"
3838
# Check the MSRV policy in README.md before changing this
39-
rust-version = "1.87"
39+
rust-version = "1.88"
4040

4141
[workspace.dependencies]
4242
anyhow = "1.0.72"

crates/catalog/glue/src/catalog.rs

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -151,33 +151,33 @@ impl GlueCatalog {
151151
async fn new(config: GlueCatalogConfig) -> Result<Self> {
152152
let sdk_config = create_sdk_config(&config.props, config.uri.as_ref()).await;
153153
let mut file_io_props = config.props.clone();
154-
if !file_io_props.contains_key(S3_ACCESS_KEY_ID) {
155-
if let Some(access_key_id) = file_io_props.get(AWS_ACCESS_KEY_ID) {
156-
file_io_props.insert(S3_ACCESS_KEY_ID.to_string(), access_key_id.to_string());
157-
}
154+
if !file_io_props.contains_key(S3_ACCESS_KEY_ID)
155+
&& let Some(access_key_id) = file_io_props.get(AWS_ACCESS_KEY_ID)
156+
{
157+
file_io_props.insert(S3_ACCESS_KEY_ID.to_string(), access_key_id.to_string());
158158
}
159-
if !file_io_props.contains_key(S3_SECRET_ACCESS_KEY) {
160-
if let Some(secret_access_key) = file_io_props.get(AWS_SECRET_ACCESS_KEY) {
161-
file_io_props.insert(
162-
S3_SECRET_ACCESS_KEY.to_string(),
163-
secret_access_key.to_string(),
164-
);
165-
}
159+
if !file_io_props.contains_key(S3_SECRET_ACCESS_KEY)
160+
&& let Some(secret_access_key) = file_io_props.get(AWS_SECRET_ACCESS_KEY)
161+
{
162+
file_io_props.insert(
163+
S3_SECRET_ACCESS_KEY.to_string(),
164+
secret_access_key.to_string(),
165+
);
166166
}
167-
if !file_io_props.contains_key(S3_REGION) {
168-
if let Some(region) = file_io_props.get(AWS_REGION_NAME) {
169-
file_io_props.insert(S3_REGION.to_string(), region.to_string());
170-
}
167+
if !file_io_props.contains_key(S3_REGION)
168+
&& let Some(region) = file_io_props.get(AWS_REGION_NAME)
169+
{
170+
file_io_props.insert(S3_REGION.to_string(), region.to_string());
171171
}
172-
if !file_io_props.contains_key(S3_SESSION_TOKEN) {
173-
if let Some(session_token) = file_io_props.get(AWS_SESSION_TOKEN) {
174-
file_io_props.insert(S3_SESSION_TOKEN.to_string(), session_token.to_string());
175-
}
172+
if !file_io_props.contains_key(S3_SESSION_TOKEN)
173+
&& let Some(session_token) = file_io_props.get(AWS_SESSION_TOKEN)
174+
{
175+
file_io_props.insert(S3_SESSION_TOKEN.to_string(), session_token.to_string());
176176
}
177-
if !file_io_props.contains_key(S3_ENDPOINT) {
178-
if let Some(aws_endpoint) = config.uri.as_ref() {
179-
file_io_props.insert(S3_ENDPOINT.to_string(), aws_endpoint.to_string());
180-
}
177+
if !file_io_props.contains_key(S3_ENDPOINT)
178+
&& let Some(aws_endpoint) = config.uri.as_ref()
179+
{
180+
file_io_props.insert(S3_ENDPOINT.to_string(), aws_endpoint.to_string());
181181
}
182182

183183
let client = aws_sdk_glue::Client::new(&sdk_config);

crates/iceberg/src/arrow/reader.rs

Lines changed: 33 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -504,10 +504,10 @@ impl ArrowReader {
504504
// we need to call next() to update the cache with the newly positioned value.
505505
delete_vector_iter.advance_to(next_row_group_base_idx);
506506
// Only update the cache if the cached value is stale (in the skipped range)
507-
if let Some(cached_idx) = next_deleted_row_idx_opt {
508-
if cached_idx < next_row_group_base_idx {
509-
next_deleted_row_idx_opt = delete_vector_iter.next();
510-
}
507+
if let Some(cached_idx) = next_deleted_row_idx_opt
508+
&& cached_idx < next_row_group_base_idx
509+
{
510+
next_deleted_row_idx_opt = delete_vector_iter.next();
511511
}
512512

513513
// still increment the current page base index but then skip to the next row group
@@ -861,10 +861,10 @@ impl ArrowReader {
861861
};
862862

863863
// If all row groups were filtered out, return an empty RowSelection (select no rows)
864-
if let Some(selected_row_groups) = selected_row_groups {
865-
if selected_row_groups.is_empty() {
866-
return Ok(RowSelection::from(Vec::new()));
867-
}
864+
if let Some(selected_row_groups) = selected_row_groups
865+
&& selected_row_groups.is_empty()
866+
{
867+
return Ok(RowSelection::from(Vec::new()));
868868
}
869869

870870
let mut selected_row_groups_idx = 0;
@@ -897,10 +897,10 @@ impl ArrowReader {
897897

898898
results.push(selections_for_page);
899899

900-
if let Some(selected_row_groups) = selected_row_groups {
901-
if selected_row_groups_idx == selected_row_groups.len() {
902-
break;
903-
}
900+
if let Some(selected_row_groups) = selected_row_groups
901+
&& selected_row_groups_idx == selected_row_groups.len()
902+
{
903+
break;
904904
}
905905
}
906906

@@ -1031,13 +1031,13 @@ fn apply_name_mapping_to_arrow_schema(
10311031

10321032
let mut metadata = field.metadata().clone();
10331033

1034-
if let Some(mapped_field) = mapped_field_opt {
1035-
if let Some(field_id) = mapped_field.field_id() {
1036-
// Field found in mapping with a field_id → assign it
1037-
metadata.insert(PARQUET_FIELD_ID_META_KEY.to_string(), field_id.to_string());
1038-
}
1039-
// If field_id is None, leave the field without an ID (will be filtered by projection)
1034+
if let Some(mapped_field) = mapped_field_opt
1035+
&& let Some(field_id) = mapped_field.field_id()
1036+
{
1037+
// Field found in mapping with a field_id → assign it
1038+
metadata.insert(PARQUET_FIELD_ID_META_KEY.to_string(), field_id.to_string());
10401039
}
1040+
// If field_id is None, leave the field without an ID (will be filtered by projection)
10411041
// If field not found in mapping, leave it without an ID (will be filtered by projection)
10421042

10431043
Field::new(field.name(), field.data_type().clone(), field.is_nullable())
@@ -2731,15 +2731,14 @@ message schema {
27312731
// Step 4: Verify we got 199 rows (not 200)
27322732
let total_rows: usize = result.iter().map(|b| b.num_rows()).sum();
27332733

2734-
println!("Total rows read: {}", total_rows);
2734+
println!("Total rows read: {total_rows}");
27352735
println!("Expected: 199 rows (deleted row 199 which had id=200)");
27362736

27372737
// This assertion will FAIL before the fix and PASS after the fix
27382738
assert_eq!(
27392739
total_rows, 199,
2740-
"Expected 199 rows after deleting row 199, but got {} rows. \
2741-
The bug causes position deletes in later row groups to be ignored.",
2742-
total_rows
2740+
"Expected 199 rows after deleting row 199, but got {total_rows} rows. \
2741+
The bug causes position deletes in later row groups to be ignored."
27432742
);
27442743

27452744
// Verify the deleted row (id=200) is not present
@@ -2950,16 +2949,15 @@ message schema {
29502949
// Row group 1 has 100 rows (ids 101-200), minus 1 delete (id=200) = 99 rows
29512950
let total_rows: usize = result.iter().map(|b| b.num_rows()).sum();
29522951

2953-
println!("Total rows read from row group 1: {}", total_rows);
2952+
println!("Total rows read from row group 1: {total_rows}");
29542953
println!("Expected: 99 rows (row group 1 has 100 rows, 1 delete at position 199)");
29552954

29562955
// This assertion will FAIL before the fix and PASS after the fix
29572956
assert_eq!(
29582957
total_rows, 99,
2959-
"Expected 99 rows from row group 1 after deleting position 199, but got {} rows. \
2958+
"Expected 99 rows from row group 1 after deleting position 199, but got {total_rows} rows. \
29602959
The bug causes position deletes to be lost when advance_to() is followed by next() \
2961-
when skipping unselected row groups.",
2962-
total_rows
2960+
when skipping unselected row groups."
29632961
);
29642962

29652963
// Verify the deleted row (id=200) is not present
@@ -3241,7 +3239,7 @@ message schema {
32413239
start: 0,
32423240
length: 0,
32433241
record_count: None,
3244-
data_file_path: format!("{}/1.parquet", table_location),
3242+
data_file_path: format!("{table_location}/1.parquet"),
32453243
data_file_format: DataFileFormat::Parquet,
32463244
schema: schema.clone(),
32473245
project_field_ids: vec![1, 2],
@@ -3338,7 +3336,7 @@ message schema {
33383336
start: 0,
33393337
length: 0,
33403338
record_count: None,
3341-
data_file_path: format!("{}/1.parquet", table_location),
3339+
data_file_path: format!("{table_location}/1.parquet"),
33423340
data_file_format: DataFileFormat::Parquet,
33433341
schema: schema.clone(),
33443342
project_field_ids: vec![1, 3],
@@ -3424,7 +3422,7 @@ message schema {
34243422
start: 0,
34253423
length: 0,
34263424
record_count: None,
3427-
data_file_path: format!("{}/1.parquet", table_location),
3425+
data_file_path: format!("{table_location}/1.parquet"),
34283426
data_file_format: DataFileFormat::Parquet,
34293427
schema: schema.clone(),
34303428
project_field_ids: vec![1, 2, 3],
@@ -3524,7 +3522,7 @@ message schema {
35243522
start: 0,
35253523
length: 0,
35263524
record_count: None,
3527-
data_file_path: format!("{}/1.parquet", table_location),
3525+
data_file_path: format!("{table_location}/1.parquet"),
35283526
data_file_format: DataFileFormat::Parquet,
35293527
schema: schema.clone(),
35303528
project_field_ids: vec![1, 2],
@@ -3565,7 +3563,7 @@ message schema {
35653563
assert_eq!(all_values.len(), 6);
35663564

35673565
for i in 0..6 {
3568-
assert_eq!(all_names[i], format!("name_{}", i));
3566+
assert_eq!(all_names[i], format!("name_{i}"));
35693567
assert_eq!(all_values[i], i as i32);
35703568
}
35713569
}
@@ -3653,7 +3651,7 @@ message schema {
36533651
start: 0,
36543652
length: 0,
36553653
record_count: None,
3656-
data_file_path: format!("{}/1.parquet", table_location),
3654+
data_file_path: format!("{table_location}/1.parquet"),
36573655
data_file_format: DataFileFormat::Parquet,
36583656
schema: schema.clone(),
36593657
project_field_ids: vec![1, 2],
@@ -3749,7 +3747,7 @@ message schema {
37493747
start: 0,
37503748
length: 0,
37513749
record_count: None,
3752-
data_file_path: format!("{}/1.parquet", table_location),
3750+
data_file_path: format!("{table_location}/1.parquet"),
37533751
data_file_format: DataFileFormat::Parquet,
37543752
schema: schema.clone(),
37553753
project_field_ids: vec![1, 5, 2],
@@ -3858,7 +3856,7 @@ message schema {
38583856
start: 0,
38593857
length: 0,
38603858
record_count: None,
3861-
data_file_path: format!("{}/1.parquet", table_location),
3859+
data_file_path: format!("{table_location}/1.parquet"),
38623860
data_file_format: DataFileFormat::Parquet,
38633861
schema: schema.clone(),
38643862
project_field_ids: vec![1, 2, 3],
@@ -3997,7 +3995,7 @@ message schema {
39973995
start: 0,
39983996
length: 0,
39993997
record_count: None,
4000-
data_file_path: format!("{}/data.parquet", table_location),
3998+
data_file_path: format!("{table_location}/data.parquet"),
40013999
data_file_format: DataFileFormat::Parquet,
40024000
schema: schema.clone(),
40034001
project_field_ids: vec![1, 2],

crates/iceberg/src/arrow/record_batch_projector.rs

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -133,25 +133,24 @@ impl RecordBatchProjector {
133133
{
134134
for (pos, field) in fields.iter().enumerate() {
135135
let id = field_id_fetch_func(field)?;
136-
if let Some(id) = id {
137-
if target_field_id == id {
138-
index_vec.push(pos);
139-
return Ok(Some(field.clone()));
140-
}
136+
if let Some(id) = id
137+
&& target_field_id == id
138+
{
139+
index_vec.push(pos);
140+
return Ok(Some(field.clone()));
141141
}
142-
if let DataType::Struct(inner) = field.data_type() {
143-
if searchable_field_func(field) {
144-
if let Some(res) = Self::fetch_field_index(
145-
inner,
146-
index_vec,
147-
target_field_id,
148-
field_id_fetch_func,
149-
searchable_field_func,
150-
)? {
151-
index_vec.push(pos);
152-
return Ok(Some(res));
153-
}
154-
}
142+
if let DataType::Struct(inner) = field.data_type()
143+
&& searchable_field_func(field)
144+
&& let Some(res) = Self::fetch_field_index(
145+
inner,
146+
index_vec,
147+
target_field_id,
148+
field_id_fetch_func,
149+
searchable_field_func,
150+
)?
151+
{
152+
index_vec.push(pos);
153+
return Ok(Some(res));
155154
}
156155
}
157156
Ok(None)

crates/iceberg/src/arrow/record_batch_transformer.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -582,7 +582,7 @@ impl RecordBatchTransformer {
582582
let this_field_id = field_id_str.parse().map_err(|e| {
583583
Error::new(
584584
ErrorKind::DataInvalid,
585-
format!("field id not parseable as an i32: {}", e),
585+
format!("field id not parseable as an i32: {e}"),
586586
)
587587
})?;
588588

crates/iceberg/src/arrow/value.rs

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -261,15 +261,15 @@ impl SchemaWithPartnerVisitor<ArrayRef> for ArrowArrayToIcebergStructConverter {
261261
"The partner is not a decimal128 array",
262262
)
263263
})?;
264-
if let DataType::Decimal128(arrow_precision, arrow_scale) = array.data_type() {
265-
if *arrow_precision as u32 != *precision || *arrow_scale as u32 != *scale {
266-
return Err(Error::new(
267-
ErrorKind::DataInvalid,
268-
format!(
269-
"The precision or scale ({arrow_precision},{arrow_scale}) of arrow decimal128 array is not compatible with iceberg decimal type ({precision},{scale})"
270-
),
271-
));
272-
}
264+
if let DataType::Decimal128(arrow_precision, arrow_scale) = array.data_type()
265+
&& (*arrow_precision as u32 != *precision || *arrow_scale as u32 != *scale)
266+
{
267+
return Err(Error::new(
268+
ErrorKind::DataInvalid,
269+
format!(
270+
"The precision or scale ({arrow_precision},{arrow_scale}) of arrow decimal128 array is not compatible with iceberg decimal type ({precision},{scale})"
271+
),
272+
));
273273
}
274274
Ok(array.iter().map(|v| v.map(Literal::decimal)).collect())
275275
}
@@ -351,10 +351,10 @@ impl SchemaWithPartnerVisitor<ArrayRef> for ArrowArrayToIcebergStructConverter {
351351
} else if let Some(array) = partner.as_any().downcast_ref::<StringArray>() {
352352
Ok(array.iter().map(|v| v.map(Literal::string)).collect())
353353
} else {
354-
return Err(Error::new(
354+
Err(Error::new(
355355
ErrorKind::DataInvalid,
356356
"The partner is not a string array",
357-
));
357+
))
358358
}
359359
}
360360
PrimitiveType::Uuid => {
@@ -418,10 +418,10 @@ impl SchemaWithPartnerVisitor<ArrayRef> for ArrowArrayToIcebergStructConverter {
418418
.map(|v| v.map(|v| Literal::binary(v.to_vec())))
419419
.collect())
420420
} else {
421-
return Err(Error::new(
421+
Err(Error::new(
422422
ErrorKind::DataInvalid,
423423
"The partner is not a binary array",
424-
));
424+
))
425425
}
426426
}
427427
}
@@ -724,10 +724,7 @@ pub(crate) fn create_primitive_array_single_element(
724724
}
725725
_ => Err(Error::new(
726726
ErrorKind::Unexpected,
727-
format!(
728-
"Unsupported constant type combination: {:?} with {:?}",
729-
data_type, prim_lit
730-
),
727+
format!("Unsupported constant type combination: {data_type:?} with {prim_lit:?}"),
731728
)),
732729
}
733730
}
@@ -825,7 +822,7 @@ pub(crate) fn create_primitive_array_repeated(
825822
(dt, _) => {
826823
return Err(Error::new(
827824
ErrorKind::Unexpected,
828-
format!("unexpected target column type {}", dt),
825+
format!("unexpected target column type {dt}"),
829826
));
830827
}
831828
})

crates/iceberg/src/catalog/mod.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,13 +1000,13 @@ mod _serde_set_statistics {
10001000
snapshot_id,
10011001
statistics,
10021002
} = SetStatistics::deserialize(deserializer)?;
1003-
if let Some(snapshot_id) = snapshot_id {
1004-
if snapshot_id != statistics.snapshot_id {
1005-
return Err(serde::de::Error::custom(format!(
1006-
"Snapshot id to set {snapshot_id} does not match the statistics file snapshot id {}",
1007-
statistics.snapshot_id
1008-
)));
1009-
}
1003+
if let Some(snapshot_id) = snapshot_id
1004+
&& snapshot_id != statistics.snapshot_id
1005+
{
1006+
return Err(serde::de::Error::custom(format!(
1007+
"Snapshot id to set {snapshot_id} does not match the statistics file snapshot id {}",
1008+
statistics.snapshot_id
1009+
)));
10101010
}
10111011

10121012
Ok(statistics)

0 commit comments

Comments
 (0)