Skip to content

Commit f8c1fae

Browse files
committed
refactor: make gxhash optional for docs.rs compatibility
- Make gxhash dependency optional with feature flag (enabled by default) - Add collections abstraction layer to switch between gxhash and std collections - Update all imports to use new collections module - Configure docs.rs to build without gxhash to avoid CPU feature requirements - Maintain performance benefits in normal builds while enabling docs.rs builds This change allows the project to build successfully on docs.rs which has restrictions on CPU-specific features, while preserving the performance advantages of gxhash for regular builds.
1 parent ab1ab2a commit f8c1fae

11 files changed

Lines changed: 92 additions & 13 deletions

File tree

Cargo.toml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ keywords = ["checkpoint", "snapshot", "backup", "time-travel", "versioning"]
1111
categories = ["filesystem", "data-structures"]
1212

1313
[features]
14-
default = []
14+
default = ["gxhash"]
1515
quick-bench = []
16+
gxhash = ["dep:gxhash"]
1617

1718
[dependencies]
1819
# Serialization
@@ -23,7 +24,7 @@ bincode = { version = "2.0", features = ["serde"] }
2324
# Hashing and Compression
2425
sha2 = "0.10"
2526
lz4_flex = "0.11"
26-
gxhash = "3.5" # Fast non-cryptographic hash algorithm
27+
gxhash = { version = "3.5", optional = true } # Fast non-cryptographic hash algorithm
2728

2829
# File system operations
2930
walkdir = "2.5"
@@ -100,3 +101,7 @@ required-features = ["rmcp", "schemars"]
100101
[[bench]]
101102
name = "titor_bench"
102103
harness = false
104+
105+
[package.metadata.docs.rs]
106+
# Build docs without gxhash to avoid CPU feature requirements
107+
no-default-features = true

src/checkpoint.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ use crate::error::Result;
4949
use chrono::{DateTime, Utc};
5050
use serde::{Deserialize, Serialize};
5151
use sha2::{Digest, Sha256};
52-
use gxhash::HashMap;
52+
use crate::collections::HashMap;
5353

