diff --git a/CHANGELOG.md b/CHANGELOG.md index e4029c18b..57c466871 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## Unreleased +- Replaced 26 infallible-by-construction `.expect()` sites in `lading_payload` + with `.unwrap_or_else(|| unreachable!("..."))`, making the impossibility + structural and explicit. Sites covered: 20 `CONST_ARR.choose(rng)` against + non-empty `const` arrays, 5 `write!(&mut Vec, ...)` calls (io::Write on + `Vec` never errors), and 3 `Option`-after-guard sites + (`as_mut().expect(...)` post-`ensure_reader()`, `take().expect(...)` + post-`fill_next_block()`, `Byte::from_u64_with_unit(1, MiB)`). No runtime + behavior change. - Removed the transitional `#![allow(clippy::expect_used)]` quarantine from `lading_throttle`. All `.expect()` sites in that crate are under `#[cfg(test)]` or `#[cfg(kani)]`, so the workspace-level diff --git a/lading_payload/src/apache_common.rs b/lading_payload/src/apache_common.rs index 87447ee62..fe08beb00 100644 --- a/lading_payload/src/apache_common.rs +++ b/lading_payload/src/apache_common.rs @@ -30,7 +30,7 @@ impl Distribution for StandardUniform { StatusCode( *STATUS_CODES .choose(rng) - .expect("failed to choose status codes"), + .unwrap_or_else(|| unreachable!("STATUS_CODES is a non-empty const array")), ) } } @@ -354,7 +354,8 @@ impl crate::Serialize for ApacheCommon { let member: Member = self.generate(&mut rng)?; buffer.clear(); // Format into the reusable buffer - write! on Vec is infallible - write!(&mut buffer, "{member}").expect("formatting to Vec cannot fail"); + write!(&mut buffer, "{member}") + .unwrap_or_else(|_| unreachable!("io::Write on Vec never errors")); let line_length = buffer.len() + 1; // add one for the newline match bytes_remaining.checked_sub(line_length) { Some(remainder) => { diff --git a/lading_payload/src/block.rs b/lading_payload/src/block.rs index e10a3a6fb..bbf6be576 100644 --- a/lading_payload/src/block.rs +++ b/lading_payload/src/block.rs @@ -143,13 +143,10 @@ pub fn default_cache_method() -> CacheMethod { /// The default block maximum size. /// -/// # Panics -/// -/// This function will panic if the byte unit conversion fails, which should never happen -/// with the hardcoded value of 1 MiB. #[must_use] pub fn default_maximum_block_size() -> Byte { - Byte::from_u64_with_unit(1, Unit::MiB).expect("catastrophic programming bug") + Byte::from_u64_with_unit(1, Unit::MiB) + .unwrap_or_else(|| unreachable!("1 MiB is always a representable Byte value")) } #[derive(Debug)] diff --git a/lading_payload/src/datadog_logs.rs b/lading_payload/src/datadog_logs.rs index db5f336d2..10107b00b 100644 --- a/lading_payload/src/datadog_logs.rs +++ b/lading_payload/src/datadog_logs.rs @@ -113,14 +113,22 @@ impl<'a> Generator<'a> for DatadogLog { { Ok(Member { message: message(&mut rng, &self.str_pool), - status: STATUSES.choose(rng).expect("failed to generate status"), + status: STATUSES + .choose(rng) + .unwrap_or_else(|| unreachable!("STATUSES is a non-empty const array")), timestamp: rng.random(), - hostname: HOSTNAMES.choose(rng).expect("failed to generate hostnames"), - service: SERVICES.choose(rng).expect("failed to generate services"), - ddsource: SOURCES.choose(rng).expect("failed to generate sources"), + hostname: HOSTNAMES + .choose(rng) + .unwrap_or_else(|| unreachable!("HOSTNAMES is a non-empty const array")), + service: SERVICES + .choose(rng) + .unwrap_or_else(|| unreachable!("SERVICES is a non-empty const array")), + ddsource: SOURCES + .choose(rng) + .unwrap_or_else(|| unreachable!("SOURCES is a non-empty const array")), ddtags: TAG_OPTIONS .choose(rng) - .expect("failed to generate tag options"), + .unwrap_or_else(|| unreachable!("TAG_OPTIONS is a non-empty const array")), }) } } diff --git a/lading_payload/src/dogstatsd.rs b/lading_payload/src/dogstatsd.rs index 72d994fc2..f88839119 100644 --- a/lading_payload/src/dogstatsd.rs +++ b/lading_payload/src/dogstatsd.rs @@ -756,7 +756,8 @@ impl DogStatsD { let member: Member = self.member_generator.generate(&mut rng)?; member_buffer.clear(); // Format into the temporary buffer - write! on Vec is infallible - write!(&mut member_buffer, "{member}").expect("formatting to Vec cannot fail"); + write!(&mut member_buffer, "{member}") + .unwrap_or_else(|_| unreachable!("io::Write on Vec never errors")); let line_length = member_buffer.len() + 1; // add one for the newline if content_buffer.len() + line_length > content_budget { break; @@ -807,7 +808,8 @@ impl DogStatsD { let member: Member = self.member_generator.generate(&mut rng)?; buffer.clear(); // Format into the reusable buffer - write! on Vec is infallible - write!(&mut buffer, "{member}").expect("formatting to Vec cannot fail"); + write!(&mut buffer, "{member}") + .unwrap_or_else(|_| unreachable!("io::Write on Vec never errors")); let line_length = buffer.len() + 1; // add one for the newline match bytes_remaining.checked_sub(line_length) { Some(remainder) => { diff --git a/lading_payload/src/json.rs b/lading_payload/src/json.rs index 79dbc6d9d..193b50944 100644 --- a/lading_payload/src/json.rs +++ b/lading_payload/src/json.rs @@ -28,7 +28,9 @@ impl Distribution for StandardUniform { where R: Rng + ?Sized, { - let max = *SIZES.choose(rng).expect("failed to choose size"); + let max = *SIZES + .choose(rng) + .unwrap_or_else(|| unreachable!("SIZES is a non-empty const array")); // Pre-allocate and fill in one operation rather than iterator-collect. // Using fill() is faster than sample_iter().take().collect() because diff --git a/lading_payload/src/splunk_hec.rs b/lading_payload/src/splunk_hec.rs index 766631277..6b52101ef 100644 --- a/lading_payload/src/splunk_hec.rs +++ b/lading_payload/src/splunk_hec.rs @@ -53,17 +53,27 @@ impl Distribution for StandardUniform { R: Rng + ?Sized, { Attrs { - system_id: SYSTEM_IDS.choose(rng).expect("failed to choose system ids"), - stage: STAGES.choose(rng).expect("failed to choose stages"), + system_id: SYSTEM_IDS + .choose(rng) + .unwrap_or_else(|| unreachable!("SYSTEM_IDS is a non-empty const array")), + stage: STAGES + .choose(rng) + .unwrap_or_else(|| unreachable!("STAGES is a non-empty const array")), event_type: EVENT_TYPES .choose(rng) - .expect("failed to choose event types"), - c2c_service: SERVICES.choose(rng).expect("failed to choose services"), - c2c_partition: PARTITIONS.choose(rng).expect("failed to choose partitions"), - c2c_stage: STAGES.choose(rng).expect("failed to choose stages"), + .unwrap_or_else(|| unreachable!("EVENT_TYPES is a non-empty const array")), + c2c_service: SERVICES + .choose(rng) + .unwrap_or_else(|| unreachable!("SERVICES is a non-empty const array")), + c2c_partition: PARTITIONS + .choose(rng) + .unwrap_or_else(|| unreachable!("PARTITIONS is a non-empty const array")), + c2c_stage: STAGES + .choose(rng) + .unwrap_or_else(|| unreachable!("STAGES is a non-empty const array")), c2c_container_type: CONTAINER_TYPES .choose(rng) - .expect("failed to choose container types"), + .unwrap_or_else(|| unreachable!("CONTAINER_TYPES is a non-empty const array")), aws_account: "verymodelofthemodernmajor", } } @@ -83,7 +93,9 @@ impl Distribution for StandardUniform { { Event { timestamp: 1_606_215_269.333_915, - message: MESSAGES.choose(rng).expect("failed to choose messages"), + message: MESSAGES + .choose(rng) + .unwrap_or_else(|| unreachable!("MESSAGES is a non-empty const array")), attrs: rng.random(), } } @@ -105,8 +117,12 @@ impl Distribution for StandardUniform { Member { event: rng.random(), time: rng.random(), - host: SYSTEM_IDS.choose(rng).expect("failed to choose system ids"), - index: PARTITIONS.choose(rng).expect("failed to choose partitions"), + host: SYSTEM_IDS + .choose(rng) + .unwrap_or_else(|| unreachable!("SYSTEM_IDS is a non-empty const array")), + index: PARTITIONS + .choose(rng) + .unwrap_or_else(|| unreachable!("PARTITIONS is a non-empty const array")), } } } @@ -166,7 +182,7 @@ impl crate::Serialize for SplunkHec { timestamp = event.timestamp, message = event.message ) - .expect("formatting to Vec cannot fail"); + .unwrap_or_else(|_| unreachable!("io::Write on Vec never errors")); serde_json::to_writer(&mut buffer, &event.attrs)?; } Encoding::Json => serde_json::to_writer(&mut buffer, &member)?, diff --git a/lading_payload/src/static_chunks.rs b/lading_payload/src/static_chunks.rs index 65043c55a..3c3e7d374 100644 --- a/lading_payload/src/static_chunks.rs +++ b/lading_payload/src/static_chunks.rs @@ -157,7 +157,7 @@ impl StaticChunks { let reader = self .current_reader .as_mut() - .expect("reader should be present after ensure_reader"); + .unwrap_or_else(|| unreachable!("ensure_reader populates current_reader on Ok")); buf.clear(); let read = reader.read_line(buf)?; diff --git a/lading_payload/src/static_timestamped.rs b/lading_payload/src/static_timestamped.rs index d3b7334c9..c53123548 100644 --- a/lading_payload/src/static_timestamped.rs +++ b/lading_payload/src/static_timestamped.rs @@ -390,7 +390,7 @@ impl crate::Serialize for StaticTimestamped { let block = self .next_block .take() - .expect("fill_next_block guarantees a block"); + .unwrap_or_else(|| unreachable!("fill_next_block populates next_block on Ok")); let mut bytes_written = 0usize; if block.lines.is_empty() { diff --git a/lading_payload/src/syslog.rs b/lading_payload/src/syslog.rs index 7da537285..0381c00d4 100644 --- a/lading_payload/src/syslog.rs +++ b/lading_payload/src/syslog.rs @@ -76,8 +76,12 @@ impl Distribution for StandardUniform { .expect("timestamp in valid range"); ts.format(&Rfc3339).expect("failed to format timestamp") }, - hostname: HOSTNAMES.choose(rng).expect("failed to choose hostname"), - app_name: APP_NAMES.choose(rng).expect("failed to choose app name"), + hostname: HOSTNAMES + .choose(rng) + .unwrap_or_else(|| unreachable!("HOSTNAMES is a non-empty const array")), + app_name: APP_NAMES + .choose(rng) + .unwrap_or_else(|| unreachable!("APP_NAMES is a non-empty const array")), procid: rng.random_range(100..=9999), msgid: rng.random_range(1..=999), message: serde_json::to_string(&rng.random::()).expect("failed to serialize"), @@ -115,7 +119,7 @@ impl crate::Serialize for Syslog5424 { member.msgid, member.message ) - .expect("formatting to Vec cannot fail"); + .unwrap_or_else(|_| unreachable!("io::Write on Vec never errors")); let line_length = buffer.len() + 1; // add one for the newline