| Crates.io | v-storage |
| lib.rs | v-storage |
| version | 0.1.2 |
| created_at | 2025-07-04 18:41:18.717885+00 |
| updated_at | 2025-09-18 18:40:11.119261+00 |
| description | Storage layer for the veda platform |
| homepage | |
| repository | |
| max_upload_size | |
| id | 1738317 |
| size | 204,046 |
A flexible storage abstraction library for the Veda platform. Provides unified interface for different storage backends including memory, LMDB, Tarantool, and remote storage.
Storage trait for all backendsAdd this to your Cargo.toml:
[dependencies]
v-storage = "0.1.0"
# Optional features
v-storage = { version = "0.1.0", features = ["tt_2", "tokio_0_2"] }
tt_2 - Tarantool 2.x supporttt_3 - Tarantool 3.x supporttokio_0_2 - Tokio 0.2 runtime supporttokio_1 - Tokio 1.x runtime supportuse v_storage::*;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create memory storage
let storage = VStorage::builder()
.memory()
.build()?;
let mut storage = VStorage::new(storage);
// Store Individual with semantic predicates
storage.put_value(StorageId::Individuals, "user:1", r#"{
"@": "user:1",
"rdf:type": [{"type": "Uri", "data": "foaf:Person"}],
"rdfs:label": [{"type": "String", "data": "John Smith - Software Engineer"}],
"foaf:name": [{"type": "String", "data": "John"}],
"foaf:familyName": [{"type": "String", "data": "Smith"}],
"foaf:age": [{"type": "Integer", "data": 30}],
"foaf:mbox": [{"type": "String", "data": "john.smith@example.com"}],
"veda:hasPosition": [{"type": "Uri", "data": "position:software_engineer"}],
"org:memberOf": [{"type": "Uri", "data": "org:development_team"}]
}"#)?;
// Retrieve Individual
if let StorageResult::Ok(data) = storage.get_value(StorageId::Individuals, "user:1") {
println!("User Individual: {} bytes", data.len());
}
Ok(())
}
| Type | Description | Dispatch | Use Case |
|---|---|---|---|
| VStorage | Dynamic dispatch with trait objects | Runtime | Maximum flexibility, runtime type selection |
| VStorageGeneric | Compile-time typed containers | Static | Type safety, known storage type |
| VStorageEnum | Static dispatch through enum | Static | Applications preferring enum dispatch |
use v_storage::*;
// Create storage using Builder pattern
let storage = VStorage::builder()
.memory()
.build()?;
let mut storage = VStorage::new(storage);
// Basic operations with semantic Individual data
storage.put_value(StorageId::Individuals, "person:example", r#"{
"@": "person:example",
"rdf:type": [{"type": "Uri", "data": "foaf:Person"}],
"rdfs:label": [{"type": "String", "data": "Example Person"}],
"foaf:name": [{"type": "String", "data": "Example"}]
}"#)?;
storage.get_value(StorageId::Individuals, "person:example")?;
storage.remove_value(StorageId::Individuals, "person:example")?;
storage.count(StorageId::Individuals)?;
// Builder Pattern
let storage = VStorage::builder()
.lmdb("/path/to/db", StorageMode::ReadWrite, None)
.build()?;
// Provider Pattern
let storage = StorageProvider::memory();
// Config Pattern
let config = StorageConfig::Memory;
let storage = VStorage::from_config(config)?;
use v_individual_model::onto::individual::Individual;
let mut individual = Individual::default();
let result = storage.get_individual(
StorageId::Individuals,
"person:john",
&mut individual
);
match result {
v_result_code::ResultCode::Ok => {
println!("Individual loaded: {}", individual.get_id());
},
v_result_code::ResultCode::NotFound => {
println!("Individual not found");
},
_ => println!("Error loading individual"),
}
// Use VStorageEnum for static dispatch
let mut storage = VStorageEnum::memory();
// Batch operations with semantic Individual data
for i in 0..1000 {
let individual_data = format!(r#"{{
"@": "person:{}",
"rdf:type": [{{"type": "Uri", "data": "foaf:Person"}}],
"rdfs:label": [{{"type": "String", "data": "Person {}"}}],
"foaf:name": [{{"type": "String", "data": "Person{}"}}],
"veda:index": [{{"type": "Integer", "data": {}}}]
}}"#, i, i, i, i);
storage.put_value(
StorageId::Individuals,
&format!("person:{}", i),
&individual_data
)?;
}
Unified Storage interface allows switching between different storage implementations:
fn process_data(storage: &mut dyn Storage) {
// Works with any storage implementation
storage.put_value(StorageId::Individuals, "person:demo", r#"{
"@": "person:demo",
"rdf:type": [{"type": "Uri", "data": "foaf:Person"}],
"rdfs:label": [{"type": "String", "data": "Demo Person"}]
}"#);
}
Fluent API for configuring storage:
let storage = VStorage::builder()
.memory()
.build()?;
Multiple ways to create storage instances:
// Through provider
let storage1 = StorageProvider::memory();
// Through config
let storage2 = VStorage::from_config(StorageConfig::Memory)?;
// Through builder
let storage3 = VStorage::builder().memory().build()?;
Theoretical dispatch overhead (in practice, database I/O dominates):
| Storage Type | Dispatch | Memory | Flexibility |
|---|---|---|---|
| VStorageEnum | Static (enum match) | Stack | Fixed set of types |
| VStorageGeneric | Static (monomorphization) | Direct | Compile-time known |
| VStorage | Dynamic (vtable) | Heap | Runtime selection |
Note: In real applications, storage backend (LMDB, Tarantool, network) dominates timing.
let storage = VStorage::builder()
.memory()
.build()?;
let storage = VStorage::builder()
.lmdb("/path/to/database", StorageMode::ReadWrite, Some(1000))
.build()?;
// Requires tt_2 or tt_3 feature
let storage = VStorage::builder()
.tarantool("127.0.0.1:3301", "username", "password")
.build()?;
let storage = VStorage::builder()
.remote("127.0.0.1:8080")
.build()?;
The examples/ directory contains comprehensive examples:
Run examples:
cargo run --example basic_usage
cargo run --example storage_types
cargo run --example factory_patterns
cargo run --example individual_operations
# Basic build
cargo build
# With all features
cargo build --features "tt_2 tokio_0_2"
# Release build
cargo build --release
# Run tests
cargo test
# Run tests with features
cargo test --features "tt_2 tokio_0_2"
# Run integration tests
cargo test --test integration_tests
# Generate documentation
cargo doc --open
# Generate with examples
cargo doc --examples --open
The library uses comprehensive error types:
match storage.get_value(StorageId::Individuals, "key") {
StorageResult::Ok(value) => println!("Value: {}", value),
StorageResult::NotFound => println!("Key not found"),
StorageResult::Error(e) => println!("Error: {}", e),
}
# Unit tests
cargo test
# Integration tests
cargo test --test integration_tests
# Example tests
cargo test --examples
# All tests with release optimization
cargo test --release
We welcome contributions! Please see our Contributing Guide for details.
cargo buildcargo testcargo run --example basic_usagecargo fmt for formattingcargo clippy for lintingThis project is licensed under the MIT License - see the LICENSE file for details.
Q: Which storage type should I choose?
A: Use VStorageEnum for applications preferring static dispatch, VStorageGeneric for type safety with known storage types, and VStorage for maximum flexibility.
Q: Can I switch storage backends at runtime?
A: Yes, with VStorage dynamic dispatch. Generic types require compile-time selection.
Q: Is the library thread-safe? A: Storage instances are not thread-safe by default. Use appropriate synchronization for concurrent access.
Q: How do I handle network failures with RemoteStorage?
A: The library returns StorageResult::Error for network issues. Implement retry logic in your application.
Built with โค๏ธ for the Veda platform