5454
/// Represents a checkpoint in the timeline
5555
///
@@ -314,7 +314,7 @@ impl Checkpoint {
314314
///
315315
/// ```rust
316316
/// # use titor::checkpoint::{Checkpoint, CheckpointMetadataBuilder};
317-
/// # use gxhash::{HashMap, HashMapExt};
317+
/// # use crate::collections::{HashMap, HashMapExt};
318318
/// # let checkpoint = Checkpoint::new(Some("parent".to_string()), None, CheckpointMetadataBuilder::new().build(), "".to_string());
319319
/// # let checkpoints = HashMap::new();
320320
/// if checkpoint.is_descendant_of("root-id", &checkpoints) {
@@ -355,7 +355,7 @@ impl Checkpoint {
355355
///
356356
/// ```rust
357357
/// # use titor::checkpoint::{Checkpoint, CheckpointMetadataBuilder};
358-
/// # use gxhash::{HashMap, HashMapExt};
358+
/// # use crate::collections::{HashMap, HashMapExt};
359359
/// # let checkpoint = Checkpoint::new(Some("parent".to_string()), None, CheckpointMetadataBuilder::new().build(), "".to_string());
360360
/// # let checkpoints = HashMap::new();
361361
/// let chain = checkpoint.get_parent_chain(&checkpoints);
@@ -596,7 +596,7 @@ impl CheckpointMetadataBuilder {
596596
#[cfg(test)]
597597
mod tests {
598598
use super::*;
599-
use gxhash::HashMapExt;
599+
use crate::collections::HashMapExt;
600600

601601
#[test]
602602
fn test_checkpoint_creation() {

src/collections.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
//! Collection type aliases that switch between gxhash and std collections
2+
//! based on feature flags. This allows building on docs.rs without CPU-specific
3+
//! requirements while maintaining performance in normal builds.
4+
5+
#[cfg(feature = "gxhash")]
6+
pub use gxhash::{
7+
HashMap as GxHashMap, HashMapExt, HashSet as GxHashSet, HashSetExt, GxBuildHasher,
8+
};
9+
10+
#[cfg(not(feature = "gxhash"))]
11+
use std::collections::{HashMap as StdHashMap, HashSet as StdHashSet};
12+
13+
/// Type alias for HashMap that uses gxhash when available, std otherwise
14+
#[cfg(feature = "gxhash")]
15+
pub type HashMap<K, V> = GxHashMap<K, V>;
16+
17+
/// Type alias for HashMap that uses gxhash when available, std otherwise
18+
#[cfg(not(feature = "gxhash"))]
19+
pub type HashMap<K, V> = StdHashMap<K, V>;
20+
21+
/// Type alias for HashSet that uses gxhash when available, std otherwise
22+
#[cfg(feature = "gxhash")]
23+
pub type HashSet<T> = GxHashSet<T>;
24+
25+
/// Type alias for HashSet that uses gxhash when available, std otherwise
26+
#[cfg(not(feature = "gxhash"))]
27+
pub type HashSet<T> = StdHashSet<T>;
28+
29+
/// Extension trait for creating HashMap instances
30+
#[cfg(not(feature = "gxhash"))]
31+
pub trait HashMapExt {
32+
/// Creates a new HashMap with default capacity
33+
fn new() -> Self;
34+
35+
/// Creates a new HashMap with specified capacity
36+
fn with_capacity(capacity: usize) -> Self;
37+
}
38+
39+
#[cfg(not(feature = "gxhash"))]
40+
impl<K, V> HashMapExt for StdHashMap<K, V> {
41+
fn new() -> Self {
42+
StdHashMap::new()
43+
}
44+
45+
fn with_capacity(capacity: usize) -> Self {
46+
StdHashMap::with_capacity(capacity)
47+
}
48+
}
49+
50+
/// Extension trait for creating HashSet instances
51+
#[cfg(not(feature = "gxhash"))]
52+
pub trait HashSetExt {
53+
/// Creates a new HashSet with default capacity
54+
fn new() -> Self;
55+
56+
/// Creates a new HashSet with specified capacity
57+
fn with_capacity(capacity: usize) -> Self;
58+
}
59+
60+
#[cfg(not(feature = "gxhash"))]
61+
impl<T> HashSetExt for StdHashSet<T> {
62+
fn new() -> Self {
63+
StdHashSet::new()
64+
}
65+
66+
fn with_capacity(capacity: usize) -> Self {
67+
StdHashSet::with_capacity(capacity)
68+
}
69+
}
70+
71+
/// Hasher type that uses GxBuildHasher when available, std otherwise
72+
#[cfg(not(feature = "gxhash"))]
73+
pub type GxBuildHasher = std::hash::RandomState;

src/file_tracking.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ use std::sync::Arc;
148148
use parking_lot::Mutex;
149149
use std::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
150150
use std::time::Instant;
151-
use gxhash::{HashMap, HashSet, HashSetExt};
151+
use crate::collections::{HashMap, HashSet, HashSetExt};
152152
use tracing::{debug, trace, warn};
153153

154154
/// File tracker for detecting changes in a directory

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ pub mod types;
202202
pub mod verification;
203203

204204
// Internal modules (not part of public API)
205+
mod collections;
205206
mod file_tracking;
206207
mod merkle;
207208
pub mod storage;

src/merkle.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ use crate::error::{Result, TitorError};
122122
use crate::types::FileEntry;
123123
use sha2::{Digest, Sha256};
124124
use std::path::PathBuf;
125-
use gxhash::{HashMap, HashMapExt};
125+
use crate::collections::{HashMap, HashMapExt};
126126
use tracing::trace;
127127

128128
/// A node in the Merkle tree structure

src/storage.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ use crate::types::{FileManifest, StorageMetadata, StorageObject, TitorConfig};
110110
use chrono::Utc;
111111
use dashmap::DashMap;
112112
use parking_lot::{Mutex, RwLock};
113-
use gxhash::GxBuildHasher;
113+
use crate::collections::GxBuildHasher;
114114
use sha2::{Digest, Sha256};
115115
use std::fs;
116116

src/timeline.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
use crate::checkpoint::Checkpoint;
4848
use crate::error::{Result, TitorError};
4949
use serde::{Deserialize, Serialize};
50-
use gxhash::{HashMap, HashMapExt, HashSet, HashSetExt};
50+
use crate::collections::{HashMap, HashMapExt, HashSet, HashSetExt};
5151
use std::collections::VecDeque;
5252
use tracing::{debug, trace};
5353

src/types.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
use chrono::{DateTime, Utc};
3030
use serde::{Deserialize, Serialize};
3131
use std::path::PathBuf;
32-
use gxhash::HashMap;
32+
use crate::collections::HashMap;
3333
use std::sync::Arc;
3434

3535
/// Represents a file entry in a checkpoint manifest

src/verification.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ use crate::types::FileEntry;
6565
use crate::utils;
6666

6767
use serde::{Deserialize, Serialize};
68-
use gxhash::{HashMap, HashMapExt};
68+
use crate::collections::{HashMap, HashMapExt};
6969
use std::collections::HashSet;
7070
use std::time::Instant;
7171
use tracing::{debug, error, info, warn};

0 commit comments

Comments
 (0)