Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ All significant changes to this project will be documented in this file.
### Bug fixes

* `FrequentItemsSketch::serialize` now writes the full 8-byte preamble for an empty sketch, matching the Java and C++ encoding. Empty sketches previously serialized to 6 bytes, which `FrequentItemsSketch::deserialize` rejected with an insufficient-data error.
* `CpcSketch` and `CpcWrapper` now classify out-of-range fields in serialized images as `InvalidData` rather than `InvalidArgument`.

## v0.3.0 (2026-05-18)

Expand Down
7 changes: 2 additions & 5 deletions datasketches/src/cpc/sketch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -630,13 +630,10 @@ impl CpcSketch {
ErrorKind::InvalidData,
)?;
if !(MIN_LG_K..=MAX_LG_K).contains(&lg_k) {
return Err(Error::invalid_argument(format!(
"lg_k out of range; got {}",
lg_k
)));
return Err(Error::deserial(format!("lg_k out of range; got {}", lg_k)));
}
if first_interesting_column > 63 {
return Err(Error::invalid_argument(format!(
return Err(Error::deserial(format!(
"first_interesting_column out of range; got {}",
first_interesting_column
)));
Expand Down
7 changes: 2 additions & 5 deletions datasketches/src/cpc/wrapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,10 @@ impl CpcWrapper {
.read_u8()
.map_err(insufficient_data("first_interesting_column"))?;
if !(MIN_LG_K..=MAX_LG_K).contains(&lg_k) {
return Err(Error::invalid_argument(format!(
"lg_k out of range; got {}",
lg_k
)));
return Err(Error::deserial(format!("lg_k out of range; got {}", lg_k)));
}
if first_interesting_column > 63 {
return Err(Error::invalid_argument(format!(
return Err(Error::deserial(format!(
"first_interesting_column out of range; got {}",
first_interesting_column
)));
Expand Down
4 changes: 2 additions & 2 deletions datasketches/src/thetafamily/common/intersection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,8 +243,8 @@ where
self.table.estimated_size()
}

/// Return the current intersection state as compact-sketch parts.
pub fn result(&self, ordered: bool) -> CompactSketchParts<E>
/// Returns the current intersection state as compact-sketch parts.
pub fn to_compact_parts(&self, ordered: bool) -> CompactSketchParts<E>
where
E: Clone,
{
Expand Down
2 changes: 1 addition & 1 deletion datasketches/src/thetafamily/common/jaccard_similarity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ where
let mut intersection = IntersectionState::new(seed, NoopMergePolicy);
intersection.update(KeyEntries(sketch_a))?;
intersection.update(KeyEntries(sketch_b))?;
let intersection = intersection.result(false);
let intersection = intersection.to_compact_parts(false);
let intersection_count = intersection
.entries
.iter()
Expand Down
2 changes: 1 addition & 1 deletion datasketches/src/thetafamily/theta/intersection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ impl ThetaIntersection {
self.state.has_result(),
"ThetaIntersection::to_sketch() called before first update()"
);
let parts = self.state.result(ordered);
let parts = self.state.to_compact_parts(ordered);
CompactThetaSketch::from_parts(
parts
.entries
Expand Down
2 changes: 1 addition & 1 deletion datasketches/src/thetafamily/tuple/intersection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ where
self.state.has_result(),
"TupleIntersection::to_sketch() called before first update()"
);
let parts = self.state.result(ordered);
let parts = self.state.to_compact_parts(ordered);
CompactTupleSketch::from_parts(
parts.entries,
parts.theta,
Expand Down
23 changes: 23 additions & 0 deletions datasketches/tests/cpc_test/wrapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use datasketches::common::NumStdDev;
use datasketches::cpc::CpcSketch;
use datasketches::cpc::CpcUnion;
use datasketches::cpc::CpcWrapper;
use datasketches::error::ErrorKind;
use googletest::assert_that;
use googletest::prelude::contains_substring;
use googletest::prelude::eq;
Expand Down Expand Up @@ -90,3 +91,25 @@ fn test_is_compressed() {
contains_substring("only compressed sketches are supported")
);
}

#[test]
fn test_invalid_image_fields_are_invalid_data() {
let original = CpcSketch::new(10).serialize();

for (index, value, field) in [
(3, 3, "lg_k"),
(3, 27, "lg_k"),
(4, 64, "first_interesting_column"),
] {
let mut bytes = original.clone();
bytes[index] = value;

let sketch_err = CpcSketch::deserialize(&bytes).unwrap_err();
assert_that!(sketch_err.kind(), eq(ErrorKind::InvalidData));
assert_that!(sketch_err.message(), contains_substring(field));

let wrapper_err = CpcWrapper::new(&bytes).unwrap_err();
assert_that!(wrapper_err.kind(), eq(ErrorKind::InvalidData));
assert_that!(wrapper_err.message(), contains_substring(field));
}
}