7.1 KiB
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
// 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
// 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
-
Error Handling: The Rust implementation uses Rust's
Result
type for error handling, while the V implementation uses V's!
operator. -
String Handling: The Rust implementation uses Rust's
&str
for string parameters andString
for string return values, while the V implementation uses V'sstring
type. -
Binary Data: The Rust implementation uses Rust's
Vec<u8>
for binary data, while the V implementation uses V's[]u8
type. -
Constructor: The Rust implementation uses a constructor function with separate parameters, while the V implementation uses a struct with named parameters.
-
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
-
Update Dependencies: Replace the V RadixTree dependency with the Rust RadixTree dependency in your project.
-
Update Import Statements: Replace V import statements with Rust use statements.
// V import freeflowuniverse.herolib.data.radixtree
// Rust use radixtree::RadixTree;
-
Update Constructor Calls: Replace V constructor calls with Rust constructor calls.
// V mut rt := radixtree.new(path: '/path/to/db', reset: false)!
// Rust let mut tree = RadixTree::new("/path/to/db", false)?;
-
Update Method Calls: Replace V method calls with Rust method calls.
// V rt.set('key', 'value'.bytes())!
// Rust tree.set("key", b"value".to_vec())?;
-
Update Error Handling: Replace V error handling with Rust error handling.
// V if value := rt.get('key') { println('Found: ${value.bytestr()}') } else { println('Error: ${err}') }
// Rust match tree.get("key") { Ok(value) => println!("Found: {}", String::from_utf8_lossy(&value)), Err(e) => println!("Error: {}", e), }
-
Update String Conversions: Replace V string conversions with Rust string conversions.
// V value.bytestr() // Convert []u8 to string
// Rust String::from_utf8_lossy(&value) // Convert Vec<u8> to string
Example Migration
V Code
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
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:
-
Memory Usage: The Rust implementation may have different memory usage patterns due to Rust's ownership model.
-
Error Handling: The Rust implementation uses Rust's
Result
type, which may have different performance characteristics compared to V's error handling. -
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:
-
Data Compatibility: Ensure that the data format is compatible between the V and Rust implementations.
-
API Usage: Ensure that you're using the correct API for the Rust implementation.
-
Error Handling: Ensure that you're handling errors correctly in the Rust implementation.
-
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.