mirror of
https://github.com/loot/libloot.git
synced 2026-07-27 14:16:01 -07:00
Deny the clippy::indexing_slicing lint
This commit is contained in:
+8
-5
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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,
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user