i2c: code quality - remove unwrap from dispatch
diff --git a/services/i2c/server/src/lib.rs b/services/i2c/server/src/lib.rs index 96bc46c..b354a23 100644 --- a/services/i2c/server/src/lib.rs +++ b/services/i2c/server/src/lib.rs
@@ -20,6 +20,17 @@ //! in from other drivers. #![no_std] +#![deny( + clippy::unwrap_used, + clippy::expect_used, + clippy::panic, + clippy::unreachable, + clippy::todo, + clippy::unimplemented +)] +// Tests use .unwrap() on zerocopy::Ref of fixed-size buffers we just wrote — +// safe by construction, but clippy can't see that. +#![cfg_attr(test, allow(clippy::unwrap_used))] pub mod loopback; pub mod slave; @@ -95,11 +106,14 @@ return encode_error(response, I2cError::BufferTooSmall); } - // ---- two passes over the descriptor array: first validate + size ---- + // ---- single pass: validate, size, and stash (kind, len) ---- let desc_base = I2cRequestHeader::SIZE; let write_base = desc_base + desc_bytes; let mut write_total = 0usize; let mut read_total = 0usize; + // Stash validated (is_read, len) pairs so the build pass needs no re-parse. + // Using bool avoids matching a #[non_exhaustive] enum a second time. + let mut op_meta = [(false, 0usize); MAX_OPS]; for i in 0..op_count { let off = desc_base + i * I2cOpDesc::SIZE; let Ok(desc) = @@ -108,8 +122,14 @@ return encode_error(response, I2cError::InvalidOperation); }; match desc.op_kind() { - Ok(I2cOpKind::Write) => write_total += desc.length(), - Ok(I2cOpKind::Read) => read_total += desc.length(), + Ok(I2cOpKind::Write) => { + op_meta[i] = (false, desc.length()); + write_total += desc.length(); + } + Ok(I2cOpKind::Read) => { + op_meta[i] = (true, desc.length()); + read_total += desc.length(); + } Ok(_) | Err(_) => return encode_error(response, I2cError::InvalidOperation), } } @@ -121,7 +141,7 @@ return encode_error(response, I2cError::BufferTooSmall); } - // ---- build the Operation list ---- + // ---- build the Operation list from stashed metadata ---- // Reads land in a private scratch (carved into disjoint &mut subslices in // op order) so the borrows of `request` (write data, shared) and the read // area never overlap. The filler `Operation::Write(&[])` is `'static`. @@ -131,22 +151,14 @@ let mut w_off = write_base; let mut read_rem: &mut [u8] = &mut read_scratch[..read_total]; for (i, op) in ops.iter_mut().enumerate().take(op_count) { - let off = desc_base + i * I2cOpDesc::SIZE; - // Re-parsed; validated identical in the sizing pass above. - let desc = zerocopy::Ref::<_, I2cOpDesc>::from_bytes(&request[off..off + I2cOpDesc::SIZE]) - .unwrap(); - let len = desc.length(); - match desc.op_kind() { - Ok(I2cOpKind::Write) => { - *op = Operation::Write(&request[w_off..w_off + len]); - w_off += len; - } - Ok(I2cOpKind::Read) => { - let (head, tail) = read_rem.split_at_mut(len); - *op = Operation::Read(head); - read_rem = tail; - } - Ok(_) | Err(_) => unreachable!("op kinds validated in the sizing pass"), + let (is_read, len) = op_meta[i]; + if is_read { + let (head, tail) = read_rem.split_at_mut(len); + *op = Operation::Read(head); + read_rem = tail; + } else { + *op = Operation::Write(&request[w_off..w_off + len]); + w_off += len; } }