Skip to content

Commit 2c9ee5e

Browse files
Merge pull request #68 from triblespace/codex/remove-anyhow-dependency-and-update-serializable-trait
Remove anyhow dependency and adopt crate errors
2 parents 471c733 + 4c4d3ba commit 2c9ee5e

File tree

13 files changed

+169
-104
lines changed

13 files changed

+169
-104
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Changelog
22

33
## Unreleased
4+
- Removed the `anyhow` dependency in favor of crate-defined errors and updated
5+
`Serializable` to expose an associated error type for reconstruction.
46
- Prevent panic in `DacsByte::len` by handling empty level lists gracefully.
57
- Embedded section handles in `BitVectorData` and added `BitVectorDataMeta` with
68
`Serializable` support for both `BitVectorData` and `BitVector`, enabling

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ rust-version = "1.61.0"
1717
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
1818

1919
[dependencies]
20-
anyhow = "1.0"
2120
num-traits = "0.2.15"
2221
anybytes = { git = "https://github.com/triblespace/anybytes", features = ["zerocopy", "mmap"] }
2322
zerocopy = "0.8"

INVENTORY.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
common builder use cases.
2424
- Audit remaining constructors for zero-capacity variants and decide whether to
2525
offer explicit `empty` helpers instead of `with_capacity(0)`.
26+
- Evaluate introducing more structured error types per module now that
27+
`anyhow` has been removed, ensuring diagnostics remain precise without
28+
relying on free-form strings.
2629
- Allocate temporary wavelet-matrix buffers from `ByteArea` to avoid
2730
intermediate `Vec` copies and ensure fully contiguous construction.
2831
- Provide a derive or macro to reduce boilerplate when implementing the

src/bit_vector/mod.rs

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,7 @@ use anybytes::area::SectionWriter;
134134
use anybytes::Bytes;
135135
use anybytes::View;
136136

137-
use anyhow::anyhow;
138-
use anyhow::Result;
137+
use crate::error::{Error, Result};
139138

