multi-base 1.0.2

multibase in rust
Documentation
# Concurrency Analysis

## Summary

The multibase crate is fully thread-safe. All public types implement `Send` and `Sync`, and the library can be safely used in concurrent applications without synchronization primitives.

## Thread Safety Guarantees

### All Public Types are Send + Sync

All public types in the multibase crate implement both `Send` and `Sync`:

- `Base` - Send + Sync
-`Error` - Send + Sync
-`EncodedString` - Send + Sync
-`Result<T, Error>` - Send + Sync (when T is Send + Sync)

This is verified by compile-time assertions in `tests/thread_safety.rs`.

### No Interior Mutability

The codebase contains **no interior mutability patterns**:

- ❌ No `RefCell<T>`
- ❌ No `Cell<T>`
- ❌ No `Mutex<T>` or `RwLock<T>`
- ❌ No `UnsafeCell<T>`
- ❌ No global mutable state
- ❌ No thread-local storage

All types use standard Rust ownership and borrowing with immutable or uniquely-owned data.

## Type-by-Type Analysis

### Base Enum

```rust
#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
pub enum Base {
    Identity,
    Base2,
    Base8,
    // ... other variants
}
```

**Thread Safety**: ✅ Send + Sync

**Rationale**:
- Simple enum with no data fields
- Implements `Copy`, which requires all contents to be `Copy`
- No interior mutability
- All operations are read-only (e.g., `code()`, `encode()`, `decode()`)

**Concurrent Usage**: Can be freely shared between threads or sent to other threads.

### Error Type

```rust
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum Error {
    UnknownBase { code: char },
    InvalidBaseString,
    BaseXDecode,
    Base256EmojiDecode,
    DataEncodingDecode { message: String },
    EmptyInput,
}
```

**Thread Safety**: ✅ Send + Sync

**Rationale**:
- Uses `thiserror` which generates appropriate Send + Sync implementations
- All variants contain only Send + Sync types:
  - `char` is Copy (and thus Send + Sync)
  - `String` is Send + Sync
- No interior mutability
- Immutable after creation

**Concurrent Usage**: Error values can be sent between threads and shared via `Arc<Error>`.

### EncodedString Type

```rust
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct EncodedString {
    base: Base,
    inner: String,
}
```

**Thread Safety**: ✅ Send + Sync

**Rationale**:
- Contains only Send + Sync types:
  - `Base` is Copy (and thus Send + Sync)
  - `String` is Send + Sync
- No interior mutability
- All operations are either read-only or consume self

**Concurrent Usage**: Can be sent between threads or shared via `Arc<EncodedString>`.

## Concurrent Operations

### Safe Concurrent Patterns

All of these patterns are safe and tested:

#### 1. Parallel Encoding

```rust
use std::thread;

let data = vec![0xAB; 1000];
let handles: Vec<_> = (0..10)
    .map(|_| {
        let d = data.clone();
        thread::spawn(move || {
            multibase::encode(Base::Base64, &d)
        })
    })
    .collect();

for handle in handles {
    let encoded = handle.join().unwrap();
    // All threads produce identical results
}
```

#### 2. Parallel Decoding

```rust
use std::sync::Arc;
use std::thread;

let encoded = Arc::new("zCn8eVZg".to_string());
let handles: Vec<_> = (0..10)
    .map(|_| {
        let e = Arc::clone(&encoded);
        thread::spawn(move || {
            multibase::decode(&*e, true)
        })
    })
    .collect();

for handle in handles {
    let (base, decoded) = handle.join().unwrap().unwrap();
    // All threads produce identical results
}
```

#### 3. Thread-Local Buffer Reuse

```rust
use std::thread;

let handles: Vec<_> = (0..10)
    .map(|_| {
        thread::spawn(move || {
            // Each thread has its own buffer
            let mut encode_buffer = String::new();
            let mut decode_buffer = Vec::new();

            for _ in 0..100 {
                multibase::encode_into(Base::Base64, b"data", &mut encode_buffer);
                multibase::decode_into(&encode_buffer, true, &mut decode_buffer).unwrap();
            }
        })
    })
    .collect();

for handle in handles {
    handle.join().unwrap();
}
```

#### 4. Sharing Validated Strings

```rust
use std::sync::Arc;
use std::thread;

let encoded = Arc::new(EncodedString::new("md29ybGQ").unwrap());

let handles: Vec<_> = (0..10)
    .map(|_| {
        let e = Arc::clone(&encoded);
        thread::spawn(move || {
            e.decode().unwrap()
        })
    })
    .collect();

for handle in handles {
    handle.join().unwrap();
}
```

