Skip to main content

cjc_runtime/
lib.rs

1//! CJC Runtime System
2//!
3//! This crate provides the core runtime infrastructure for the CJC deterministic
4//! numerical programming language. It is the largest crate in the workspace and
5//! underpins both the AST tree-walk interpreter (`cjc-eval`) and the MIR register
6//! machine executor (`cjc-mir-exec`).
7//!
8//! # Core Abstractions
9//!
10//! - [`Buffer<T>`] -- Deterministic memory allocation with COW (copy-on-write)
11//!   semantics. Cloning is O(1); mutation triggers a deep copy only when shared.
12//! - [`Tensor`] -- N-dimensional tensor backed by `Buffer<f64>`. Supports
13//!   element-wise arithmetic (SIMD-accelerated), matrix multiplication (tiled +
14//!   parallel), and numerically-stable reductions via [`BinnedAccumulatorF64`].
15//! - [`Value`] -- The universal tagged-union value type that flows through both
16//!   interpreters. Covers scalars, strings, tensors, closures, structs, enums,
17//!   and opaque type-erased objects (AD graphs, tidy views, quantum states).
18//! - [`RuntimeError`] -- Error type for all fallible runtime operations.
19//!
20//! # Determinism Guarantees
21//!
22//! - All floating-point reductions use Kahan or [`BinnedAccumulatorF64`] summation.
23//! - Ordered containers only ([`BTreeMap`]/[`BTreeSet`]) -- no `HashMap`/`HashSet`.
24//! - [`DetMap`] provides a deterministic hash map with [`murmurhash3`] hashing.
25//! - SIMD kernels avoid hardware FMA for bit-identical cross-platform results.
26//! - RNG is SplitMix64 with explicit seed threading (`cjc-repro`).
27//!
28//! # Memory Model
29//!
30//! - **NoGC tier:** [`Buffer<T>`], [`Tensor`], [`AlignedByteSlice`] -- zero GC
31//!   overhead, COW semantics.
32//! - **GC tier:** [`GcHeap`] / [`GcRef`] -- RC-backed object slab for class
33//!   instances.
34//! - **Arena tier:** [`FrameArena`] / [`ArenaStore`] -- bump allocation per
35//!   function frame for non-escaping temporaries.
36//!
37//! # Module Organization
38//!
39//! | Layer | Modules |
40//! |-------|---------|
41//! | Core types | [`value`], [`error`], [`buffer`], [`tensor`], [`tensor_dtype`] |
42//! | Builtins | [`builtins`] -- shared stateless dispatch for both executors |
43//! | Accumulation | [`accumulator`], [`dispatch`] |
44//! | Linear algebra | [`linalg`], [`sparse`], [`sparse_solvers`], [`sparse_eigen`] |
45//! | Statistics | [`stats`], [`distributions`], [`hypothesis`] |
46//! | Data | [`json`], [`datetime`], [`window`], [`timeseries`] |
47//! | ML / NN | [`ml`], [`fft`], [`clustering`], [`optimize`], [`interpolate`] |
48//! | Memory | [`gc`], [`object_slab`], [`frame_arena`], [`binned_alloc`], [`aligned_pool`] |
49//! | SIMD / Perf | [`tensor_simd`], [`tensor_tiled`], [`tensor_pool`] |
50//!
51//! [`BinnedAccumulatorF64`]: accumulator::BinnedAccumulatorF64
52//! [`BTreeMap`]: std::collections::BTreeMap
53//! [`BTreeSet`]: std::collections::BTreeSet
54
55// --- Core standalone modules ---
56
57/// BinnedAccumulator for order-invariant deterministic floating-point summation.
58pub mod accumulator;
59/// Complex number arithmetic with deterministic fixed-sequence operations.
60pub mod complex;
61/// Hybrid summation strategy dispatch (Kahan vs Binned) based on execution context.
62pub mod dispatch;
63/// IEEE 754 half-precision (f16) floating-point type.
64pub mod f16;
65/// Quantized tensor storage (4-bit, 8-bit) for memory-efficient inference.
66pub mod quantized;
67
68// --- Shared builtin dispatch (used by both cjc-eval and cjc-mir-exec) ---
69
70/// Stateless builtin function dispatch shared by both interpreters.
71///
72/// Every builtin registered here is callable from CJC source code. Functions
73/// that require interpreter state (print, GC, clock, RNG) stay in the
74/// individual executors.
75pub mod builtins;
76
77// --- Core data structures ---
78
79/// COW (copy-on-write) buffer -- the memory primitive under [`Tensor`].
80pub mod buffer;
81/// N-dimensional tensor with element-wise, reduction, linalg, and NN operations.
82pub mod tensor;
83/// Deterministic binary serialization for tensors and tensor lists.
84pub mod tensor_snap;
85/// Pre-allocated KV-cache scratchpad for zero-allocation transformer inference.
86pub mod scratchpad;
87/// 16-byte-aligned memory pool for SIMD-friendly byte buffers.
88pub mod aligned_pool;
89/// Internal bridge to compiled SIMD/tiled kernel functions.
90mod kernel_bridge;
91pub use kernel_bridge::kernel;
92/// Block-paged KV-cache (vLLM-style) for efficient autoregressive decoding.
93pub mod paged_kv;
94/// Size-class binned allocator for deterministic memory management.
95pub mod binned_alloc;
96/// Bump-arena per function frame for non-escaping temporaries.
97pub mod frame_arena;
98/// RC-backed object slab for class instances (replaces mark-sweep GC).
99pub mod object_slab;
100/// GC heap abstraction wrapping the RC-backed object slab.
101pub mod gc;
102/// Sparse matrix types: CSR and COO representations.
103pub mod sparse;
104/// Direct sparse solvers (LU factorization, triangular solve).
105pub mod sparse_solvers;
106/// L2-cache-friendly tiled matrix multiplication engine.
107pub mod tensor_tiled;
108/// AVX2 SIMD kernels for element-wise and unary tensor operations.
109pub mod tensor_simd;
110/// Tensor memory pool for reducing allocation pressure in hot loops.
111pub mod tensor_pool;
112/// Deterministic hash map using MurmurHash3 -- iteration order is fixed.
113pub mod det_map;
114/// Dense linear algebra: determinant, solve, eigenvalues, SVD, QR, LU.
115pub mod linalg;
116/// The universal [`Value`] tagged union and supporting types ([`Bf16`], [`FnValue`]).
117pub mod value;
118/// [`RuntimeError`] enum for all fallible runtime operations.
119pub mod error;
120/// Library registry for module-system symbol lookup.
121pub mod lib_registry;
122/// JSON parse/stringify builtins for CJC values.
123pub mod json;
124/// Pure-arithmetic datetime manipulation (epoch-based, no system clock).
125pub mod datetime;
126/// Rolling window aggregations (sum, mean, min, max).
127pub mod window;
128/// Descriptive and inferential statistics functions.
129pub mod stats;
130/// Probability distribution functions (CDF, PDF, PPF) for Normal, t, chi2, F.
131pub mod distributions;
132/// Hypothesis testing: t-test, chi-squared test, paired t-test.
133pub mod hypothesis;
134/// Machine learning loss functions and optimizer state types.
135pub mod ml;
136/// Fast Fourier Transform (radix-2 Cooley-Tukey).
137pub mod fft;
138/// Time-series stationarity tests (ADF).
139pub mod stationarity;
140/// ODE solver primitives (Euler, RK4 step functions).
141pub mod ode;
142/// Sparse eigenvalue solvers (Lanczos, Arnoldi).
143pub mod sparse_eigen;
144/// Interpolation primitives (linear, cubic spline).
145pub mod interpolate;
146/// Numerical optimization (gradient descent, L-BFGS, Nelder-Mead).
147pub mod optimize;
148/// Clustering algorithms (k-means, DBSCAN).
149pub mod clustering;
150/// Typed tensor storage: [`DType`] enum and byte-first [`TypedStorage`].
151pub mod tensor_dtype;
152/// Time-series analysis utilities (autocorrelation, differencing).
153pub mod timeseries;
154/// Numerical integration (trapezoidal, Simpson's rule).
155pub mod integrate;
156/// Numerical differentiation (finite differences).
157pub mod differentiate;
158/// Deterministic profile counters (Tier 2 of Chess RL v2.3). Write-only
159/// timing sink that does not perturb program state, RNG, or weight hashes.
160pub mod profile;
161/// Runtime Policy Layer — deterministic thermally-bounded execution policy
162/// (thread caps, thermal profiles, batch sizing, audit depth) plus a
163/// wall-clock-free energy estimate. The "green compute" control surface.
164pub mod runtime_policy;
165/// Phase 2b — typed-ID newtypes for ML metadata. Currently provides
166/// only `ParamIdx`, used by `crate::ml::AdamState` and `SgdState`.
167pub mod idx;
168
169// --- Re-exports for backward compatibility ---
170// All downstream crates that were doing `use cjc_runtime::Tensor` etc. continue to work.
171
172/// Re-export: COW buffer with deterministic copy-on-write semantics.
173pub use buffer::Buffer;
174/// Re-export: N-dimensional tensor -- the primary numerical type.
175pub use tensor::Tensor;
176/// Re-export: Pre-allocated KV-cache scratchpad.
177pub use scratchpad::Scratchpad;
178/// Re-export: 16-byte-aligned memory pool and byte slice.
179pub use aligned_pool::{AlignedPool, AlignedByteSlice};
180/// Re-export: Block-paged KV-cache types.
181pub use paged_kv::{KvBlock, PagedKvCache};
182/// Re-export: GC heap and reference types.
183pub use gc::{GcRef, GcHeap};
184/// Re-export: Size-class binned allocator.
185pub use binned_alloc::BinnedAllocator;
186/// Re-export: Bump-arena and arena store types.
187pub use frame_arena::{FrameArena, ArenaStore};
188/// Re-export: Object slab and slab reference types.
189pub use object_slab::{ObjectSlab, SlabRef};
190/// Re-export: Sparse matrix types (CSR and COO).
191pub use sparse::{SparseCsr, SparseCoo};
192/// Re-export: Tiled matrix multiplication engine.
193pub use tensor_tiled::TiledMatmul;
194/// Re-export: Deterministic map, MurmurHash3, and value hashing utilities.
195pub use det_map::{DetMap, murmurhash3, murmurhash3_finalize, value_hash, values_equal_static};
196/// Re-export: Universal value type and supporting types.
197pub use value::{Value, Bf16, FnValue};
198/// Re-export: Runtime error type.
199pub use error::RuntimeError;
200/// Re-export: Typed tensor storage types.
201pub use tensor_dtype::{DType, TypedStorage};
202
203// ---------------------------------------------------------------------------
204// Tests — remain here so they can use `super::*` to access all re-exports.
205// ---------------------------------------------------------------------------
206
207#[cfg(test)]
208mod tests {
209    use super::*;
210    use std::rc::Rc;
211    use cjc_repro::Rng;
212
213    // -- Buffer tests -------------------------------------------------------
214
215    #[test]
216    fn test_buffer_alloc_get_set() {
217        let mut buf = Buffer::alloc(5, 0.0f64);
218        assert_eq!(buf.len(), 5);
219        assert_eq!(buf.get(0), Some(0.0));
220        assert_eq!(buf.get(4), Some(0.0));
221        assert_eq!(buf.get(5), None);
222
223        buf.set(2, 42.0).unwrap();
224        assert_eq!(buf.get(2), Some(42.0));
225
226        assert!(buf.set(10, 1.0).is_err());
227    }
228
229    #[test]
230    fn test_buffer_from_vec() {
231        let buf = Buffer::from_vec(vec![1, 2, 3, 4, 5]);
232        assert_eq!(buf.len(), 5);
233        assert_eq!(buf.get(0), Some(1));
234        assert_eq!(buf.get(4), Some(5));
235        assert_eq!(buf.as_slice(), vec![1, 2, 3, 4, 5]);
236    }
237
238    #[test]
239    fn test_buffer_cow_behavior() {
240        let buf_a = Buffer::from_vec(vec![10, 20, 30]);
241        let mut buf_b = buf_a.clone();
242
243        assert_eq!(buf_a.refcount(), 2);
244        assert_eq!(buf_b.refcount(), 2);
245
246        buf_b.set(0, 99).unwrap();
247
248        assert_eq!(buf_a.refcount(), 1);
249        assert_eq!(buf_b.refcount(), 1);
250        assert_eq!(buf_a.get(0), Some(10));
251        assert_eq!(buf_b.get(0), Some(99));
252    }
253
254    #[test]
255    fn test_buffer_clone_buffer_forces_deep_copy() {
256        let buf_a = Buffer::from_vec(vec![1, 2, 3]);
257        let buf_b = buf_a.clone_buffer();
258
259        assert_eq!(buf_a.refcount(), 1);
260        assert_eq!(buf_b.refcount(), 1);
261        assert_eq!(buf_a.as_slice(), buf_b.as_slice());
262    }
263
264    // -- Tensor tests -------------------------------------------------------
265
266    #[test]
267    fn test_tensor_creation_and_indexing() {
268        let t = Tensor::zeros(&[2, 3]);
269        assert_eq!(t.shape(), &[2, 3]);
270        assert_eq!(t.ndim(), 2);
271        assert_eq!(t.len(), 6);
272        assert_eq!(t.get(&[0, 0]).unwrap(), 0.0);
273        assert_eq!(t.get(&[1, 2]).unwrap(), 0.0);
274
275        assert!(t.get(&[2, 0]).is_err());
276        assert!(t.get(&[0]).is_err());
277    }
278
279    #[test]
280    fn test_tensor_from_vec_and_set() {
281        let mut t = Tensor::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], &[2, 3]).unwrap();
282        assert_eq!(t.get(&[0, 0]).unwrap(), 1.0);
283        assert_eq!(t.get(&[0, 2]).unwrap(), 3.0);
284        assert_eq!(t.get(&[1, 0]).unwrap(), 4.0);
285        assert_eq!(t.get(&[1, 2]).unwrap(), 6.0);
286
287        t.set(&[1, 1], 99.0).unwrap();
288        assert_eq!(t.get(&[1, 1]).unwrap(), 99.0);
289    }
290
291    #[test]
292    fn test_tensor_elementwise_ops() {
293        let a = Tensor::from_vec(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]).unwrap();
294        let b = Tensor::from_vec(vec![5.0, 6.0, 7.0, 8.0], &[2, 2]).unwrap();
295
296        let sum = a.add(&b).unwrap();
297        assert_eq!(sum.to_vec(), vec![6.0, 8.0, 10.0, 12.0]);
298
299        let diff = a.sub(&b).unwrap();
300        assert_eq!(diff.to_vec(), vec![-4.0, -4.0, -4.0, -4.0]);
301
302        let prod = a.mul_elem(&b).unwrap();
303        assert_eq!(prod.to_vec(), vec![5.0, 12.0, 21.0, 32.0]);
304
305        let quot = b.div_elem(&a).unwrap();
306        assert_eq!(quot.to_vec(), vec![5.0, 3.0, 7.0 / 3.0, 2.0]);
307    }
308
309    #[test]
310    fn test_tensor_matmul_correctness() {
311        let a = Tensor::from_vec(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]).unwrap();
312        let b = Tensor::from_vec(vec![5.0, 6.0, 7.0, 8.0], &[2, 2]).unwrap();
313
314        let c = a.matmul(&b).unwrap();
315        assert_eq!(c.shape(), &[2, 2]);
316        assert_eq!(c.get(&[0, 0]).unwrap(), 19.0);
317        assert_eq!(c.get(&[0, 1]).unwrap(), 22.0);
318        assert_eq!(c.get(&[1, 0]).unwrap(), 43.0);
319        assert_eq!(c.get(&[1, 1]).unwrap(), 50.0);
320    }
321
322    #[test]
323    fn test_tensor_matmul_nonsquare() {
324        let a = Tensor::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], &[2, 3]).unwrap();
325        let b = Tensor::from_vec(vec![7.0, 8.0, 9.0, 10.0, 11.0, 12.0], &[3, 2]).unwrap();
326
327        let c = a.matmul(&b).unwrap();
328        assert_eq!(c.shape(), &[2, 2]);
329        assert_eq!(c.get(&[0, 0]).unwrap(), 58.0);
330        assert_eq!(c.get(&[0, 1]).unwrap(), 64.0);
331        assert_eq!(c.get(&[1, 0]).unwrap(), 139.0);
332        assert_eq!(c.get(&[1, 1]).unwrap(), 154.0);
333    }
334
335    #[test]
336    fn test_tensor_reshape_shares_buffer() {
337        let t = Tensor::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], &[2, 3]).unwrap();
338        let r = t.reshape(&[3, 2]).unwrap();
339
340        assert_eq!(r.shape(), &[3, 2]);
341        assert_eq!(r.get(&[0, 0]).unwrap(), 1.0);
342        assert_eq!(r.get(&[2, 1]).unwrap(), 6.0);
343
344        assert_eq!(t.buffer.refcount(), 2);
345
346        assert!(t.reshape(&[4, 2]).is_err());
347    }
348
349    #[test]
350    fn test_tensor_sum_and_mean() {
351        let t = Tensor::from_vec(vec![1.0, 2.0, 3.0, 4.0], &[4]).unwrap();
352        assert!((t.sum() - 10.0).abs() < 1e-12);
353        assert!((t.mean() - 2.5).abs() < 1e-12);
354    }
355
356    // -- GC tests -----------------------------------------------------------
357
358    #[test]
359    fn test_gc_alloc_and_read() {
360        let mut heap = GcHeap::new(100);
361        let r1 = heap.alloc(42i64);
362        let r2 = heap.alloc("hello".to_string());
363
364        assert_eq!(heap.live_count(), 2);
365        assert_eq!(*heap.get::<i64>(r1).unwrap(), 42);
366        assert_eq!(heap.get::<String>(r2).unwrap().as_str(), "hello");
367
368        assert!(heap.get::<f64>(r1).is_none());
369    }
370
371    #[test]
372    fn test_gc_collect_is_noop_rc_backed() {
373        // In the RC-backed ObjectSlab, collect() is a no-op.
374        // All objects survive regardless of roots provided.
375        let mut heap = GcHeap::new(100);
376        let r1 = heap.alloc(1i64);
377        let r2 = heap.alloc(2i64);
378        let r3 = heap.alloc(3i64);
379
380        assert_eq!(heap.live_count(), 3);
381
382        // collect with partial roots — all objects survive (RC, not GC)
383        heap.collect(&[r1, r2]);
384
385        assert_eq!(heap.live_count(), 3, "RC keeps all objects alive");
386        assert_eq!(*heap.get::<i64>(r1).unwrap(), 1);
387        assert_eq!(*heap.get::<i64>(r2).unwrap(), 2);
388        assert_eq!(*heap.get::<i64>(r3).unwrap(), 3);
389    }
390
391    #[test]
392    fn test_gc_explicit_free_and_slot_reuse() {
393        // Slot reuse now requires explicit free() — no automatic GC collection.
394        let mut heap = GcHeap::new(100);
395        let r1 = heap.alloc(1i64);
396        let r2 = heap.alloc(2i64);
397        let r3 = heap.alloc(3i64);
398
399        // Explicitly free all three slots
400        heap.free(r1);
401        heap.free(r2);
402        heap.free(r3);
403        assert_eq!(heap.live_count(), 0);
404        assert_eq!(heap.free_list().len(), 3);
405
406        // New alloc reuses freed slot (LIFO)
407        let r4 = heap.alloc(99i64);
408        assert!(r4.index < 3, "should reuse a freed slot");
409        assert_eq!(*heap.get::<i64>(r4).unwrap(), 99);
410    }
411
412    // -- Stable summation test ----------------------------------------------
413
414    #[test]
415    fn test_stable_summation_via_tensor() {
416        let n = 100_000;
417        let data: Vec<f64> = (0..n).map(|_| 0.00001).collect();
418        let t = Tensor::from_vec(data, &[n]).unwrap();
419        let result = t.sum();
420        let expected = 0.00001 * n as f64;
421        assert!(
422            (result - expected).abs() < 1e-10,
423            "Kahan sum drift: expected {expected}, got {result}"
424        );
425    }
426
427    // -- Tensor randn determinism test --------------------------------------
428
429    #[test]
430    fn test_tensor_randn_deterministic() {
431        let mut rng1 = Rng::seeded(42);
432        let mut rng2 = Rng::seeded(42);
433
434        let t1 = Tensor::randn(&[3, 4], &mut rng1);
435        let t2 = Tensor::randn(&[3, 4], &mut rng2);
436
437        assert_eq!(t1.to_vec(), t2.to_vec());
438    }
439
440    // -- Value display test -------------------------------------------------
441
442    #[test]
443    fn test_value_display() {
444        assert_eq!(format!("{}", Value::Int(42)), "42");
445        assert_eq!(format!("{}", Value::Bool(true)), "true");
446        assert_eq!(format!("{}", Value::Void), "void");
447        assert_eq!(format!("{}", Value::String(Rc::new("hi".into()))), "hi");
448    }
449
450    #[test]
451    fn test_cow_string_clone_shares() {
452        let s = Value::String(Rc::new("hello".into()));
453        let s2 = s.clone();
454        if let (Value::String(a), Value::String(b)) = (&s, &s2) {
455            assert!(Rc::ptr_eq(a, b));
456        } else {
457            panic!("expected String values");
458        }
459    }
460
461    #[test]
462    fn test_cow_string_display() {
463        let s = Value::String(Rc::new("world".into()));
464        assert_eq!(format!("{}", s), "world");
465    }
466
467    // -- ByteSlice / StrView / U8 tests ------------------------------------
468
469    #[test]
470    fn test_byteslice_value_display_utf8() {
471        let bs = Value::ByteSlice(Rc::new(b"hello".to_vec()));
472        assert_eq!(format!("{}", bs), r#"b"hello""#);
473    }
474
475    #[test]
476    fn test_byteslice_value_display_hex() {
477        let bs = Value::ByteSlice(Rc::new(vec![0xff, 0x00, 0x41]));
478        assert_eq!(format!("{}", bs), r#"b"\xff\x00A""#);
479    }
480
481    #[test]
482    fn test_strview_value_display() {
483        let sv = Value::StrView(Rc::new(b"world".to_vec()));
484        assert_eq!(format!("{}", sv), "world");
485    }
486
487    #[test]
488    fn test_u8_value_display() {
489        assert_eq!(format!("{}", Value::U8(65)), "65");
490    }
491
492    #[test]
493    fn test_byteslice_hash_deterministic() {
494        let a = Value::ByteSlice(Rc::new(b"hello".to_vec()));
495        let b = Value::ByteSlice(Rc::new(b"hello".to_vec()));
496        assert_eq!(value_hash(&a), value_hash(&b));
497    }
498
499    #[test]
500    fn test_byteslice_hash_different_content() {
501        let a = Value::ByteSlice(Rc::new(b"hello".to_vec()));
502        let b = Value::ByteSlice(Rc::new(b"world".to_vec()));
503        assert_ne!(value_hash(&a), value_hash(&b));
504    }
505
506    #[test]
507    fn test_byteslice_equality() {
508        let a = Value::ByteSlice(Rc::new(b"abc".to_vec()));
509        let b = Value::ByteSlice(Rc::new(b"abc".to_vec()));
510        let c = Value::ByteSlice(Rc::new(b"def".to_vec()));
511        assert!(values_equal_static(&a, &b));
512        assert!(!values_equal_static(&a, &c));
513    }
514
515    #[test]
516    fn test_strview_equality() {
517        let a = Value::StrView(Rc::new(b"test".to_vec()));
518        let b = Value::StrView(Rc::new(b"test".to_vec()));
519        assert!(values_equal_static(&a, &b));
520    }
521
522    #[test]
523    fn test_u8_hash_and_equality() {
524        let a = Value::U8(42);
525        let b = Value::U8(42);
526        let c = Value::U8(99);
527        assert_eq!(value_hash(&a), value_hash(&b));
528        assert_ne!(value_hash(&a), value_hash(&c));
529        assert!(values_equal_static(&a, &b));
530        assert!(!values_equal_static(&a, &c));
531    }
532
533    #[test]
534    fn test_byteslice_clone_shares_rc() {
535        let bs = Value::ByteSlice(Rc::new(b"data".to_vec()));
536        let bs2 = bs.clone();
537        if let (Value::ByteSlice(a), Value::ByteSlice(b)) = (&bs, &bs2) {
538            assert!(Rc::ptr_eq(a, b));
539        } else {
540            panic!("expected ByteSlice values");
541        }
542    }
543
544    #[test]
545    fn test_byteslice_in_detmap() {
546        let mut map = DetMap::new();
547        let key = Value::ByteSlice(Rc::new(b"token".to_vec()));
548        map.insert(key.clone(), Value::Int(1));
549
550        let lookup = Value::ByteSlice(Rc::new(b"token".to_vec()));
551        assert!(map.contains_key(&lookup));
552        match map.get(&lookup) {
553            Some(Value::Int(1)) => {},
554            _ => panic!("expected Int(1)"),
555        }
556    }
557
558    #[test]
559    fn test_murmurhash3_byteslice_stability() {
560        let h1 = murmurhash3(b"hello");
561        let h2 = murmurhash3(b"hello");
562        assert_eq!(h1, h2);
563
564        let h3 = murmurhash3(b"");
565        let h4 = murmurhash3(b"");
566        assert_eq!(h3, h4);
567
568        assert_ne!(murmurhash3(b"hello"), murmurhash3(b"world"));
569    }
570}