-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add reed solomon encoding #190
Conversation
e504f0c
to
eb316e5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Rust part.
Very good job! I like the copying slice into slice part, using copy_from_slice
was the good choice.
The general remark is that it would be nice to add some tests to check if the interface is good. Just several simple cases showing that we cannot easily trigger undefined behaviour.
Example:
#[cfg(test)]
mod tests {
use super::*;
use std::ptr;
#[test]
fn test_decode_success() {
// Mock data setup
let original_shards_count = 2;
let recovery_shards_count = 1;
let shard_size = 4;
let original_shards: [u8; 8] = [1, 2, 3, 4, 5, 6, 7, 8];
let original_shards_indexes: [usize; 2] = [0, 1];
let recovery_shards: [u8; 4] = [9, 10, 11, 12];
let recovery_shards_indexes: [usize; 1] = [2];
let mut recovered_shards_out: [u8; 4] = [0; 4];
let mut recovered_shards_indexes_out: [usize; 1] = [0; 1];
unsafe {
let result = reed_solomon_decode(
original_shards_count,
recovery_shards_count,
shard_size,
original_shards.as_ptr(),
original_shards.len(),
original_shards_indexes.as_ptr(),
recovery_shards.as_ptr(),
recovery_shards.len(),
recovery_shards_indexes.as_ptr(),
recovered_shards_out.as_mut_ptr(),
recovered_shards_indexes_out.as_mut_ptr(),
);
assert_eq!(result, 0); // Success
assert_eq!(recovered_shards_out, [9, 10, 11, 12]);
assert_eq!(recovered_shards_indexes_out, [2]);
}
}
#[test]
fn test_decode_invalid_shard_size() {
let original_shards_count = 2;
let recovery_shards_count = 1;
let shard_size = 4;
let original_shards: [u8; 9] = [1, 2, 3, 4, 5, 6, 7, 8, 9];
let original_shards_indexes: [usize; 2] = [0, 1];
let recovery_shards: [u8; 4] = [9, 10, 11, 12];
let recovery_shards_indexes: [usize; 1] = [2];
let mut recovered_shards_out: [u8; 4] = [0; 4];
let mut recovered_shards_indexes_out: [usize; 1] = [0; 1];
unsafe {
let result = reed_solomon_decode(
original_shards_count,
recovery_shards_count,
shard_size,
original_shards.as_ptr(),
original_shards.len(),
original_shards_indexes.as_ptr(),
recovery_shards.as_ptr(),
recovery_shards.len(),
recovery_shards_indexes.as_ptr(),
recovered_shards_out.as_mut_ptr(),
recovered_shards_indexes_out.as_mut_ptr(),
);
assert_eq!(result, -1); // Failure due to invalid shard size
}
}
#[test]
fn test_decode_mismatched_shard_counts() {
let original_shards_count = 3; // Incorrect count
let recovery_shards_count = 1;
let shard_size = 4;
let original_shards: [u8; 8] = [1, 2, 3, 4, 5, 6, 7, 8];
let original_shards_indexes: [usize; 2] = [0, 1];
let recovery_shards: [u8; 4] = [9, 10, 11, 12];
let recovery_shards_indexes: [usize; 1] = [2];
let mut recovered_shards_out: [u8; 4] = [0; 4];
let mut recovered_shards_indexes_out: [usize; 1] = [0; 1];
unsafe {
let result = reed_solomon_decode(
original_shards_count,
recovery_shards_count,
shard_size,
original_shards.as_ptr(),
original_shards.len(),
original_shards_indexes.as_ptr(),
recovery_shards.as_ptr(),
recovery_shards.len(),
recovery_shards_indexes.as_ptr(),
recovered_shards_out.as_mut_ptr(),
recovered_shards_indexes_out.as_mut_ptr(),
);
assert_eq!(result, -1); // Failure due to mismatched shard count
}
}
#[test]
fn test_decode_minimum_shards() {
let original_shards_count = 1;
let recovery_shards_count = 1;
let shard_size = 4;
let original_shards: [u8; 4] = [1, 2, 3, 4];
let original_shards_indexes: [usize; 1] = [0];
let recovery_shards: [u8; 4] = [5, 6, 7, 8];
let recovery_shards_indexes: [usize; 1] = [1];
let mut recovered_shards_out: [u8; 4] = [0; 4];
let mut recovered_shards_indexes_out: [usize; 1] = [0; 1];
unsafe {
let result = reed_solomon_decode(
original_shards_count,
recovery_shards_count,
shard_size,
original_shards.as_ptr(),
original_shards.len(),
original_shards_indexes.as_ptr(),
recovery_shards.as_ptr(),
recovery_shards.len(),
recovery_shards_indexes.as_ptr(),
recovered_shards_out.as_mut_ptr(),
recovered_shards_indexes_out.as_mut_ptr(),
);
assert_eq!(result, 0); // Success
assert_eq!(recovered_shards_out, [5, 6, 7, 8]);
assert_eq!(recovered_shards_indexes_out, [1]);
}
}
#[test]
fn test_decode_null_pointer() {
let original_shards_count = 2;
let recovery_shards_count = 1;
let shard_size = 4;
let original_shards: [u8; 8] = [1, 2, 3, 4, 5, 6, 7, 8];
let original_shards_indexes: [usize; 2] = [0, 1];
let recovery_shards: [u8; 4] = [9, 10, 11, 12];
let recovery_shards_indexes: [usize; 1] = [2];
let mut recovered_shards_out: [u8; 4] = [0; 4];
let mut recovered_shards_indexes_out: [usize; 1] = [0; 1];
unsafe {
// Test null pointer for original_shards
let result = reed_solomon_decode(
original_shards_count,
recovery_shards_count,
shard_size,
ptr::null(),
original_shards.len(),
original_shards_indexes.as_ptr(),
recovery_shards.as_ptr(),
recovery_shards.len(),
recovery_shards_indexes.as_ptr(),
recovered_shards_out.as_mut_ptr(),
recovered_shards_indexes_out.as_mut_ptr(),
);
assert_eq!(result, -1); // Failure due to null pointer
// Test null pointer for recovery_shards
let result = reed_solomon_decode(
original_shards_count,
recovery_shards_count,
shard_size,
original_shards.as_ptr(),
original_shards.len(),
original_shards_indexes.as_ptr(),
ptr::null(),
recovery_shards.len(),
recovery_shards_indexes.as_ptr(),
recovered_shards_out.as_mut_ptr(),
recovered_shards_indexes_out.as_mut_ptr(),
);
assert_eq!(result, -1); // Failure due to null pointer
// Test null pointer for recovered_shards_out
let result = reed_solomon_decode(
original_shards_count,
recovery_shards_count,
shard_size,
original_shards.as_ptr(),
original_shards.len(),
original_shards_indexes.as_ptr(),
recovery_shards.as_ptr(),
recovery_shards.len(),
recovery_shards_indexes.as_ptr(),
ptr::null_mut(),
recovered_shards_indexes_out.as_mut_ptr(),
);
assert_eq!(result, -1); // Failure due to null pointer
// Test null pointer for recovered_shards_indexes_out
let result = reed_solomon_decode(
original_shards_count,
recovery_shards_count,
shard_size,
original_shards.as_ptr(),
original_shards.len(),
original_shards_indexes.as_ptr(),
recovery_shards.as_ptr(),
recovery_shards.len(),
recovery_shards_indexes.as_ptr(),
recovered_shards_out.as_mut_ptr(),
ptr::null_mut(),
);
assert_eq!(result, -1); // Failure due to null pointer
}
}
}
@asmie thanks again for the detailed Rust review. :) |
00b23e4
to
4275a6b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice job!
Only some nitpicks left - feel free to use them or not 😄
Just a random thought: if we can distinguish what went wrong maybe we could use more error consts than only -1
- but if we just want to indicate error, we can even join those if
s together, as all of the error conditions returns exactly the same value 👍
Overall, LGTM, merge whenever Go side is approved 👍
23d962c
to
ec492c7
Compare
Add reed solomon encoding by wrapping the rust reed-solomon-simd crate and exposing it via FFI.
ec492c7
to
59b3024
Compare
Thanks for all the feedback. :) Addressed it all. Added some limitations for total shards and shard size, that should prevent any overflows too. |
59b3024
to
8ca6183
Compare
Add reed solomon encoding by wrapping the rust reed-solomon-simd crate and exposing it via FFI.
Part of #141