Skip to content

Commit

Permalink
vcf/record/info/field/value: Percent-decode string value
Browse files Browse the repository at this point in the history
This changes string values from `&str` to `Cow<'_, str>`.

Fixes #300.
  • Loading branch information
zaeleus committed Sep 6, 2024
1 parent 99b0ec9 commit 6a91b5a
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ where
Some(field::Value::Float(n)) => write_float_value(writer, n),
Some(field::Value::Flag) => write_flag_value(writer),
Some(field::Value::Character(c)) => write_character_value(writer, c),
Some(field::Value::String(s)) => write_string_value(writer, s),
Some(field::Value::String(s)) => write_string_value(writer, &s),
Some(field::Value::Array(field::value::Array::Integer(values))) => {
write_integer_array_value(writer, values)
}
Expand Down
4 changes: 2 additions & 2 deletions noodles-bcf/src/record/info/field/value.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{io, iter};
use std::{borrow::Cow, io, iter};

use noodles_vcf::{
self as vcf,
Expand Down Expand Up @@ -154,7 +154,7 @@ fn read_character_array_value<'a>(src: &mut &'a [u8]) -> io::Result<Option<Value
fn read_string_value<'a>(src: &mut &'a [u8]) -> io::Result<Option<Value<'a>>> {
match read_typed_value(src)? {
None | Some(TypedValue::String(None)) => Ok(None),
Some(TypedValue::String(Some(s))) => Ok(Some(Value::String(s))),
Some(TypedValue::String(Some(s))) => Ok(Some(Value::String(Cow::from(s)))),
v => Err(type_mismatch_error(v, Type::String)),
}
}
Expand Down
6 changes: 3 additions & 3 deletions noodles-vcf/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

### Changed

* vcf/variant/record/info/field/value/array/values: Percent-decode string
values ([#300]).
* vcf/record/info/field/value: Percent-decode string value ([#300]).

This changes the values iterator item from `&str` to `Cow<'_, str>`.
This changes the string values (`Value::String` and
`Value::Array(Array::String)`) from `&str` to `Cow<'_, str>`.

[#300]: https://github.com/zaeleus/noodles/issues/300

Expand Down
26 changes: 25 additions & 1 deletion noodles-vcf/src/record/info/field/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,11 @@ fn parse_character_value(src: &str) -> io::Result<Value<'_>> {
}

fn parse_string_value(src: &str) -> io::Result<Value<'_>> {
Ok(Value::String(src))
use crate::io::reader::record_buf::value::percent_decode;

percent_decode(src)
.map(Value::String)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
}

fn parse_integer_array_value(src: &str) -> io::Result<Value<'_>> {
Expand All @@ -77,3 +81,23 @@ fn parse_character_array_value(src: &str) -> io::Result<Value<'_>> {
fn parse_string_array_value(src: &str) -> io::Result<Value<'_>> {
Ok(Value::Array(Array::String(Box::new(src))))
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_parse_string_value() -> io::Result<()> {
assert!(matches!(
parse_string_value("")?,
Value::String(s) if s == ""
));

assert!(matches!(
parse_string_value("a%3Bb")?,
Value::String(s) if s == "a;b"
));

Ok(())
}
}
4 changes: 2 additions & 2 deletions noodles-vcf/src/variant/record/info/field/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

pub mod array;

use std::io;
use std::{borrow::Cow, io};

pub use self::array::Array;

Expand All @@ -18,7 +18,7 @@ pub enum Value<'a> {
/// A character.
Character(char),
/// A string.
String(&'a str),
String(Cow<'a, str>),
/// An array.
Array(Array<'a>),
}
Expand Down
4 changes: 2 additions & 2 deletions noodles-vcf/src/variant/record_buf/info/field/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

mod array;

use std::str;
use std::{borrow::Cow, str};

pub use self::array::Array;

Expand Down Expand Up @@ -84,7 +84,7 @@ impl<'a> From<&'a Value> for crate::variant::record::info::field::Value<'a> {
Value::Float(n) => Self::Float(*n),
Value::Flag => Self::Flag,
Value::Character(c) => Self::Character(*c),
Value::String(s) => Self::String(s.as_ref()),
Value::String(s) => Self::String(Cow::from(s.as_str())),
Value::Array(array) => Self::Array(array.into()),
}
}
Expand Down

0 comments on commit 6a91b5a

Please sign in to comment.