140139
/// Builder that collects raw bits into a zero-copy [`BitVector`].
141140
@@ -189,10 +188,10 @@ impl<'a> BitVectorBuilder<'a> {
189188
/// Returns the `pos`-th bit.
190189
pub fn get_bit(&self, pos: usize) -> Result<bool> {
191190
if self.len <= pos {
192-
return Err(anyhow!(
191+
return Err(Error::invalid_argument(format!(
193192
"pos must be no greater than self.len()={}, but got {pos}.",
194193
self.len
195-
));
194+
)));
196195
}
197196
let word = pos / WORD_LEN;
198197
let pos_in_word = pos % WORD_LEN;
@@ -202,10 +201,10 @@ impl<'a> BitVectorBuilder<'a> {
202201
/// Sets the `pos`-th bit to `bit`.
203202
pub fn set_bit(&mut self, pos: usize, bit: bool) -> Result<()> {
204203
if self.len <= pos {
205-
return Err(anyhow!(
204+
return Err(Error::invalid_argument(format!(
206205
"pos must be no greater than self.len()={}, but got {pos}.",
207206
self.len
208-
));
207+
)));
209208
}
210209
let word = pos / WORD_LEN;
211210
let pos_in_word = pos % WORD_LEN;
@@ -217,11 +216,10 @@ impl<'a> BitVectorBuilder<'a> {
217216
/// Sets all bits in `range` to `bit`.
218217
pub fn set_bits(&mut self, range: std::ops::Range<usize>, bit: bool) -> Result<()> {
219218
if range.end > self.len {
220-
return Err(anyhow!(
219+
return Err(Error::invalid_argument(format!(
221220
"range end must be no greater than self.len()={}, but got {}.",
222-
self.len,
223-
range.end
224-
));
221+
self.len, range.end
222+
)));
225223
}
226224
if range.is_empty() {
227225
return Ok(());
@@ -250,10 +248,10 @@ impl<'a> BitVectorBuilder<'a> {
250248
/// Swaps bits at positions `a` and `b`.
251249
pub fn swap_bits(&mut self, a: usize, b: usize) -> Result<()> {
252250
if a >= self.len || b >= self.len {
253-
return Err(anyhow!(
251+
return Err(Error::invalid_argument(format!(
254252
"positions must be less than self.len()={}, but got {a} and {b}.",
255253
self.len
256-
));
254+
)));
257255
}
258256
if a == b {
259257
return Ok(());
@@ -284,11 +282,10 @@ impl<'a> BitVectorBuilder<'a> {
284282
I: Iterator<Item = bool>,
285283
{
286284
if start > self.len {
287-
return Err(anyhow!(
285+
return Err(Error::invalid_argument(format!(
288286
"start must be no greater than self.len()={}, but got {}.",
289-
self.len,
290-
start
291-
));
287+
self.len, start
288+
)));
292289
}
293290
let mut pos = start;
294291
while pos < self.len {
@@ -390,7 +387,7 @@ impl BitVectorData {
390387

391388
/// Reconstructs the data from zero-copy [`Bytes`] and its metadata.
392389
pub fn from_bytes(meta: BitVectorDataMeta, bytes: Bytes) -> Result<Self> {
393-
let words = meta.handle.view(&bytes).map_err(|e| anyhow::anyhow!(e))?;
390+
let words = meta.handle.view(&bytes)?;
394391
Ok(Self {
395392
words,
396393
len: meta.len,
@@ -439,6 +436,7 @@ impl BitVectorData {
439436

440437
impl Serializable for BitVectorData {
441438
type Meta = BitVectorDataMeta;
439+
type Error = Error;
442440

443441
fn metadata(&self) -> Self::Meta {
444442
BitVectorData::metadata(self)
@@ -700,6 +698,7 @@ impl<I: BitVectorIndex> BitVector<I> {
700698

701699
impl<I: BitVectorIndex> Serializable for BitVector<I> {
702700
type Meta = BitVectorDataMeta;
701+
type Error = Error;
703702

704703
fn metadata(&self) -> Self::Meta {
705704
self.data.metadata()

src/bit_vector/rank9sel/inner.rs

Lines changed: 11 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@
44
use anybytes::Bytes;
55
use anybytes::View;
66

7-
use anyhow::Result;
8-
97
use crate::bit_vector::BitVectorData;
108
use crate::broadword;
9+
use crate::error::{Error, Result};
1110

1211
const BLOCK_LEN: usize = 8;
1312
const SELECT_ONES_PER_HINT: usize = 64 * BLOCK_LEN * 2;
@@ -443,49 +442,25 @@ impl<const SELECT1: bool, const SELECT0: bool> Rank9SelIndex<SELECT1, SELECT0> {
443442
impl<const SELECT1: bool, const SELECT0: bool> Rank9SelIndex<SELECT1, SELECT0> {
444443
/// Reconstructs the index from zero-copy [`Bytes`].
445444
pub fn from_bytes(mut bytes: Bytes) -> Result<Self> {
446-
let len = *bytes
447-
.view_prefix::<usize>()
448-
.map_err(|e| anyhow::anyhow!(e))?;
449-
let brp_len = *bytes
450-
.view_prefix::<usize>()
451-
.map_err(|e| anyhow::anyhow!(e))?;
452-
let block_rank_pairs = bytes
453-
.view_prefix_with_elems::<[usize]>(brp_len)
454-
.map_err(|e| anyhow::anyhow!(e))?;
455-
let has_select1 = *bytes
456-
.view_prefix::<usize>()
457-
.map_err(|e| anyhow::anyhow!(e))?
458-
!= 0;
445+
let len = *bytes.view_prefix::<usize>()?;
446+
let brp_len = *bytes.view_prefix::<usize>()?;
447+
let block_rank_pairs = bytes.view_prefix_with_elems::<[usize]>(brp_len)?;
448+
let has_select1 = *bytes.view_prefix::<usize>()? != 0;
459449
let select1_hints = if has_select1 {
460-
let l = *bytes
461-
.view_prefix::<usize>()
462-
.map_err(|e| anyhow::anyhow!(e))?;
463-
Some(
464-
bytes
465-
.view_prefix_with_elems::<[usize]>(l)
466-
.map_err(|e| anyhow::anyhow!(e))?,
467-
)
450+
let l = *bytes.view_prefix::<usize>()?;
451+
Some(bytes.view_prefix_with_elems::<[usize]>(l)?)
468452
} else {
469453
None
470454
};
471-
let has_select0 = *bytes
472-
.view_prefix::<usize>()
473-
.map_err(|e| anyhow::anyhow!(e))?
474-
!= 0;
455+
let has_select0 = *bytes.view_prefix::<usize>()? != 0;
475456
let select0_hints = if has_select0 {
476-
let l = *bytes
477-
.view_prefix::<usize>()
478-
.map_err(|e| anyhow::anyhow!(e))?;
479-
Some(
480-
bytes
481-
.view_prefix_with_elems::<[usize]>(l)
482-
.map_err(|e| anyhow::anyhow!(e))?,
483-
)
457+
let l = *bytes.view_prefix::<usize>()?;
458+
Some(bytes.view_prefix_with_elems::<[usize]>(l)?)
484459
} else {
485460
None
486461
};
487462
if has_select1 != SELECT1 || has_select0 != SELECT0 {
488-
return Err(anyhow::anyhow!("mismatched hint flags"));
463+
return Err(Error::MismatchedHintFlags);
489464
}
490465
Ok(Self {
491466
len,

src/char_sequences/wavelet_matrix.rs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ use anybytes::area::SectionHandle;
1111
use anybytes::area::SectionWriter;
1212
use anybytes::Bytes;
1313

14-
use anyhow::anyhow;
15-
use anyhow::Result;
14+
use crate::error::{Error, Result};
1615

1716
use crate::bit_vector::Access;
1817
use crate::bit_vector::BitVector;
@@ -120,7 +119,7 @@ impl<'a> WaveletMatrixBuilder<'a> {
120119
writer: &mut SectionWriter<'a>,
121120
) -> Result<Self> {
122121
if len == 0 {
123-
return Err(anyhow!("seq must not be empty."));
122+
return Err(Error::invalid_argument("seq must not be empty."));
124123
}
125124
let alph_width = utils::needed_bits(alph_size);
126125
let mut handles = writer.reserve::<SectionHandle<u64>>(alph_width)?;
@@ -142,13 +141,16 @@ impl<'a> WaveletMatrixBuilder<'a> {
142141
/// Sets the `pos`-th integer to `val`.
143142
pub fn set_int(&mut self, pos: usize, val: usize) -> Result<()> {
144143
if self.len <= pos {
145-
return Err(anyhow!(
144+
return Err(Error::invalid_argument(format!(
146145
"pos must be no greater than self.len()={}, but got {pos}.",
147146
self.len
148-
));
147+
)));
149148
}
150149
if val >= self.alph_size {
151-
return Err(anyhow!("value {} out of range 0..{}", val, self.alph_size));
150+
return Err(Error::invalid_argument(format!(
151+
"value {} out of range 0..{}",
152+
val, self.alph_size
153+
)));
152154
}
153155
for (layer_idx, layer) in self.layers.iter_mut().enumerate() {
154156
let shift = self.alph_width - 1 - layer_idx;
@@ -166,11 +168,10 @@ impl<'a> WaveletMatrixBuilder<'a> {
166168
I: Iterator<Item = usize>,
167169
{
168170
if start > self.len {
169-
return Err(anyhow!(
171+
return Err(Error::invalid_argument(format!(
170172
"start must be no greater than self.len()={}, but got {}.",
171-
self.len,
172-
start
173-
));
173+
self.len, start
174+
)));
174175
}
175176
let mut pos = start;
176177
while pos < self.len {
@@ -806,6 +807,7 @@ where
806807

807808
impl<I: BitVectorIndex> Serializable for WaveletMatrix<I> {
808809
type Meta = WaveletMatrixMeta;
810+
type Error = Error;
809811

810812
fn metadata(&self) -> Self::Meta {
811813
WaveletMatrixMeta {
@@ -817,7 +819,7 @@ impl<I: BitVectorIndex> Serializable for WaveletMatrix<I> {
817819
}
818820

819821
fn from_bytes(meta: Self::Meta, bytes: Bytes) -> Result<Self> {
820-
let handles_view = meta.layers.view(&bytes).map_err(anyhow::Error::from)?;
822+
let handles_view = meta.layers.view(&bytes)?;
821823
let mut layers = Vec::with_capacity(meta.alph_width);
822824
for h in handles_view.as_ref() {
823825
let data = BitVectorData::from_bytes(

src/data.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,13 @@ pub struct IntVectorData {
99

1010
impl IntVectorData {
1111
/// Creates integer vector data from a slice of values.
12-
pub fn from_slice<T: num_traits::ToPrimitive>(vals: &[T]) -> anyhow::Result<Self> {
12+
pub fn from_slice<T: num_traits::ToPrimitive>(vals: &[T]) -> crate::error::Result<Self> {
1313
let mut ints = Vec::with_capacity(vals.len());
1414
for v in vals {
1515
ints.push(
16-
v.to_usize()
17-
.ok_or_else(|| anyhow::anyhow!("vals must be castable"))?,
16+
v.to_usize().ok_or_else(|| {
17+
crate::error::Error::invalid_argument("vals must be castable")
18+
})?,
1819
);
1920
}
2021
Ok(Self { ints })

src/error.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
//! Common error types used throughout the crate.
2+
3+
use std::fmt;
4+
5+
use anybytes::view::ViewError;
6+
7+
/// Result type used across the crate.
8+
pub type Result<T, E = Error> = std::result::Result<T, E>;
9+
10+
/// Error type covering failures across Jerky data structures.
11+
#[derive(Debug)]
12+
pub enum Error {
13+
/// An argument violated preconditions.
14+
InvalidArgument(String),
15+
/// Deserialized metadata was malformed or inconsistent.
16+
InvalidMetadata(String),
17+
/// A mismatch between serialized hint flags and the requested type.
18+
MismatchedHintFlags,
19+
/// Wrapper around [`std::io::Error`] values.
20+
Io(std::io::Error),
21+
/// Wrapper around [`anybytes::ViewError`] values.
22+
View(ViewError),
23+
}
24+
25+
impl Error {
26+
/// Creates an [`Error::InvalidArgument`] with the provided message.
27+
pub fn invalid_argument(msg: impl Into<String>) -> Self {
28+
Self::InvalidArgument(msg.into())
29+
}
30+
31+
/// Creates an [`Error::InvalidMetadata`] with the provided message.
32+
pub fn invalid_metadata(msg: impl Into<String>) -> Self {
33+
Self::InvalidMetadata(msg.into())
34+
}
35+
}
36+
37+
impl fmt::Display for Error {
38+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39+
match self {
40+
Error::InvalidArgument(msg) => write!(f, "{msg}"),
41+
Error::InvalidMetadata(msg) => write!(f, "{msg}"),
42+
Error::MismatchedHintFlags => write!(f, "mismatched hint flags"),
43+
Error::Io(err) => write!(f, "I/O error: {err}"),
44+
Error::View(err) => write!(f, "view error: {err}"),
45+
}
46+
}
47+
}
48+
49+
impl std::error::Error for Error {
50+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
51+
match self {
52+
Error::InvalidArgument(_) | Error::InvalidMetadata(_) | Error::MismatchedHintFlags => {
53+
None
54+
}
55+
Error::Io(err) => Some(err),
56+
Error::View(err) => Some(err),
57+
}
58+
}
59+
}
60+
61+
impl From<std::io::Error> for Error {
62+
fn from(err: std::io::Error) -> Self {
63+
Error::Io(err)
64+
}
65+
}
66+
67+
impl From<ViewError> for Error {
68+
fn from(err: ViewError) -> Self {
69+
Error::View(err)
70+
}
71+
}

0 commit comments

Comments
 (0)