From ecc0037ae8c1f7407960da703d9e8b498f0ecc93 Mon Sep 17 00:00:00 2001 From: Michael Macias Date: Wed, 11 Jan 2023 11:37:59 -0600 Subject: [PATCH] sam/header/record/value/map/read_group/platform: Disallow inputs with mixed-case This is in response to the change in samtools/hts-specs#684. --- noodles-sam/CHANGELOG.md | 3 +++ .../record/value/map/read_group/platform.rs | 27 ++++++++++++++++--- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/noodles-sam/CHANGELOG.md b/noodles-sam/CHANGELOG.md index 5c85d818f..9a33806ef 100644 --- a/noodles-sam/CHANGELOG.md +++ b/noodles-sam/CHANGELOG.md @@ -33,6 +33,9 @@ * sam/header/record: Add record IDs to `ParseError::InvalidReferenceSequence` and `ParseError::InvalidReadGroup`. + * sam/header/record/value/map/read_group/platform: Disallow inputs with + mixed-case. + * sam/header/record/value/map/reference_sequence: `ReferenceSequence::new` requires a nonzero length. diff --git a/noodles-sam/src/header/record/value/map/read_group/platform.rs b/noodles-sam/src/header/record/value/map/read_group/platform.rs index fea8ab537..c708624ca 100644 --- a/noodles-sam/src/header/record/value/map/read_group/platform.rs +++ b/noodles-sam/src/header/record/value/map/read_group/platform.rs @@ -1,6 +1,6 @@ //! SAM header read group platform. -use std::{error, fmt, str::FromStr}; +use std::{borrow::Cow, error, fmt, str::FromStr}; /// A SAM header read group platform (`PL`). #[derive(Clone, Copy, Debug, Eq, PartialEq)] @@ -77,8 +77,27 @@ impl FromStr for Platform { type Err = ParseError; fn from_str(s: &str) -> Result { - match s.to_uppercase().as_str() { - "" => Err(ParseError::Empty), + if s.is_empty() { + return Err(ParseError::Empty); + } + + let (is_lowercase, is_uppercase) = s + .chars() + .filter(char::is_ascii_alphabetic) + .map(|c| c.is_ascii_uppercase()) + .fold((true, true), |(l, u), is_ascii_uppercase| { + (l & !is_ascii_uppercase, u & is_ascii_uppercase) + }); + + let t = if is_uppercase { + Cow::from(s) + } else if is_lowercase { + Cow::from(s.to_uppercase()) + } else { + return Err(ParseError::Invalid); + }; + + match t.as_ref() { "CAPILLARY" => Ok(Self::Capillary), "DNBSEQ" => Ok(Self::DnbSeq), "ELEMENT" => Ok(Self::Element), @@ -128,10 +147,10 @@ mod tests { assert_eq!("PACBIO".parse(), Ok(Platform::PacBio)); assert_eq!("ULTIMA".parse(), Ok(Platform::Ultima)); - assert_eq!("Illumina".parse(), Ok(Platform::Illumina)); assert_eq!("illumina".parse(), Ok(Platform::Illumina)); assert_eq!("".parse::(), Err(ParseError::Empty)); + assert_eq!("Illumina".parse::(), Err(ParseError::Invalid)); assert_eq!("NOODLES".parse::(), Err(ParseError::Invalid)); } }