-
Notifications
You must be signed in to change notification settings - Fork 14
Implement handling of invalid values in arrays #46
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -38,7 +38,8 @@ impl Value { | |
Value::UInt64z(val) => *val != 0x0, | ||
// TODO: I need to check this logic, since for Byte Arrays it's only invalid if | ||
// all the values are invalid. Is that the case for all array fields or just "byte arrays"? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider removing this comment since this should be resolved with this PR |
||
Value::Array(vals) => !vals.is_empty() && vals.iter().all(|v| v.is_valid()), | ||
Value::Array(vals) => !vals.is_empty() && vals.iter().any(|v| v.is_valid()), | ||
Value::Invalid => false, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think there is a hypothetical issue here. Since values are abstracted as enum variants, we could in theory create a Value::Array which contains values of differing types. If those values would be valid, this code would return True. However an array of values should never contain values of differing types. As long as the parsing code is well-behaved this case should never appear but if this should be checked I would propose something like this: if let Some(first) = vals.first().map(|v|discriminant(v)) {
vals.iter().all(|x|matiches!(x, Value::Invalid) || discriminant(x) == first) && vals.iter().any(|v| v.is_valid())
} else {
false
} or a bit less concise but without double iteration: if let Some(first) = vals.first().map(|v| discriminant(v)) {
let mut same_type = true;
let mut any_valid = false;
for v in vals{
same_type &= matiches!(x, Value::Invalid) || discriminant(v) == first;
any_valid |= v.is_valid();
}
same_type && any_valid
} else {
false
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You are correct, I have that noted in the actual If FIT file writing ever gets implemented then we’d want to validate array contents somewhere along the way in the serialization process. |
||
} | ||
} | ||
} | ||
|
@@ -595,7 +596,11 @@ fn data_field_value( | |
_ => le_u8(input).map(|(i, v)| (i, Value::UInt8(v)))?, // Treat unexpected like Byte | ||
}; | ||
bytes_consumed += base_type.size(); | ||
values.push(value); | ||
if value.is_valid() { | ||
values.push(value); | ||
} else { | ||
values.push(Value::Invalid) | ||
} | ||
Comment on lines
-598
to
+603
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looking at the FIT file specification again, I think there might be an Issue here. As I unuderstand it now, the special remark regarding the Byte value and arrays of it addresses the following situation: For all Value types except the Byte type, value validity for values inside an array is determined on a per value basis. For byte values however, if one value inside the array is considered valid, all should be considered valid. I think this might be the case, because otherwise not a single byte inside a Byte array filed would be allowed to be Currently, a byte array My proposal: if matches!(base_type, FitBaseType::Byte) || value.is_valid() {
values.push(value);
} else {
values.push(Value::Invalid)
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You are spot on, great catch on that bug. |
||
input = i; | ||
} | ||
|
||
|
@@ -606,7 +611,7 @@ fn data_field_value( | |
Value::Array(values) | ||
}; | ||
|
||
// Only return "something" if it's in the valid range | ||
// Strip invalid values from the output | ||
if value.is_valid() { | ||
Ok((input, Some(value))) | ||
} else { | ||
|
@@ -684,7 +689,7 @@ mod tests { | |
|
||
#[test] | ||
fn data_field_value_test_array_value() { | ||
let data = [0x00, 0x01, 0x02, 0x03, 0xFF]; | ||
let data = [0x00, 0x01, 0x02, 0x03, 0xFF, 0x05]; | ||
|
||
// parse off a valid byte | ||
let (rem, val) = | ||
|
@@ -701,18 +706,24 @@ mod tests { | |
), | ||
None => panic!("No value returned."), | ||
} | ||
assert_eq!(rem, &[0xFF]); | ||
assert_eq!(rem, &[0xFF, 0x05]); | ||
|
||
// parse off an invalid byte | ||
let (rem, val) = | ||
data_field_value(&data, FitBaseType::Uint8, Endianness::Native, 5).unwrap(); | ||
if val.is_some() { | ||
panic!("None should be returned for invalid bytes.") | ||
} | ||
assert_eq!(rem, &[]); | ||
|
||
if val.is_some() { | ||
panic!("None should be returned for array with an invalid size.") | ||
data_field_value(&data, FitBaseType::Uint8, Endianness::Native, 6).unwrap(); | ||
match val { | ||
Some(v) => assert_eq!( | ||
v, | ||
Value::Array(vec![ | ||
Value::UInt8(0x00), | ||
Value::UInt8(0x01), | ||
Value::UInt8(0x02), | ||
Value::UInt8(0x03), | ||
Value::Invalid, | ||
Value::UInt8(0x05), | ||
]) | ||
), | ||
None => panic!("No value returned."), | ||
} | ||
assert_eq!(rem, &[]); | ||
} | ||
|
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.
Consider
let mut value = Vec::with_capacity(size as _);
in line 574.