# Library API Reference
Complete API reference for using base-d as a Rust library.
## Installation
Add to your `Cargo.toml`:
```toml
[dependencies]
base-d = "0.1"
```
## Core Types
### `Dictionary`
Represents an encoding dictionary with associated encoding mode.
```rust
use base_d::{Dictionary, EncodingMode};
// Create from character vector
let chars: Vec<char> = "0123456789ABCDEF".chars().collect();
let dictionary = Dictionary::new(chars)?;
// Create with specific mode
let dictionary = Dictionary::new_with_mode(
chars,
EncodingMode::Chunked,
Some('=') // padding character
)?;
// Create byte-range dictionary
let dictionary = Dictionary::new_with_mode_and_range(
Vec::new(),
EncodingMode::ByteRange,
None,
Some(127991) // start codepoint
)?;
```
**Methods:**
- `base(&self) -> usize` - Get dictionary size
- `mode(&self) -> &EncodingMode` - Get encoding mode
- `encode_digit(&self, digit: usize) -> Option<char>` - Encode single digit
- `decode_char(&self, c: char) -> Option<usize>` - Decode single character
### `EncodingMode`
Encoding algorithm to use.
```rust
pub enum EncodingMode {
BaseConversion, // Mathematical (any dictionary size)
Chunked, // RFC 4648 (power-of-2 sizes)
ByteRange, // Direct byte-to-char (256 chars)
}
```
### `DictionariesConfig`
Configuration containing multiple dictionary definitions.
```rust
use base_d::DictionariesConfig;
// Load built-in dictionaries
let config = DictionariesConfig::load_default()?;
// Load with user overrides
let config = DictionariesConfig::load_with_overrides()?;
// Load from specific file
let config = DictionariesConfig::load_from_file("config.toml".as_ref())?;
// Get specific dictionary
let base64_config = config.get_dictionary("base64").unwrap();
// Merge configurations
let mut config1 = DictionariesConfig::load_default()?;
let config2 = DictionariesConfig::load_from_file("custom.toml".as_ref())?;
config1.merge(config2);
```
### `DictionaryConfig`
Configuration for a single dictionary.
```rust
pub struct DictionaryConfig {
pub chars: String, // Dictionary characters
pub mode: EncodingMode, // Encoding mode
pub padding: Option<String>, // Padding character
pub start_codepoint: Option<u32>, // For ByteRange mode
}
```
### `DecodeError`
Error type for decoding operations.
```rust
pub enum DecodeError {
InvalidCharacter(char), // Character not in dictionary
EmptyInput, // Empty string provided
InvalidPadding, // Malformed padding
}
```
Implements `std::error::Error` and `Display`.
## Encoding Functions
### `encode`
Encode bytes to string using specified dictionary.
```rust
use base_d::{encode, Dictionary};
let dictionary = /* create dictionary */;
let data = b"Hello, World!";
let encoded: String = encode(data, &dictionary);
```
### `decode`
Decode string to bytes using specified dictionary.
```rust
use base_d::{decode, Dictionary, DecodeError};
let dictionary = /* create dictionary */;
let encoded = "SGVsbG8sIFdvcmxkIQ==";
let decoded: Result<Vec<u8>, DecodeError> = decode(encoded, &dictionary);
```
## Streaming API
### `StreamingEncoder`
Encode data in chunks without loading entire input.
```rust
use base_d::{StreamingEncoder, Dictionary};
use std::fs::File;
let dictionary = /* create dictionary */;
let mut input = File::open("input.bin")?;
let mut output = File::create("output.txt")?;
let mut encoder = StreamingEncoder::new(&dictionary, output);
encoder.encode(&mut input)?;
```
**Methods:**
- `new(dictionary: &Dictionary, writer: W) -> Self` - Create encoder
- `encode<R: Read>(&mut self, reader: &mut R) -> std::io::Result<()>` - Encode stream
### `StreamingDecoder`
Decode data in chunks without loading entire input.
```rust
use base_d::{StreamingDecoder, Dictionary, DecodeError};
use std::fs::File;
let dictionary = /* create dictionary */;
let mut input = File::open("input.txt")?;
let mut output = File::create("output.bin")?;
let mut decoder = StreamingDecoder::new(&dictionary, output);
decoder.decode(&mut input)?;
```
**Methods:**
- `new(dictionary: &Dictionary, writer: W) -> Self` - Create decoder
- `decode<R: Read>(&mut self, reader: &mut R) -> Result<(), DecodeError>` - Decode stream
## Complete Examples
### Example 1: Simple Encoding
```rust
use base_d::{DictionariesConfig, Dictionary, encode, decode};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = DictionariesConfig::load_default()?;
let base64_config = config.get_dictionary("base64").unwrap();
let chars: Vec<char> = base64_config.chars.chars().collect();
let padding = base64_config.padding.as_ref().and_then(|s| s.chars().next());
let dictionary = Dictionary::new_with_mode(
chars,
base64_config.mode.clone(),
padding
)?;
let data = b"Hello, World!";
let encoded = encode(data, &dictionary);
println!("Encoded: {}", encoded);
let decoded = decode(&encoded, &dictionary)?;
assert_eq!(data, &decoded[..]);
Ok(())
}
```
### Example 2: Custom Dictionary
```rust
use base_d::{Dictionary, EncodingMode, encode, decode};
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create custom emoji dictionary
let chars: Vec<char> = "😀😁😂🤣😃😄😅😆".chars().collect();
let dictionary = Dictionary::new_with_mode(
chars,
EncodingMode::BaseConversion,
None
)?;
let data = b"Hi";
let encoded = encode(data, &dictionary);
println!("Encoded: {}", encoded);
let decoded = decode(&encoded, &dictionary)?;
assert_eq!(data, &decoded[..]);
Ok(())
}
```
### Example 3: ByteRange (base100)
```rust
use base_d::{Dictionary, EncodingMode, encode, decode};
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create base100 dictionary (256 emoji)
let dictionary = Dictionary::new_with_mode_and_range(
Vec::new(),
EncodingMode::ByteRange,
None,
Some(127991) // U+1F3F7
)?;
let data = b"Test";
let encoded = encode(data, &dictionary);
println!("Encoded: {}", encoded); // 4 emoji, 1:1 mapping
let decoded = decode(&encoded, &dictionary)?;
assert_eq!(data, &decoded[..]);
Ok(())
}
```
### Example 4: Streaming Large Files
```rust
use base_d::{DictionariesConfig, Dictionary, StreamingEncoder, StreamingDecoder};
use std::fs::File;
fn stream_encode_file(
input_path: &str,
output_path: &str,
dict_name: &str
) -> Result<(), Box<dyn std::error::Error>> {
let config = DictionariesConfig::load_default()?;
let dict_config = config.get_dictionary(dict_name)
.ok_or("Dictionary not found")?;
let dictionary = create_dictionary_from_config(dict_config)?;
let mut input = File::open(input_path)?;
let output = File::create(output_path)?;
let mut encoder = StreamingEncoder::new(&dictionary, output);
encoder.encode(&mut input)?;
Ok(())
}
fn create_dictionary_from_config(
config: &base_d::DictionaryConfig
) -> Result<Dictionary, Box<dyn std::error::Error>> {
use base_d::EncodingMode;
match config.mode {
EncodingMode::ByteRange => {
let start = config.start_codepoint
.ok_or("ByteRange requires start_codepoint")?;
Ok(Dictionary::new_with_mode_and_range(
Vec::new(),
config.mode.clone(),
None,
Some(start)
)?)
}
_ => {
let chars: Vec<char> = config.chars.chars().collect();
let padding = config.padding.as_ref()
.and_then(|s| s.chars().next());
Ok(Dictionary::new_with_mode(
chars,
config.mode.clone(),
padding
)?)
}
}
}
```
### Example 5: Error Handling
```rust
use base_d::{decode, Dictionary, DecodeError};
fn safe_decode(
encoded: &str,
dictionary: &Dictionary
) -> Result<Vec<u8>, String> {
decode(encoded, dictionary).map_err(|e| match e {
DecodeError::InvalidCharacter(c) => {
format!("Invalid character '{}' in encoded data", c)
}
DecodeError::EmptyInput => {
"Cannot decode empty string".to_string()
}
DecodeError::InvalidPadding => {
"Malformed padding in encoded data".to_string()
}
})
}
```
### Example 6: Working with User Config
```rust
use base_d::DictionariesConfig;
fn list_available_dictionaries() -> Result<(), Box<dyn std::error::Error>> {
// Load with user overrides
let config = DictionariesConfig::load_with_overrides()?;
println!("Available dictionaries:");
for (name, dict_config) in config.dictionaries.iter() {
let mode = match dict_config.mode {
base_d::EncodingMode::BaseConversion => "math",
base_d::EncodingMode::Chunked => "chunked",
base_d::EncodingMode::ByteRange => "range",
};
let size = match dict_config.mode {
base_d::EncodingMode::ByteRange => 256,
_ => dict_config.chars.chars().count(),
};
println!(" {} (base-{}, {})", name, size, mode);
}
Ok(())
}
```
## Thread Safety
All types are `Send` and `Sync` where appropriate:
- `Dictionary` is `Send + Sync`
- `DictionariesConfig` is `Send + Sync`
- `StreamingEncoder` and `StreamingDecoder` are `Send` (not `Sync` due to `Write` requirement)
## Hashing API
### `HashAlgorithm`
Supported hash algorithms.
```rust
use base_d::HashAlgorithm;
use std::str::FromStr;
// Parse from string
let algo = HashAlgorithm::from_str("sha256")?;
// Get output size
let size = HashAlgorithm::Sha256.output_size(); // 32 bytes
// Get string representation
let name = HashAlgorithm::Blake3.as_str(); // "blake3"
```
### `hash`
Compute hash with default settings (backward compatible).
```rust
use base_d::{hash, HashAlgorithm};
let data = b"hello world";
let hash_bytes = hash(data, HashAlgorithm::Sha256);
// Returns Vec<u8> with raw hash output
```
### `hash_with_config`
Compute hash with custom xxHash configuration (seed and/or secret).
```rust
use base_d::{hash_with_config, HashAlgorithm, XxHashConfig};
let data = b"hello world";
// Use custom seed
let config = XxHashConfig::with_seed(42);
let hash_bytes = hash_with_config(data, HashAlgorithm::XxHash64, &config);
// Hash output will differ from default seed (0)
```
### `XxHashConfig`
Configuration for xxHash algorithms.
```rust
#[derive(Debug, Clone, Default)]
pub struct XxHashConfig {
pub seed: u64,
pub secret: Option<Vec<u8>>,
}
impl XxHashConfig {
pub fn with_seed(seed: u64) -> Self;
pub fn with_secret(seed: u64, secret: Vec<u8>) -> Result<Self, String>;
}
```
## Hashing Examples
### Example 7: Hashing with Custom Seed
```rust
use base_d::{hash_with_config, HashAlgorithm, XxHashConfig};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let data = b"hello world";
// Default seed (backward compatible)
let default_config = XxHashConfig::default();
let hash1 = hash_with_config(data, HashAlgorithm::XxHash64, &default_config);
// Custom seed
let custom_config = XxHashConfig::with_seed(42);
let hash2 = hash_with_config(data, HashAlgorithm::XxHash64, &custom_config);
// Different seeds produce different hashes
assert_ne!(hash1, hash2);
// Format as hex string
let hex = hash2.iter()
.map(|b| format!("{:02x}", b))
.collect::<String>();
println!("Hash: {}", hex);
Ok(())
}
```
### Example 8: XXH3 with Secret File
```rust
use base_d::{hash_with_config, HashAlgorithm, XxHashConfig};
use std::fs;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Read secret from file (must be >= 136 bytes)
let secret = fs::read("/path/to/xxh3-secret.bin")?;
// Create config with seed and secret
let config = XxHashConfig::with_secret(0, secret)?;
// Hash data with secret
let data = b"sensitive data";
let hash = hash_with_config(data, HashAlgorithm::XxHash3_64, &config);
println!("XXH3 hash: {:x?}", hash);
Ok(())
}
```
### Example 9: Loading xxHash Config from TOML
```rust
use base_d::{DictionariesConfig, XxHashConfig, hash_with_config, HashAlgorithm};
use std::fs;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Load config from file
let config = DictionariesConfig::load_with_overrides()?;
// Build XxHashConfig from settings
let seed = config.settings.xxhash.default_seed;
let xxhash_config = if let Some(ref secret_path) = config.settings.xxhash.default_secret_file {
// Expand tilde in path
let expanded = shellexpand::tilde(secret_path);
let secret = fs::read(expanded.as_ref())?;
XxHashConfig::with_secret(seed, secret)?
} else {
XxHashConfig::with_seed(seed)
};
// Use config for hashing
let data = b"hello world";
let hash = hash_with_config(data, HashAlgorithm::XxHash64, &xxhash_config);
println!("Hash: {:x?}", hash);
Ok(())
}
```
### Example 10: xxHash in Streaming Mode
```rust
use base_d::{DictionariesConfig, Dictionary, StreamingEncoder, XxHashConfig, HashAlgorithm};
use std::fs::File;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = DictionariesConfig::load_default()?;
let dict_config = config.get_dictionary("base64").unwrap();
let chars: Vec<char> = dict_config.chars.chars().collect();
let dictionary = Dictionary::new_with_mode(
chars,
dict_config.mode.clone(),
dict_config.padding.as_ref().and_then(|s| s.chars().next())
)?;
// Create xxHash config with custom seed
let xxhash_config = XxHashConfig::with_seed(42);
let mut input = File::open("large_file.bin")?;
let output = File::create("encoded.txt")?;
// Create streaming encoder with hashing enabled
let mut encoder = StreamingEncoder::new(&dictionary, output)
.with_xxhash_config(xxhash_config)
.with_hash(HashAlgorithm::XxHash64);
encoder.encode(&mut input)?;
// Hash is computed during streaming and included in output metadata
Ok(())
}
```
## Performance Tips
1. **Reuse Dictionaries**: Create dictionary once and reuse for multiple operations
2. **Use Streaming**: For files > 10MB, use `StreamingEncoder`/`StreamingDecoder`
3. **Choose Right Mode**:
- Chunked: Best for RFC compliance and streaming
- ByteRange: Best for emoji/1:1 mapping
- BaseConversion: Most flexible but slowest
4. **Avoid String Allocations**: `encode` returns `String`, consider using streaming for large data
5. **xxHash for Speed**: Use xxHash3 for fastest non-cryptographic hashing
6. **Reuse Hash Config**: Create `XxHashConfig` once and reuse across multiple operations
## See Also
- [DICTIONARIES.md](DICTIONARIES.md) - All built-in dictionaries
- [ENCODING_MODES.md](ENCODING_MODES.md) - Encoding algorithm details
- [STREAMING.md](STREAMING.md) - Streaming guide
- [CUSTOM_DICTIONARIES.md](CUSTOM_DICTIONARIES.md) - Creating custom dictionaries