265 lines
7.1 KiB
Markdown
265 lines
7.1 KiB
Markdown
# Migration Guide: V to Rust RadixTree
|
|
|
|
This document provides guidance for migrating from the V implementation of RadixTree to the Rust implementation.
|
|
|
|
## API Changes
|
|
|
|
The Rust implementation maintains API compatibility with the V implementation, but with some idiomatic Rust changes:
|
|
|
|
### V API
|
|
|
|
```v
|
|
// Create a new radix tree
|
|
mut rt := radixtree.new(path: '/tmp/radixtree_test', reset: true)!
|
|
|
|
// Set a key-value pair
|
|
rt.set('test', 'value1'.bytes())!
|
|
|
|
// Get a value by key
|
|
value := rt.get('test')!
|
|
|
|
// Update a value at a prefix
|
|
rt.update('prefix', 'new_value'.bytes())!
|
|
|
|
// Delete a key
|
|
rt.delete('test')!
|
|
|
|
// List keys with a prefix
|
|
keys := rt.list('prefix')!
|
|
|
|
// Get all values with a prefix
|
|
values := rt.getall('prefix')!
|
|
```
|
|
|
|
### Rust API
|
|
|
|
```rust
|
|
// Create a new radix tree
|
|
let mut tree = RadixTree::new("/tmp/radixtree_test", true)?;
|
|
|
|
// Set a key-value pair
|
|
tree.set("test", b"value1".to_vec())?;
|
|
|
|
// Get a value by key
|
|
let value = tree.get("test")?;
|
|
|
|
// Update a value at a prefix
|
|
tree.update("prefix", b"new_value".to_vec())?;
|
|
|
|
// Delete a key
|
|
tree.delete("test")?;
|
|
|
|
// List keys with a prefix
|
|
let keys = tree.list("prefix")?;
|
|
|
|
// Get all values with a prefix
|
|
let values = tree.getall("prefix")?;
|
|
```
|
|
|
|
## Key Differences
|
|
|
|
1. **Error Handling**: The Rust implementation uses Rust's `Result` type for error handling, while the V implementation uses V's `!` operator.
|
|
|
|
2. **String Handling**: The Rust implementation uses Rust's `&str` for string parameters and `String` for string return values, while the V implementation uses V's `string` type.
|
|
|
|
3. **Binary Data**: The Rust implementation uses Rust's `Vec<u8>` for binary data, while the V implementation uses V's `[]u8` type.
|
|
|
|
4. **Constructor**: The Rust implementation uses a constructor function with separate parameters, while the V implementation uses a struct with named parameters.
|
|
|
|
5. **Ownership**: The Rust implementation follows Rust's ownership model, requiring mutable references for methods that modify the tree.
|
|
|
|
## Data Compatibility
|
|
|
|
The Rust implementation maintains data compatibility with the V implementation:
|
|
|
|
- The same serialization format is used for nodes
|
|
- The same OurDB storage format is used
|
|
- Existing RadixTree data created with the V implementation can be read by the Rust implementation
|
|
|
|
## Migration Steps
|
|
|
|
1. **Update Dependencies**: Replace the V RadixTree dependency with the Rust RadixTree dependency in your project.
|
|
|
|
2. **Update Import Statements**: Replace V import statements with Rust use statements.
|
|
|
|
```v
|
|
// V
|
|
import freeflowuniverse.herolib.data.radixtree
|
|
```
|
|
|
|
```rust
|
|
// Rust
|
|
use radixtree::RadixTree;
|
|
```
|
|
|
|
3. **Update Constructor Calls**: Replace V constructor calls with Rust constructor calls.
|
|
|
|
```v
|
|
// V
|
|
mut rt := radixtree.new(path: '/path/to/db', reset: false)!
|
|
```
|
|
|
|
```rust
|
|
// Rust
|
|
let mut tree = RadixTree::new("/path/to/db", false)?;
|
|
```
|
|
|
|
4. **Update Method Calls**: Replace V method calls with Rust method calls.
|
|
|
|
```v
|
|
// V
|
|
rt.set('key', 'value'.bytes())!
|
|
```
|
|
|
|
```rust
|
|
// Rust
|
|
tree.set("key", b"value".to_vec())?;
|
|
```
|
|
|
|
5. **Update Error Handling**: Replace V error handling with Rust error handling.
|
|
|
|
```v
|
|
// V
|
|
if value := rt.get('key') {
|
|
println('Found: ${value.bytestr()}')
|
|
} else {
|
|
println('Error: ${err}')
|
|
}
|
|
```
|
|
|
|
```rust
|
|
// Rust
|
|
match tree.get("key") {
|
|
Ok(value) => println!("Found: {}", String::from_utf8_lossy(&value)),
|
|
Err(e) => println!("Error: {}", e),
|
|
}
|
|
```
|
|
|
|
6. **Update String Conversions**: Replace V string conversions with Rust string conversions.
|
|
|
|
```v
|
|
// V
|
|
value.bytestr() // Convert []u8 to string
|
|
```
|
|
|
|
```rust
|
|
// Rust
|
|
String::from_utf8_lossy(&value) // Convert Vec<u8> to string
|
|
```
|
|
|
|
## Example Migration
|
|
|
|
### V Code
|
|
|
|
```v
|
|
module main
|
|
|
|
import freeflowuniverse.herolib.data.radixtree
|
|
|
|
fn main() {
|
|
mut rt := radixtree.new(path: '/tmp/radixtree_test', reset: true) or {
|
|
println('Error creating RadixTree: ${err}')
|
|
return
|
|
}
|
|
|
|
rt.set('hello', 'world'.bytes()) or {
|
|
println('Error setting key: ${err}')
|
|
return
|
|
}
|
|
|
|
rt.set('help', 'me'.bytes()) or {
|
|
println('Error setting key: ${err}')
|
|
return
|
|
}
|
|
|
|
if value := rt.get('hello') {
|
|
println('hello: ${value.bytestr()}')
|
|
} else {
|
|
println('Error getting key: ${err}')
|
|
return
|
|
}
|
|
|
|
keys := rt.list('hel') or {
|
|
println('Error listing keys: ${err}')
|
|
return
|
|
}
|
|
println('Keys with prefix "hel": ${keys}')
|
|
|
|
values := rt.getall('hel') or {
|
|
println('Error getting all values: ${err}')
|
|
return
|
|
}
|
|
println('Values with prefix "hel":')
|
|
for i, value in values {
|
|
println(' ${i}: ${value.bytestr()}')
|
|
}
|
|
|
|
rt.delete('help') or {
|
|
println('Error deleting key: ${err}')
|
|
return
|
|
}
|
|
println('Deleted "help"')
|
|
}
|
|
```
|
|
|
|
### Rust Code
|
|
|
|
```rust
|
|
use radixtree::RadixTree;
|
|
|
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
let mut tree = RadixTree::new("/tmp/radixtree_test", true)
|
|
.map_err(|e| format!("Error creating RadixTree: {}", e))?;
|
|
|
|
tree.set("hello", b"world".to_vec())
|
|
.map_err(|e| format!("Error setting key: {}", e))?;
|
|
|
|
tree.set("help", b"me".to_vec())
|
|
.map_err(|e| format!("Error setting key: {}", e))?;
|
|
|
|
let value = tree.get("hello")
|
|
.map_err(|e| format!("Error getting key: {}", e))?;
|
|
println!("hello: {}", String::from_utf8_lossy(&value));
|
|
|
|
let keys = tree.list("hel")
|
|
.map_err(|e| format!("Error listing keys: {}", e))?;
|
|
println!("Keys with prefix \"hel\": {:?}", keys);
|
|
|
|
let values = tree.getall("hel")
|
|
.map_err(|e| format!("Error getting all values: {}", e))?;
|
|
println!("Values with prefix \"hel\":");
|
|
for (i, value) in values.iter().enumerate() {
|
|
println!(" {}: {}", i, String::from_utf8_lossy(value));
|
|
}
|
|
|
|
tree.delete("help")
|
|
.map_err(|e| format!("Error deleting key: {}", e))?;
|
|
println!("Deleted \"help\"");
|
|
|
|
Ok(())
|
|
}
|
|
```
|
|
|
|
## Performance Considerations
|
|
|
|
The Rust implementation should provide similar or better performance compared to the V implementation. However, there are some considerations:
|
|
|
|
1. **Memory Usage**: The Rust implementation may have different memory usage patterns due to Rust's ownership model.
|
|
|
|
2. **Error Handling**: The Rust implementation uses Rust's `Result` type, which may have different performance characteristics compared to V's error handling.
|
|
|
|
3. **String Handling**: The Rust implementation uses Rust's string types, which may have different performance characteristics compared to V's string types.
|
|
|
|
## Troubleshooting
|
|
|
|
If you encounter issues during migration, check the following:
|
|
|
|
1. **Data Compatibility**: Ensure that the data format is compatible between the V and Rust implementations.
|
|
|
|
2. **API Usage**: Ensure that you're using the correct API for the Rust implementation.
|
|
|
|
3. **Error Handling**: Ensure that you're handling errors correctly in the Rust implementation.
|
|
|
|
4. **String Encoding**: Ensure that string encoding is consistent between the V and Rust implementations.
|
|
|
|
If you encounter any issues that are not covered in this guide, please report them to the project maintainers. |