From 6a91b5aba1bd2b566c7c57a75c2c0da4da984e2b Mon Sep 17 00:00:00 2001 From: Michael Macias Date: Fri, 6 Sep 2024 11:50:44 -0500 Subject: [PATCH] vcf/record/info/field/value: Percent-decode string value This changes string values from `&str` to `Cow<'_, str>`. Fixes #300. --- .../codec/encoder/site/info/field/value.rs | 2 +- noodles-bcf/src/record/info/field/value.rs | 4 +-- noodles-vcf/CHANGELOG.md | 6 ++--- noodles-vcf/src/record/info/field/value.rs | 26 ++++++++++++++++++- .../src/variant/record/info/field/value.rs | 4 +-- .../variant/record_buf/info/field/value.rs | 4 +-- 6 files changed, 35 insertions(+), 11 deletions(-) diff --git a/noodles-bcf/src/record/codec/encoder/site/info/field/value.rs b/noodles-bcf/src/record/codec/encoder/site/info/field/value.rs index 2e68b0a9f..0df48972d 100644 --- a/noodles-bcf/src/record/codec/encoder/site/info/field/value.rs +++ b/noodles-bcf/src/record/codec/encoder/site/info/field/value.rs @@ -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) } diff --git a/noodles-bcf/src/record/info/field/value.rs b/noodles-bcf/src/record/info/field/value.rs index 178e22b00..304791749 100644 --- a/noodles-bcf/src/record/info/field/value.rs +++ b/noodles-bcf/src/record/info/field/value.rs @@ -1,4 +1,4 @@ -use std::{io, iter}; +use std::{borrow::Cow, io, iter}; use noodles_vcf::{ self as vcf, @@ -154,7 +154,7 @@ fn read_character_array_value<'a>(src: &mut &'a [u8]) -> io::Result(src: &mut &'a [u8]) -> io::Result>> { 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)), } } diff --git a/noodles-vcf/CHANGELOG.md b/noodles-vcf/CHANGELOG.md index 9923747a3..c33918840 100644 --- a/noodles-vcf/CHANGELOG.md +++ b/noodles-vcf/CHANGELOG.md @@ -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 diff --git a/noodles-vcf/src/record/info/field/value.rs b/noodles-vcf/src/record/info/field/value.rs index 2bada30c1..cc0d31915 100644 --- a/noodles-vcf/src/record/info/field/value.rs +++ b/noodles-vcf/src/record/info/field/value.rs @@ -59,7 +59,11 @@ fn parse_character_value(src: &str) -> io::Result> { } fn parse_string_value(src: &str) -> io::Result> { - 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> { @@ -77,3 +81,23 @@ fn parse_character_array_value(src: &str) -> io::Result> { fn parse_string_array_value(src: &str) -> io::Result> { 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(()) + } +} diff --git a/noodles-vcf/src/variant/record/info/field/value.rs b/noodles-vcf/src/variant/record/info/field/value.rs index 47b724876..dfa75983d 100644 --- a/noodles-vcf/src/variant/record/info/field/value.rs +++ b/noodles-vcf/src/variant/record/info/field/value.rs @@ -2,7 +2,7 @@ pub mod array; -use std::io; +use std::{borrow::Cow, io}; pub use self::array::Array; @@ -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>), } diff --git a/noodles-vcf/src/variant/record_buf/info/field/value.rs b/noodles-vcf/src/variant/record_buf/info/field/value.rs index 5842c389a..ffbf9273c 100644 --- a/noodles-vcf/src/variant/record_buf/info/field/value.rs +++ b/noodles-vcf/src/variant/record_buf/info/field/value.rs @@ -2,7 +2,7 @@ mod array; -use std::str; +use std::{borrow::Cow, str}; pub use self::array::Array; @@ -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()), } }