Deny the clippy::indexing_slicing lint

This commit is contained in:
Oliver Hamlet
2025-04-23 00:16:09 +01:00
parent 10ff304473
commit 0fd0f94c2a
8 changed files with 71 additions and 58 deletions
+8 -5
View File
@@ -28,10 +28,10 @@ impl TryFrom<[u8; HEADER_SIZE - TYPE_ID.len()]> for Header {
fn try_from(value: [u8; HEADER_SIZE - TYPE_ID.len()]) -> Result<Self, Self::Error> {
let header = Self {
type_id: TYPE_ID,
version: to_u32(&value)?,
version: to_u32(&value, 0)?,
archive_type: to_archive_type(&value)?,
file_count: to_u32(&value[8..])?,
file_paths_offset: to_u64(&value[12..])?,
file_count: to_u32(&value, 8)?,
file_paths_offset: to_u64(&value, 12)?,
};
// The header version is 1, 7 or 8 for Fallout 4 and 2 or 3 for Starfield.
@@ -140,8 +140,11 @@ fn trim_slashes(mut path_bytes: &[u8]) -> &[u8] {
}
fn rsplit_on(slice: &[u8], needle: u8) -> Option<(&[u8], &[u8])> {
let index = slice.iter().rposition(|b| *b == needle)?;
Some((&slice[..index], &slice[index + 1..]))
let mut iter = slice.rsplitn(2, |b| *b == needle);
let second = iter.next()?;
let first = iter.next()?;
Some((first, second))
}
fn hash<T: Hash>(value: &T) -> u64 {
+15 -15
View File
@@ -30,14 +30,14 @@ impl TryFrom<[u8; HEADER_SIZE - TYPE_ID.len()]> for Header {
fn try_from(value: [u8; HEADER_SIZE - TYPE_ID.len()]) -> Result<Self, Self::Error> {
let header = Self {
type_id: TYPE_ID,
version: to_u32(&value)?,
records_offset: to_u32(&value[4..])?,
archive_flags: to_u32(&value[8..])?,
folder_count: to_u32(&value[12..])?,
total_file_count: to_u32(&value[16..])?,
total_folder_names_length: to_u32(&value[20..])?,
total_file_names_length: to_u32(&value[24..])?,
content_type_flags: to_u32(&value[28..])?,
version: to_u32(&value, 0)?,
records_offset: to_u32(&value, 4)?,
archive_flags: to_u32(&value, 8)?,
folder_count: to_u32(&value, 12)?,
total_file_count: to_u32(&value, 16)?,
total_folder_names_length: to_u32(&value, 20)?,
total_file_names_length: to_u32(&value, 24)?,
content_type_flags: to_u32(&value, 28)?,
};
if to_usize(header.records_offset) != HEADER_SIZE {
@@ -80,9 +80,9 @@ mod v103 {
}
Ok(FolderRecord {
name_hash: to_u64(value)?,
file_count: to_u32(&value[8..])?,
file_records_offset: to_u32(&value[12..])?,
name_hash: to_u64(value, 0)?,
file_count: to_u32(value, 8)?,
file_records_offset: to_u32(value, 12)?,
})
}
}
@@ -106,9 +106,9 @@ mod v105 {
}
Ok(FolderRecord {
name_hash: to_u64(value)?,
file_count: to_u32(&value[8..])?,
file_records_offset: to_u32(&value[16..])?,
name_hash: to_u64(value, 0)?,
file_count: to_u32(value, 8)?,
file_records_offset: to_u32(value, 16)?,
})
}
}
@@ -197,7 +197,7 @@ fn read_assets_with_header<T: BufRead, const U: usize>(
.chunks_exact(FILE_RECORD_SIZE)
.take(to_usize(folder_record.file_count))
{
let file_hash = to_u64(file_chunk)?;
let file_hash = to_u64(file_chunk, 0)?;
if !file_hashes.insert(file_hash) {
return Err(ArchiveParsingError::HashCollision {
+1 -2
View File
@@ -111,8 +111,7 @@ fn find_associated_archives_with_arbitrary_suffixes(
return false;
}
let Ok(filename) = std::str::from_utf8(&archive_filename.as_bytes()[..plugin_stem_len])
else {
let Some(filename) = archive_filename.get(..plugin_stem_len) else {
return false;
};
+16 -9
View File
@@ -94,20 +94,27 @@ fn get_assets_in_archive(
}
}
pub(super) fn to_u32(bytes: &[u8]) -> Result<u32, ArchiveParsingError> {
pub(super) fn to_u32(bytes: &[u8], start_index: usize) -> Result<u32, ArchiveParsingError> {
const ARRAY_SIZE: usize = to_usize(u32::BITS >> 3);
<[u8; ARRAY_SIZE]>::try_from(&bytes[..ARRAY_SIZE])
.map(u32::from_le_bytes)
.map_err(|_e| slice_too_small(bytes, ARRAY_SIZE))
subarray::<ARRAY_SIZE>(bytes, start_index).map(u32::from_le_bytes)
}
pub(super) fn to_u64(bytes: &[u8]) -> Result<u64, ArchiveParsingError> {
pub(super) fn to_u64(bytes: &[u8], start_index: usize) -> Result<u64, ArchiveParsingError> {
const ARRAY_SIZE: usize = to_usize(u64::BITS >> 3);
subarray::<ARRAY_SIZE>(bytes, start_index).map(u64::from_le_bytes)
}
<[u8; ARRAY_SIZE]>::try_from(&bytes[..ARRAY_SIZE])
.map(u64::from_le_bytes)
.map_err(|_e| slice_too_small(bytes, ARRAY_SIZE))
fn subarray<const SIZE: usize>(
bytes: &[u8],
start_index: usize,
) -> Result<[u8; SIZE], ArchiveParsingError> {
let stop_index = start_index + SIZE;
let bytes = bytes
.get(start_index..stop_index)
.ok_or_else(|| slice_too_small(bytes, stop_index))?;
<[u8; SIZE]>::try_from(bytes).map_err(|_e| slice_too_small(bytes, SIZE))
}
#[expect(
+2 -1
View File
@@ -44,7 +44,7 @@
clippy::get_unwrap,
clippy::host_endian_bytes,
clippy::if_then_some_else_none,
// clippy::indexing_slicing,
clippy::indexing_slicing,
clippy::infinite_loop,
clippy::integer_division,
clippy::integer_division_remainder_used,
@@ -101,6 +101,7 @@
test,
allow(
clippy::assertions_on_result_states,
clippy::indexing_slicing,
clippy::missing_asserts_for_indexing,
clippy::panic,
clippy::unwrap_used,
+5 -20
View File
@@ -335,9 +335,8 @@ impl std::default::Default for MetadataDocument {
}
fn replace_prelude(masterlist: String, prelude: &str) -> String {
let line_ending = detect_line_ending(&masterlist);
if let Some((start, end)) = split_on_prelude(&masterlist) {
let prelude = indent_prelude(prelude, line_ending);
let prelude = indent_prelude(prelude);
format!("{start}{prelude}{end}")
} else {
@@ -345,20 +344,6 @@ fn replace_prelude(masterlist: String, prelude: &str) -> String {
}
}
fn detect_line_ending(masterlist: &str) -> &'static str {
if let Some(pos) = masterlist.rfind('\n') {
if pos == 0 {
"\n"
} else if masterlist.as_bytes()[pos - 1] == b'\r' {
"\r\n"
} else {
"\n"
}
} else {
"\n"
}
}
fn split_on_prelude(masterlist: &str) -> Option<(&str, &str)> {
let (prefix, remainder) = split_on_prelude_start(masterlist)?;
@@ -396,17 +381,17 @@ fn split_on_prelude_start(masterlist: &str) -> Option<(&str, &str)> {
// two steps and there's always the risk of a bug being introduced
// in the middle.
if let Some((prefix, remainder)) = masterlist.split_at_checked(index) {
return Some((prefix, remainder))
return Some((prefix, remainder));
}
}
None
}
}
fn indent_prelude(prelude: &str, line_ending: &str) -> String {
fn indent_prelude(prelude: &str) -> String {
let prelude = ("\n ".to_owned() + &prelude.replace('\n', "\n "))
.replace(&format!(" {line_ending}"), line_ending);
.replace(" \r\n", "\r\n")
.replace(" \n", "\n");
if prelude.ends_with("\n ") {
prelude.trim_end_matches(' ').to_owned()
+20 -6
View File
@@ -996,8 +996,10 @@ fn get_plugins_in_groups<T: SortingPlugin>(
let mut keys = plugins_in_groups.keys().collect::<Vec<_>>();
keys.sort();
for key in keys {
let plugin_names: Vec<_> = plugins_in_groups[key]
.iter()
let plugin_names: Vec<_> = plugins_in_groups
.get(key)
.into_iter()
.flatten()
.map(|i| format!("\"{}\"", graph[*i].name()))
.collect();
logging::debug!("\t{}: {}", key, plugin_names.join(", "));
@@ -1087,13 +1089,25 @@ impl<'a, 'b, 'c, 'd, 'e, T: SortingPlugin> GroupsPathVisitor<'a, 'b, 'c, 'd, 'e,
edge_stack_index: usize,
target_plugins: &[PluginNodeIndex],
) {
let from_plugins = self.edge_stack[edge_stack_index].1;
let Some([from_edge, edges @ ..]) = self.edge_stack.get(edge_stack_index..) else {
if is_log_enabled(LogLevel::Error) {
logging::error!(
"Unexpected invalid edge stack index {} for edge stack {:?}",
edge_stack_index,
self.edge_stack
.iter()
.map(|e| e.0.weight())
.collect::<Vec<_>>()
);
}
return;
};
let path_involves_user_metadata = self.edge_stack[edge_stack_index..]
.iter()
let path_involves_user_metadata = std::iter::once(from_edge)
.chain(edges.iter())
.any(|p| *p.0.weight() == EdgeType::UserLoadAfter);
for from_plugin in from_plugins {
for from_plugin in from_edge.1 {
self.add_edges_from_plugin(*from_plugin, target_plugins, path_involves_user_metadata);
}
}
+4
View File
@@ -32,6 +32,10 @@ pub fn is_compatible(major: u32, minor: u32, _patch: u32) -> bool {
clippy::as_conversions,
reason = "Can't const-convert the byte to a u32 a safer way"
)]
#[expect(
clippy::indexing_slicing,
reason = "Can't const-convert the byte to a u8 a safer way"
)]
const fn parse_u32(value: &str) -> u32 {
let mut acc = 0;
let mut i = 0;