### Unsafe Concurrent Patterns

These patterns are **NOT recommended** but are safe:

#### Shared Mutable State (Requires External Synchronization)

```rust
use std::sync::Mutex;
use std::thread;

// This works but is unnecessary - use thread-local buffers instead
let shared_buffer = Mutex::new(String::new());

let handles: Vec<_> = (0..10)
    .map(|_| {
        thread::spawn(move || {
            let mut buf = shared_buffer.lock().unwrap();
            multibase::encode_into(Base::Base64, b"data", &mut buf);
        })
    })
    .collect();
```

**Note**: The library itself doesn't require locks. This pattern is safe but introduces unnecessary contention. Use thread-local buffers instead.

## Performance Considerations

### Scalability

The library scales linearly with the number of threads:

- No shared mutable state means no lock contention
- No global caches or pools that could become bottlenecks
- Each operation is independent and can run in parallel

### Benchmarking Results

From stress testing (`tests/thread_safety.rs`):

- 20 threads × 100 operations each = 2000 total operations
- All operations complete successfully with correct results
- No data races detected
- No deadlocks or livelocks

## Data Race Freedom

### Verification Methods

1. **Compile-Time Verification**: Rust's type system ensures Send/Sync correctness
2. **Runtime Testing**: 20 thread safety tests
3. **Stress Testing**: High-concurrency scenarios with atomic counters
4. **Property Testing**: Concurrent property tests verify invariants hold under parallelism

### Test Coverage

The test suite includes:

- ✅ Compile-time Send/Sync assertions for all public types
- ✅ Cross-thread send tests (moving values between threads)
- ✅ Cross-thread sync tests (sharing via Arc)
- ✅ Concurrent encoding correctness tests
- ✅ Concurrent decoding correctness tests
- ✅ Concurrent buffer reuse tests
- ✅ Multi-base concurrent operations
- ✅ Stress test with 2000 concurrent operations
- ✅ No data race verification with read-only concurrent access

All 20 thread safety tests pass consistently.

## Memory Ordering

### Atomics

The codebase does **not use** atomic operations because it has no shared mutable state.

### No Hidden Synchronization

The library performs no hidden synchronization:

- No global state requiring locks
- No lazy initialization with `Once` or `OnceLock`
- No caching that would require synchronization
- All operations are pure functions or consume owned data

## Thread Safety Best Practices

### For Library Users

1. **Use thread-local buffers** when calling `encode_into` or `decode_into` in loops
2. **Share read-only data** via `Arc` when appropriate
3. **Clone when needed** - Base is Copy, Error and EncodedString implement Clone
4. **No synchronization needed** - the library handles everything safely

### For Library Maintainers

If adding new types or features:

1. ✅ Ensure new types are Send + Sync (or document why not)
2. ✅ Add compile-time assertions for new public types
3. ✅ Add thread safety tests for new functionality
4. ✅ Avoid interior mutability unless absolutely necessary
5. ✅ Document any thread safety implications

## Guarantees and Limitations

### What We Guarantee

- ✅ All public types are Send + Sync
- ✅ No data races possible
- ✅ No deadlocks or livelocks
- ✅ Concurrent operations produce correct results
- ✅ Thread-safe without external synchronization

### What We Don't Guarantee

- ❌ Operation ordering between threads (no happens-before relationships)
- ❌ Fairness (threads may complete in any order)
- ❌ Performance characteristics under contention (use thread-local buffers)

These limitations are standard for thread-safe libraries and do not affect correctness.

## Testing

### Running Thread Safety Tests

```bash
# Run all thread safety tests
cargo test --test thread_safety

# Run with thread sanitizer (requires nightly Rust)
RUSTFLAGS="-Z sanitizer=thread" cargo +nightly test --test thread_safety --target x86_64-unknown-linux-gnu
```

### Test Statistics

- **20 thread safety tests** in `tests/thread_safety.rs`
- **5 compile-time Send/Sync assertions**
- **15 runtime concurrency tests**
- **2000 concurrent operations** in stress test
- **100% pass rate**

## References

- [Rust Nomicon - Send and Sync]https://doc.rust-lang.org/nomicon/send-and-sync.html
- [Rust Book - Fearless Concurrency]https://doc.rust-lang.org/book/ch16-00-concurrency.html
- [Thread Safety in Rust]https://doc.rust-lang.org/std/marker/trait.Send.html

## Conclusion

The multibase crate is fully thread-safe and can be confidently used in concurrent applications. All public types implement Send and Sync, there is no interior mutability, and the test suite verifies correct concurrent behavior.