diff --git a/noodles-bcf/src/lazy/record/value.rs b/noodles-bcf/src/lazy/record/value.rs index c25a61ad0..93b4e2087 100644 --- a/noodles-bcf/src/lazy/record/value.rs +++ b/noodles-bcf/src/lazy/record/value.rs @@ -8,11 +8,11 @@ mod ty; pub use self::{array::Array, float::Float, int16::Int16, int32::Int32, int8::Int8, ty::Type}; #[derive(Clone, Debug, PartialEq)] -pub enum Value { +pub enum Value<'a> { Int8(Option), Int16(Option), Int32(Option), Float(Option), - String(Option), + String(Option<&'a str>), Array(Array), } diff --git a/noodles-bcf/src/record/codec/decoder.rs b/noodles-bcf/src/record/codec/decoder.rs index 6ccccd5da..d1394e783 100644 --- a/noodles-bcf/src/record/codec/decoder.rs +++ b/noodles-bcf/src/record/codec/decoder.rs @@ -121,7 +121,7 @@ pub fn read_ref_alt(src: &mut &[u8], len: usize) -> io::Result<(ReferenceBases, for _ in 0..len { match read_value(src)? { - Some(Value::String(Some(s))) => alleles.push(s), + Some(Value::String(Some(s))) => alleles.push(s.into()), Some(Value::String(None)) => alleles.push(String::from(".")), v => { return Err(io::Error::new( diff --git a/noodles-bcf/src/record/codec/decoder/value.rs b/noodles-bcf/src/record/codec/decoder/value.rs index 9fa6a4681..cd5814d9d 100644 --- a/noodles-bcf/src/record/codec/decoder/value.rs +++ b/noodles-bcf/src/record/codec/decoder/value.rs @@ -2,7 +2,7 @@ mod ty; pub use self::ty::read_type; -use std::io::{self, Read}; +use std::{io, str}; use byteorder::{LittleEndian, ReadBytesExt}; @@ -11,7 +11,7 @@ use crate::lazy::record::{ Value, }; -pub fn read_value(src: &mut &[u8]) -> io::Result> { +pub fn read_value<'a>(src: &mut &'a [u8]) -> io::Result>> { let ty = read_type(src)?; match ty { @@ -111,10 +111,16 @@ fn read_float_array(src: &mut &[u8], len: usize) -> io::Result> { Ok(buf) } -fn read_string(src: &mut &[u8], len: usize) -> io::Result { - let mut buf = vec![0; len]; - src.read_exact(&mut buf)?; - String::from_utf8(buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) +fn read_string<'a>(src: &mut &'a [u8], len: usize) -> io::Result<&'a str> { + if src.len() < len { + return Err(io::Error::from(io::ErrorKind::UnexpectedEof)); + } + + let (buf, rest) = src.split_at(len); + let s = str::from_utf8(buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + *src = rest; + + Ok(s) } #[cfg(test)] diff --git a/noodles-bcf/src/record/codec/encoder/site.rs b/noodles-bcf/src/record/codec/encoder/site.rs index a47e58384..4928e2972 100644 --- a/noodles-bcf/src/record/codec/encoder/site.rs +++ b/noodles-bcf/src/record/codec/encoder/site.rs @@ -180,13 +180,14 @@ pub(crate) fn write_id(writer: &mut W, ids: &vcf::record::Ids) -> io::Result< where W: Write, { - let value = if ids.is_empty() { - Some(Value::String(None)) + if ids.is_empty() { + let value = Some(Value::String(None)); + write_value(writer, value) } else { - Some(Value::String(Some(ids.to_string()))) - }; - - write_value(writer, value) + let s = ids.to_string(); + let value = Some(Value::String(Some(&s))); + write_value(writer, value) + } } pub(crate) fn write_ref_alt( @@ -198,12 +199,13 @@ where W: Write, { let r#ref = reference_bases.to_string(); - let ref_value = Some(Value::String(Some(r#ref))); + let ref_value = Some(Value::String(Some(&r#ref))); write_value(writer, ref_value)?; if !alternate_bases.is_empty() { for allele in alternate_bases.iter() { - let alt_value = Some(Value::String(Some(allele.to_string()))); + let alt = allele.to_string(); + let alt_value = Some(Value::String(Some(&alt))); write_value(writer, alt_value)?; } } diff --git a/noodles-bcf/src/record/codec/encoder/site/info.rs b/noodles-bcf/src/record/codec/encoder/site/info.rs index d71863061..67af0a898 100644 --- a/noodles-bcf/src/record/codec/encoder/site/info.rs +++ b/noodles-bcf/src/record/codec/encoder/site/info.rs @@ -140,14 +140,15 @@ fn write_info_field_character_value(writer: &mut W, c: char) -> io::Result<() where W: Write, { - write_value(writer, Some(Value::String(Some(c.into())))) + let s = c.to_string(); + write_value(writer, Some(Value::String(Some(&s)))) } fn write_info_field_string_value(writer: &mut W, s: &str) -> io::Result<()> where W: Write, { - write_value(writer, Some(Value::String(Some(s.into())))) + write_value(writer, Some(Value::String(Some(s)))) } fn write_info_field_integer_array_value(writer: &mut W, values: &[Option]) -> io::Result<()> @@ -297,7 +298,7 @@ where s.push(c); } - write_value(writer, Some(Value::String(Some(s)))) + write_value(writer, Some(Value::String(Some(&s)))) } fn write_info_field_string_array_value( @@ -321,7 +322,7 @@ where } } - write_value(writer, Some(Value::String(Some(s)))) + write_value(writer, Some(Value::String(Some(&s)))) } #[cfg(test)] diff --git a/noodles-bcf/src/record/codec/encoder/value.rs b/noodles-bcf/src/record/codec/encoder/value.rs index 3f5facd1b..11a5f76b3 100644 --- a/noodles-bcf/src/record/codec/encoder/value.rs +++ b/noodles-bcf/src/record/codec/encoder/value.rs @@ -8,7 +8,7 @@ use byteorder::{LittleEndian, WriteBytesExt}; use crate::lazy::record::value::{Array, Float, Int16, Int32, Int8, Type, Value}; -pub fn write_value(writer: &mut W, value: Option) -> io::Result<()> +pub fn write_value(writer: &mut W, value: Option>) -> io::Result<()> where W: Write, { @@ -153,7 +153,7 @@ where Ok(()) } -fn write_string(writer: &mut W, value: Option) -> io::Result<()> +fn write_string(writer: &mut W, value: Option<&str>) -> io::Result<()> where W: Write, { @@ -238,11 +238,11 @@ mod tests { assert_eq!(buf, [0x07]); buf.clear(); - write_value(&mut buf, Some(Value::String(Some(String::from("n")))))?; + write_value(&mut buf, Some(Value::String(Some("n"))))?; assert_eq!(buf, [0x17, 0x6e]); buf.clear(); - write_value(&mut buf, Some(Value::String(Some(String::from("ndls")))))?; + write_value(&mut buf, Some(Value::String(Some("ndls"))))?; assert_eq!(buf, [0x47, 0x6e, 0x64, 0x6c, 0x73]); Ok(())