Skip to content

Commit

Permalink
Add a global configuration config::Config with validate_checksums
Browse files Browse the repository at this point in the history
… option
  • Loading branch information
LDeakin committed Feb 5, 2024
1 parent f6c5ab6 commit 4a73044
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 8 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added
- Add a global configuration `config::Config` accessible via `config::{get_config,get_config_mut}`
- Currently it exposes a single configuration option: `validate_checksums` (default: `true`)

## [0.11.5] - 2024-02-05

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "zarrs"
version = "0.11.5"
version = "0.11.6"
authors = ["Lachlan Deakin <[email protected]>"]
edition = "2021"
rust-version = "1.71"
Expand Down
15 changes: 8 additions & 7 deletions src/array/codec/bytes_to_bytes/crc32c/crc32c_codec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,15 @@ impl BytesToBytesCodecTraits for Crc32cCodec {
_parallel: bool,
) -> Result<Vec<u8>, CodecError> {
if encoded_value.len() >= CHECKSUM_SIZE {
let decoded_value = &encoded_value[..encoded_value.len() - CHECKSUM_SIZE];
let checksum = crc32c::crc32c(decoded_value).to_le_bytes();
if checksum == encoded_value[encoded_value.len() - CHECKSUM_SIZE..] {
encoded_value.resize_with(encoded_value.len() - CHECKSUM_SIZE, Default::default);
Ok(encoded_value)
} else {
Err(CodecError::InvalidChecksum)
if crate::config::global_config().validate_checksums() {
let decoded_value = &encoded_value[..encoded_value.len() - CHECKSUM_SIZE];
let checksum = crc32c::crc32c(decoded_value).to_le_bytes();
if checksum != encoded_value[encoded_value.len() - CHECKSUM_SIZE..] {
return Err(CodecError::InvalidChecksum);
}
}
encoded_value.resize_with(encoded_value.len() - CHECKSUM_SIZE, Default::default);
Ok(encoded_value)
} else {
Err(CodecError::Other(
"CRC32C checksum decoder expects a 32 bit input".to_string(),
Expand Down
78 changes: 78 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
//! Zarrs global configuration options.
use std::sync::{OnceLock, RwLock, RwLockReadGuard, RwLockWriteGuard};

/// Global configuration options for the zarrs crate.
///
/// Retrieve the global [`Config`] with [`global_config`] and modify it with [`global_config_mut`].
///
/// ## Configuration Options
///
/// ### Validate Checksums
/// > default: [`true`]
///
/// If enabled, checksum codecs (e.g. `crc32c`) will validate that encoded data matches stored checksums, otherwise validation is skipped.
/// Note that regardless of this configuration option, checksum codecs may skip validation when partial decoding.
#[derive(Debug)]
pub struct Config {
validate_checksums: bool,
}

#[allow(clippy::derivable_impls)]
impl Default for Config {
fn default() -> Self {
Config {
validate_checksums: true,
}
}
}

impl Config {
/// Get the [validate checksums](#validate-checksums) configuration.
#[must_use]
pub fn validate_checksums(&self) -> bool {
self.validate_checksums
}

/// Set the [validate checksums](#validate-checksums) configuration.
pub fn set_validate_checksums(&mut self, validate_checksums: bool) {
self.validate_checksums = validate_checksums;
}
}

static CONFIG: OnceLock<RwLock<Config>> = OnceLock::new();

/// Returns a reference to the global zarrs configuration.
///
/// # Panics
/// This function panics if the underlying lock has been poisoned and might panic if the global config is already held by the current thread.
pub fn global_config() -> RwLockReadGuard<'static, Config> {
CONFIG
.get_or_init(|| RwLock::new(Config::default()))
.read()
.unwrap()
}

/// Returns a mutable reference to the global zarrs configuration.
///
/// # Panics
/// This function panics if the underlying lock has been poisoned and might panic if the global config is already held by the current thread.
pub fn global_config_mut() -> RwLockWriteGuard<'static, Config> {
CONFIG
.get_or_init(|| RwLock::new(Config::default()))
.write()
.unwrap()
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn config_validate_checksums() {
assert!(global_config().validate_checksums());
global_config_mut().set_validate_checksums(false);
assert!(!global_config().validate_checksums());
global_config_mut().set_validate_checksums(true);
}
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
pub mod array;
pub mod array_subset;
pub mod byte_range;
pub mod config;
pub mod group;
pub mod metadata;
pub mod node;
Expand Down

0 comments on commit 4a73044

Please sign in to comment.