use serde::de::{self, SeqAccess, MapAccess, Visitor};
use crate::fort_error::FError;
use crate::serde_common::{DResult, DError};
use crate::format_specs::FortField;
pub use crate::format_specs::{FortValue, FortFormat};
use crate::parsing;
#[derive(Debug, Clone)]
pub struct DeSettings {
trim_strings: bool,
}
impl DeSettings {
pub fn do_trim(mut self, trim_strings: bool) -> Self {
self.trim_strings = trim_strings;
self
}
}
impl Default for DeSettings {
fn default() -> Self {
Self { trim_strings: true }
}
}
pub fn from_str<'a, T>(s: &'a str, fmt: &'a FortFormat) -> DResult<T>
where T: de::Deserialize<'a>
{
from_str_custom(s, fmt, DeSettings::default())
}
pub fn from_str_custom<'a, T>(s: &'a str, fmt: &'a FortFormat, settings: DeSettings) -> DResult<T>
where T: de::Deserialize<'a>
{
let mut deserializer: Deserializer<'_, &str> = Deserializer::from_str(s, fmt, settings);
let t = T::deserialize(&mut deserializer)?;
Ok(t)
}
pub fn from_str_with_fields<'a, T, F>(s: &'a str, fmt: &'a FortFormat, fields: &'a[F]) -> DResult<T>
where T: de::Deserialize<'a>,
F: AsRef<str>
{
from_str_with_fields_custom(s, fmt, fields, DeSettings::default())
}
pub fn from_str_with_fields_custom<'a, T, F>(s: &'a str, fmt: &'a FortFormat, fields: &'a[F], settings: DeSettings) -> DResult<T>
where T: de::Deserialize<'a>,
F: AsRef<str>
{
let mut deserializer = Deserializer::from_str_with_fields(s, fmt, fields, settings);
let t = T::deserialize(&mut deserializer)?;
Ok(t)
}
pub struct Deserializer<'de, F: AsRef<str>> {
settings: DeSettings,
input: &'de str,
input_idx: usize,
fmt: &'de FortFormat,
fmt_idx: usize,
field_idx: usize,
fields: Option<&'de [F]>,
found_terminal_char: bool,
}
impl<'de, F: AsRef<str>> Deserializer<'de, F> {
pub fn from_str(input: &'de str, fmt: &'de FortFormat, settings: DeSettings) -> Self {
Self { settings, input, input_idx: 0, fmt, fmt_idx: 0, field_idx: 0, fields: None, found_terminal_char: false }
}
pub fn from_str_with_fields(input: &'de str, fmt: &'de FortFormat, fields: &'de[F], settings: DeSettings) -> Self {
Self { settings, input, input_idx: 0, fmt, fmt_idx: 0, field_idx: 0, fields: Some(fields), found_terminal_char: false }
}
fn advance_over_skips(&mut self) {
loop {
let peeked_fmt = self.fmt.get_field(self.fmt_idx);
match peeked_fmt {
Some(&FortField::Skip) => {
self.fmt_idx += 1;
let _ = self.next_n_bytes(1);
}
_ => return,
}
}
}
fn next_fmt(&mut self) -> DResult<&FortField> {
self.advance_over_skips();
loop {
let next_fmt = self.fmt.get_field(self.fmt_idx);
match next_fmt {
Some(field) => {
self.fmt_idx += 1;
self.field_idx += 1;
return Ok(field)
},
None => return Err(DError::FormatSpecTooShort)
}
}
}
fn curr_field(&self) -> Option<&str> {
if let Some(fields) = self.fields {
fields.get(self.field_idx).map(|f| f.as_ref())
} else {
panic!("Called next_field on a deserializer without fields")
}
}
fn try_prev_field(&self) -> Option<&str> {
if self.field_idx == 0 {
return None;
}
self.fields.map(|f| f.get(self.field_idx - 1))
.flatten()
.map(|f| f.as_ref())
}
#[allow(dead_code)] fn peek_fmt(&mut self) -> Option<&FortField> {
self.advance_over_skips();
self.fmt.get_field(self.fmt_idx)
}
fn rewind_fmt(&mut self) {
if self.fmt_idx == 0 {
return;
}
self.fmt_idx = self.fmt_idx.saturating_sub(1);
self.field_idx = self.field_idx.saturating_sub(1);
}
fn next_n_bytes(&mut self, n: u32) -> Result<&'de str, DError> {
let n: usize = n.try_into().expect("Could not fit u32 into usize");
let mut nbytes = 0;
for c in self.input[self.input_idx..].chars() {
nbytes += c.len_utf8();
if nbytes >= n { break; }
}
if nbytes < n {
return Err(DError::InputEndedEarly)
}
let s = &self.input[self.input_idx..self.input_idx+nbytes];
self.input_idx += nbytes;
Ok(s)
}
fn has_n_bytes_remaining(&self, n: u32) -> bool {
self.input.len() > n as usize
}
#[allow(dead_code)] fn prev_n_bytes(&mut self, n: u32) {
let n: usize = n.try_into().expect("Could not fit u32 into usize");
let mut nbytes = 0;
for c in self.input[..self.input_idx].chars().rev() {
nbytes += c.len_utf8();
if nbytes >= n { break; }
}
self.input_idx -= nbytes;
}
fn peek_char(&self) -> Option<char> {
self.input[self.input_idx..].chars().next()
}
fn next_list_directed_substring(&mut self, peek: bool) -> Result<&'de str, DError> {
self.skip_list_separators();
let next_char = self.peek_char()
.ok_or_else(|| DError::InputEndedEarly)?;
if next_char == '\'' || next_char == '"' {
self.take_quoted_string(peek)
} else {
self.take_until_sep(peek)
}
}
fn take_quoted_string(&mut self, peek: bool) -> Result<&'de str, DError> {
if self.found_terminal_char {
return Err(DError::InputEndedEarly)
}
let mut chars = self.input[self.input_idx..].chars();
let quote = chars.next().expect("Called take_quoted_string when all characters in the input had already been read.");
let mut nbytes = quote.len_utf8();
let mut found_end_quote = false;
for c in chars {
nbytes += c.len_utf8();
if c == quote {
found_end_quote = true;
break;
}
}
if !found_end_quote {
return Err(DError::ClosingQuoteMissing{quote, start_byte: self.input_idx});
}
let nbq = quote.len_utf8();
let inner_str = &self.input[self.input_idx+nbq..self.input_idx+nbytes-nbq];
if !peek {
self.input_idx += nbytes;
}
Ok(inner_str)
}
fn take_until_sep(&mut self, peek: bool) -> Result<&'de str, DError> {
if self.found_terminal_char {
return Err(DError::InputEndedEarly)
}
let start = self.input_idx;
loop {
let c = self.peek_char();
if Self::is_list_sep(c) {
break;
} else if Self::is_terminal_char(c) {
self.found_terminal_char = true;
break;
} else {
self.input_idx += c.map(|c| c.len_utf8()).unwrap_or(0);
}
}
let s = &self.input[start..self.input_idx];
if peek {
self.input_idx = start;
}
Ok(s)
}
fn skip_list_separators(&mut self) {
loop {
let c = self.peek_char();
if Self::is_list_sep(c) {
self.input_idx += c.map(|c| c.len_utf8()).unwrap_or(0);
if c.is_none() {
self.found_terminal_char = true;
break;
}
} else if Self::is_terminal_char(c) {
self.found_terminal_char = true;
break;
} else {
break;
}
}
}
fn is_list_sep(c: Option<char>) -> bool {
if let Some(c) = c {
c.is_ascii_whitespace() || c == ','
} else {
true
}
}
fn is_terminal_char(c: Option<char>) -> bool {
c.is_some_and(|c| c == '/')
}
}
impl<'de, 'a, F: AsRef<str>> de::Deserializer<'de> for &'a mut Deserializer<'de, F> {
type Error = DError;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de> {
match self.peek_fmt() {
None => Err(DError::FormatSpecTooShort),
Some(FortField::Char { width: _ }) => self.deserialize_str(visitor),
Some(FortField::Integer { width: _, zeros: _, base: _ }) => self.deserialize_i64(visitor),
Some(FortField::Logical { width: _ }) => self.deserialize_bool(visitor),
Some(FortField::Real { width: _, precision: _, fmt: _, scale: _ }) => self.deserialize_f64(visitor),
Some(FortField::Any) => {
self.next_fmt()?;
let s = self.next_list_directed_substring(false)?;
let c1 = s.chars().next().unwrap_or(' ');
if c1.is_ascii_digit() || c1 == '+' || c1 == '-' {
if let Ok(v) = parsing::parse_integer(s) {
return visitor.visit_i64(v);
}
if let Ok(v) = parsing::parse_any_real(s) {
return visitor.visit_f64(v);
}
}
if let Ok(v) = parsing::parse_logical(s) {
return visitor.visit_bool(v);
}
return visitor.visit_str(s);
},
Some(FortField::Skip) => panic!("Got a skip format during peak")
}
}
fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de> {
let next_fmt = *self.next_fmt()?;
if let FortField::Logical { width } = next_fmt {
let substr = self.next_n_bytes(width)?;
let b = parsing::parse_logical(substr)?;
visitor.visit_bool(b)
} else if let FortField::Any = next_fmt {
let substr = self.next_list_directed_substring(false)?;
let b = parsing::parse_logical(substr)?;
visitor.visit_bool(b)
} else {
Err(DError::FormatTypeMismatch { spec_type: next_fmt, serde_type: "bool", field_name: self.try_prev_field().map(|f| f.to_string()) })
}
}
fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de> {
self.deserialize_i64(visitor)
.map_err(|e| e.with_serde_type("i8"))
}
fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de> {
self.deserialize_i64(visitor)
.map_err(|e| e.with_serde_type("i16"))
}
fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de> {
self.deserialize_i64(visitor)
.map_err(|e| e.with_serde_type("i32"))
}
fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de> {
let next_fmt = *self.next_fmt()?;
if let FortField::Integer { width, zeros: _, base } = next_fmt {
let substr = self.next_n_bytes(width)?;
let v = match base {
crate::format_specs::IntBase::Decimal => parsing::parse_integer(substr)?,
crate::format_specs::IntBase::Octal => todo!(),
crate::format_specs::IntBase::Hexadecimal => todo!(),
};
visitor.visit_i64(v)
} else if let FortField::Any = next_fmt {
let substr = self.next_list_directed_substring(false)?;
let v = parsing::parse_integer(substr)?;
visitor.visit_i64(v)
} else {
Err(DError::FormatTypeMismatch { spec_type: next_fmt, serde_type: "i64", field_name: self.try_prev_field().map(|f| f.to_string()) })
}
}
fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de> {
self.deserialize_u64(visitor)
.map_err(|e| e.with_serde_type("u8"))
}
fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de> {
self.deserialize_u64(visitor)
.map_err(|e| e.with_serde_type("u16"))
}
fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de> {
self.deserialize_u64(visitor)
.map_err(|e| e.with_serde_type("u32"))
}
fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de> {
let next_fmt = *self.next_fmt()?;
if let FortField::Integer { width, zeros: _, base } = next_fmt {
let substr = self.next_n_bytes(width)?;
let v = match base {
crate::format_specs::IntBase::Decimal => parsing::parse_unsigned_integer(substr)?,
crate::format_specs::IntBase::Octal => todo!(),
crate::format_specs::IntBase::Hexadecimal => todo!(),
};
visitor.visit_u64(v)
} else if let FortField::Any = next_fmt {
let substr = self.next_list_directed_substring(false)?;
let v = parsing::parse_unsigned_integer(substr)?;
visitor.visit_u64(v)
} else {
Err(DError::FormatTypeMismatch { spec_type: next_fmt, serde_type: "u64", field_name: self.try_prev_field().map(|f| f.to_string()) })
}
}
fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de> {
self.deserialize_f64(visitor)
.map_err(|e| e.with_serde_type("f32"))
}
fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de> {
let next_fmt = *self.next_fmt()?;
if let FortField::Real { width, precision: _, fmt, scale } = next_fmt {
let substr = self.next_n_bytes(width)?;
let substr = substr.trim(); let res = if fmt.is_d() {
let valstr = substr.replace("d", "e").replace("D", "E");
valstr.parse::<f64>()
} else {
substr.parse::<f64>()
};
let v = res.map_err(|e| FError::ParsingError { s: substr.to_string(), t: "real", reason: format!("Invalid real number format ({e})") })?;
let v = if fmt.is_f() && scale != 0 {
v * 10.0_f64.powi(-scale)
} else {
v
};
visitor.visit_f64(v)
} else if let FortField::Any = next_fmt {
let substr = self.next_list_directed_substring(false)?.trim();
let v = parsing::parse_any_real(substr)?;
visitor.visit_f64(v)
} else {
Err(DError::FormatTypeMismatch { spec_type: next_fmt, serde_type: "f64", field_name: self.try_prev_field().map(|f| f.to_string()) })
}
}
fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de> {
let next_fmt = *self.next_fmt()?;
match next_fmt {
FortField::Char { width: None } | FortField::Char { width: Some(1) } => {
let c = self.next_n_bytes(1)?
.chars()
.next()
.unwrap(); visitor.visit_char(c)
},
FortField::Char { width: _ } => {
Err(DError::FormatTypeMismatch { spec_type: next_fmt, serde_type: "char (requires 'a' or 'a1' Fortran format)", field_name: self.try_prev_field().map(|f| f.to_string()) })
},
FortField::Any => {
let s: Vec<char> = self.next_list_directed_substring(false)?
.chars()
.collect();
if s.len() != 1 {
Err(DError::FormatTypeMismatch {
spec_type: next_fmt,
serde_type: "char (list-directed parsing provided a substring with 0 or >1 characters)",
field_name: self.try_prev_field().map(|f| f.to_string())
})
} else {
visitor.visit_char(s[0])
}
}
_ => {
Err(DError::FormatTypeMismatch { spec_type: next_fmt, serde_type: "char", field_name: self.try_prev_field().map(|f| f.to_string()) })
}
}
}
fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de> {
let next_fmt = *self.next_fmt()?;
if let FortField::Char { width } = next_fmt {
let s = self.next_n_bytes(width.unwrap_or(1))?;
if self.settings.trim_strings {
visitor.visit_borrowed_str(s.trim())
} else {
visitor.visit_borrowed_str(s)
}
} else if let FortField::Any = next_fmt {
let s = self.next_list_directed_substring(false)?;
if self.settings.trim_strings {
visitor.visit_borrowed_str(s.trim())
} else {
visitor.visit_borrowed_str(s)
}
} else {
Err(DError::FormatTypeMismatch { spec_type: next_fmt, serde_type: "&str", field_name: self.try_prev_field().map(|f| f.to_string()) })
}
}
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de> {
self.deserialize_str(visitor)
}
fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de> {
todo!()
}
fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de> {
todo!()
}
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de> {
self.advance_over_skips();
let next_fmt = self.peek_fmt().map(|f| *f);
let visit_some = match next_fmt {
Some(FortField::Any) => {
self.skip_list_separators();
!self.found_terminal_char && self.has_n_bytes_remaining(1)
},
Some(FortField::Char { width }) => self.has_n_bytes_remaining(width.unwrap_or(1)),
Some(FortField::Integer { width, zeros: _, base: _ }) => self.has_n_bytes_remaining(width),
Some(FortField::Logical { width }) => self.has_n_bytes_remaining(width),
Some(FortField::Real { width, precision: _, fmt: _, scale: _ }) => self.has_n_bytes_remaining(width),
Some(FortField::Skip) => panic!("Any skip format specifiers should have been skipped over"),
None => false,
};
if visit_some {
visitor.visit_some(self)
} else {
visitor.visit_none()
}
}
fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de> {
todo!()
}
fn deserialize_unit_struct<V>(
self,
name: &'static str,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de> {
todo!()
}
fn deserialize_newtype_struct<V>(
self,
name: &'static str,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de> {
todo!()
}
fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de> {
visitor.visit_seq(UnknownLenSeq::new(self, None))
}
fn deserialize_tuple<V>(self, len: usize, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de> {
visitor.visit_seq(KnownLenSeq::new(self, len))
}
fn deserialize_tuple_struct<V>(
self,
name: &'static str,
len: usize,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de> {
todo!()
}
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de> {
if self.fields.is_some() {
let map_accessor = FieldSequence::new(self);
visitor.visit_map(map_accessor)
} else {
todo!()
}
}
fn deserialize_struct<V>(
self,
_name: &'static str,
fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de> {
if self.fields.is_some() {
let map_accessor = FieldSequence::new(self);
visitor.visit_map(map_accessor)
} else {
visitor.visit_seq(KnownLenSeq::new(self, fields.len()))
}
}
fn deserialize_enum<V>(
self,
name: &'static str,
variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de> {
todo!()
}
fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de> {
if let Some(fields) = self.fields {
let this_field = fields.get(self.field_idx)
.map(|f| f)
.ok_or_else(|| DError::FieldListTooShort)?;
visitor.visit_borrowed_str(this_field.as_ref())
} else {
self.deserialize_str(visitor)
}
}
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de> {
self.deserialize_any(visitor)
}
}
struct KnownLenSeq<'a, 'de: 'a, F: AsRef<str>> {
de: &'a mut Deserializer<'de, F>,
n: usize,
i: usize,
}
impl<'a, 'de, F: AsRef<str>> KnownLenSeq<'a, 'de, F> {
fn new(de: &'a mut Deserializer<'de, F>, n: usize) -> Self {
Self { de, n, i: 0 }
}
}
impl<'de, 'a, F: AsRef<str>> SeqAccess<'de> for KnownLenSeq<'a, 'de, F> {
type Error = DError;
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
where
T: de::DeserializeSeed<'de> {
if self.i == self.n {
Ok(None)
} else {
self.i += 1;
seed.deserialize(&mut *self.de).map(Some)
}
}
}
struct UnknownLenSeq<'a, 'de: 'a, F: AsRef<str>> {
de: &'a mut Deserializer<'de, F>,
n: usize,
max_n: Option<usize>
}
impl<'a, 'de, F: AsRef<str>> UnknownLenSeq<'a, 'de, F> {
fn new(de: &'a mut Deserializer<'de, F>, max_n: Option<usize>) -> Self {
Self { de, n: 0, max_n }
}
}
impl<'de, 'a, F: AsRef<str>> SeqAccess<'de> for UnknownLenSeq<'a, 'de, F> {
type Error = DError;
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
where
T: de::DeserializeSeed<'de> {
if let Some(m) = self.max_n {
if m == self.n {
return Ok(None)
}
}
match seed.deserialize(&mut *self.de) {
Ok(el) => Ok(Some(el)),
Err(DError::FormatTypeMismatch { spec_type: _, serde_type: _, field_name: _ }) => {
self.de.rewind_fmt();
Ok(None)
}, Err(DError::FormatSpecTooShort) => Ok(None), Err(DError::InputEndedEarly) => Ok(None), Err(e) => Err(e) }
}
}
struct FieldSequence<'a, 'de: 'a, F: AsRef<str>> {
de: &'a mut Deserializer<'de, F>,
}
impl<'a, 'de, F: AsRef<str>> FieldSequence<'a, 'de, F> {
fn new(de: &'a mut Deserializer<'de, F>) -> Self {
Self { de }
}
}
impl<'a, 'de, F: AsRef<str>> MapAccess<'de> for FieldSequence<'a, 'de, F> {
type Error = DError;
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
where
K: de::DeserializeSeed<'de> {
if self.de.curr_field().is_none() {
return Ok(None)
}
seed.deserialize(&mut *self.de).map(Some)
}
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
where
V: de::DeserializeSeed<'de> {
seed.deserialize(&mut *self.de)
}
}
pub(crate) struct FortValueVisitor;
impl<'de> Visitor<'de> for FortValueVisitor {
type Value = FortValue;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("any valid scalar Fortran value")
}
fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(FortValue::Logical(v))
}
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(FortValue::Integer(v))
}
fn visit_u8<E>(self, v: u8) -> Result<Self::Value, E>
where
E: de::Error,
{
self.visit_i64(v.into())
}
fn visit_u16<E>(self, v: u16) -> Result<Self::Value, E>
where
E: de::Error,
{
self.visit_i64(v.into())
}
fn visit_u32<E>(self, v: u32) -> Result<Self::Value, E>
where
E: de::Error,
{
self.visit_i64(v.into())
}
fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(FortValue::Real(v))
}
fn visit_char<E>(self, v: char) -> Result<Self::Value, E>
where
E: de::Error,
{
self.visit_str(v.encode_utf8(&mut [0u8; 4]))
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(FortValue::Char(v.to_string()))
}
fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
where
E: de::Error,
{
self.visit_str(v)
}
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(FortValue::Char(v))
}
}
#[cfg(test)]
mod tests {
use serde::Deserialize;
use super::*;
#[test]
fn test_de_bool() -> DResult<()> {
let ff = FortFormat::parse("(l1)")?;
let b: bool = from_str("T", &ff)?;
assert_eq!(b, true);
Ok(())
}
#[test]
fn test_de_integer() -> DResult<()> {
let ff = FortFormat::parse("(i2)")?;
let i: i8 = from_str(" 8", &ff)?;
assert_eq!(i, 8);
let i: i8 = from_str("-1", &ff)?;
assert_eq!(i, -1);
let i: i8 = from_str("-22", &ff)?;
assert_eq!(i, -2);
let i: i64 = from_str("42", &ff)?;
assert_eq!(i, 42);
let i: i64 = from_str("-7", &ff)?;
assert_eq!(i, -7);
let u: u8 = from_str(" 3", &ff)?;
assert_eq!(u, 3);
let u: u64 = from_str("26", &ff)?;
assert_eq!(u, 26);
let u: u8 = from_str("200", &ff)?;
assert_eq!(u, 20);
Ok(())
}
#[test]
fn test_de_float() -> DResult<()> {
let ff = FortFormat::parse("(f8)")?;
let r: f64 = from_str("12.45678", &ff)?;
assert_eq!(r, 12.45678);
let r: f64 = from_str("-23.5678", &ff)?;
assert_eq!(r, -23.5678);
let ff = FortFormat::parse("(e8)")?;
let r: f64 = from_str("1.34E+03", &ff)?;
assert_eq!(r, 1.34e3);
let r: f64 = from_str("1.34e+03", &ff)?;
assert_eq!(r, 1.34e3);
let r: f64 = from_str("1.34E-03", &ff)?;
assert_eq!(r, 1.34e-3);
let r: f64 = from_str("1.34e-03", &ff)?;
assert_eq!(r, 1.34e-3);
let ff = FortFormat::parse("(d8)")?;
let r: f64 = from_str("1.34D+03", &ff)?;
assert_eq!(r, 1.34e3);
let r: f64 = from_str("1.34d+03", &ff)?;
assert_eq!(r, 1.34e3);
let r: f64 = from_str("1.34D-03", &ff)?;
assert_eq!(r, 1.34e-3);
let r: f64 = from_str("1.34d-03", &ff)?;
assert_eq!(r, 1.34e-3);
let ff = FortFormat::parse("(2pe13.5)")?;
let r: f64 = from_str(" 90.0000E-02", &ff)?;
assert_eq!(r, 0.9, "(2pe13.5)");
let ff = FortFormat::parse("(-2pe13.5)")?;
let r: f64 = from_str(" 0.00900E+02", &ff)?;
assert_eq!(r, 0.9, "(-2pe13.5)");
let ff = FortFormat::parse("(2pf13.5)")?;
let r: f64 = from_str(" 90.00000", &ff)?;
assert_eq!(r, 0.9, "(2pf13.5)");
let ff = FortFormat::parse("(-2pf13.5)")?;
let r: f64 = from_str(" 0.00800", &ff)?;
assert_eq!(r, 0.8, "(-2pf13.5)");
Ok(())
}
#[test]
fn test_de_string() -> DResult<()> {
let ff = FortFormat::parse("(a16)")?;
let s: String = from_str("Hello world! ", &ff)?;
assert_eq!(s, "Hello world!");
let settings = DeSettings::default().do_trim(false);
let s: String = from_str_custom("Hello world! ", &ff, settings)?;
assert_eq!(s, "Hello world! ");
Ok(())
}
#[test]
fn test_de_tuple() -> DResult<()> {
let ff = FortFormat::parse("(a1,1x,i2,1x,i4)")?;
let t: (char, i32, i32) = from_str("a 16 9876", &ff)?;
assert_eq!(t, ('a', 16, 9876));
Ok(())
}
#[test]
fn test_de_vec() -> DResult<()> {
let ff = FortFormat::parse("5(i3,1x)")?;
let v: Vec<i32> = from_str("123 456 789 246 369", &ff)?;
assert_eq!(&v, &[123, 456, 789, 246, 369]);
Ok(())
}
#[test]
fn test_de_vec_in_tuple() -> DResult<()> {
let ff = FortFormat::parse("(a5,1x,3i3,a5)")?;
let t: (String, Vec<i32>, String) = from_str("Hello 12 34 56 World", &ff)?;
assert_eq!(t, ("Hello".to_owned(), vec![12, 34, 56], "World".to_owned()));
Ok(())
}
#[test]
fn test_de_struct() -> DResult<()> {
#[derive(Debug, PartialEq, Eq, Deserialize)]
struct Test {
x: i32,
y: i32,
c: char,
b: bool
}
let ff = FortFormat::parse("(2i3,1x,a,1x,l1)")?;
let s: Test = from_str(" 10 20 z F", &ff)?;
assert_eq!(s, Test { x: 10, y: 20, c: 'z', b: false });
Ok(())
}
#[test]
fn test_de_struct_with_array() -> DResult<()> {
#[derive(Debug, PartialEq, Eq, Deserialize)]
struct Test {
flag: bool,
data: [i32; 8]
}
let ff = FortFormat::parse("(l1,1x,8i3)")?;
let s: Test = from_str("T 10 20 30 40 50 60 70 80", &ff)?;
assert_eq!(s, Test{ flag: true, data: [10, 20, 30, 40, 50, 60, 70, 80] });
Ok(())
}
#[test]
fn test_de_struct_with_fields() -> DResult<()> {
#[derive(Debug, PartialEq, Deserialize)]
struct Test {
alpha: i32,
beta: f64,
gamma: String,
}
let ff = FortFormat::parse("(a8,1x,i4,1x,f5.3)")?;
let fields = ["gamma", "alpha", "beta"];
let s: Test = from_str_with_fields(
"abcdefgh 1234 9.876",
&ff,
&fields
)?;
assert_eq!(s, Test{ alpha: 1234, beta: 9.876, gamma: "abcdefgh".to_string() });
Ok(())
}
#[test]
fn test_de_struct_with_inner_struct() -> DResult<()> {
#[derive(Debug, PartialEq, Deserialize)]
struct Inner {
x: i32,
y: i32,
}
#[derive(Debug, PartialEq, Deserialize)]
struct Outer {
sid: String,
#[serde(flatten)]
coords: Inner,
flag: i8,
}
let ff = FortFormat::parse("(a2,1x,i1,1x,i3,1x,i3)")?;
let fields = ["sid", "flag", "y", "x"];
let s: Outer = from_str_with_fields(
"pa 0 456 123",
&ff,
&fields
)?;
assert_eq!(s, Outer{ sid: "pa".to_string(), flag: 0, coords: Inner { x: 123, y: 456 } });
Ok(())
}
#[test]
fn test_de_inner_struct_not_flattened() -> DResult<()> {
#[derive(Debug, PartialEq, Deserialize)]
struct Inner {
x: i32,
y: i32,
}
#[derive(Debug, PartialEq, Deserialize)]
struct Outer {
sid: String,
coords: Inner,
flag: i8,
}
let ff = FortFormat::parse("(a2,1x,i1,1x,i3,1x,i3)")?;
let fields = ["sid", "flag", "y", "x"];
let s: DResult<Outer> = from_str_with_fields(
"pa 0 456 123",
&ff,
&fields
);
assert!(s.is_err());
Ok(())
}
#[test]
fn test_extra_fields_map() -> DResult<()> {
#[derive(Debug, PartialEq, Deserialize)]
struct Test {
name: String,
flag: i8,
#[serde(flatten)]
gases: std::collections::HashMap<String, f32>
}
let ff = FortFormat::parse("(a5,1x,i1,1x,f6.2,1x,f6.1,1x,f6.2)")?;
let fields = ["name", "flag", "co2", "ch4", "n2o"];
let data = "spec1 0 432.10 1800.0 98.76";
let s: Test = from_str_with_fields(data, &ff, &fields)?;
let gases = std::collections::HashMap::from([
("co2".to_string(), 432.10),
("ch4".to_string(), 1800.0),
("n2o".to_string(), 98.76)
]);
let expected = Test { name: "spec1".to_string(), flag: 0, gases };
assert_eq!(s, expected);
Ok(())
}
#[test]
fn test_middle_opt_field() -> DResult<()> {
#[derive(Debug, PartialEq, Deserialize)]
struct Test {
a: i32,
b: Option<i32>,
c: i32
}
let ff = FortFormat::parse("(i2,i2)")?;
let fields = ["a", "c"];
let data = " 1 2";
let s: Test = from_str_with_fields(&data, &ff, &fields)?;
let expected = Test { a: 1, b: None, c: 2 };
assert_eq!(s, expected, "Deserializing struct with missing optional field failed with fixed format");
let s: Test = from_str_with_fields(&data, &FortFormat::ListDirected, &fields)?;
assert_eq!(s, expected, "Deserializing struct with missing optional field failed with list-directed format");
Ok(())
}
#[test]
fn test_middle_opt_field_missing_by_name() -> DResult<()> {
#[derive(Debug, PartialEq, Deserialize)]
struct Test {
a: i32,
b: Option<i32>,
c: i32
}
let ff = FortFormat::parse("(i2,1x,a4,1x,i2)")?;
let fields = ["a", "skip", "c"];
let data = "10 abcd 20";
let s: Test = from_str_with_fields(&data, &ff, &fields)?;
let expected = Test { a: 10, b: None, c: 20 };
assert_eq!(s, expected, "Deserializing struct with missing optional field failed with fixed format");
let s: Test = from_str_with_fields(&data, &FortFormat::ListDirected, &fields)?;
assert_eq!(s, expected, "Deserializing struct with missing optional field failed with list-directed format");
Ok(())
}
#[test]
fn test_de_scalar_fort_value() -> DResult<()> {
let v: FortValue = from_str("T", &FortFormat::parse("(l1)")?)?;
assert_eq!(v, FortValue::Logical(true));
let v: FortValue = from_str("123", &FortFormat::parse("(i3)")?)?;
assert_eq!(v, FortValue::Integer(123));
let v: FortValue = from_str("-456", &FortFormat::parse("(i4)")?)?;
assert_eq!(v, FortValue::Integer(-456));
let v: FortValue = from_str("9.5", &FortFormat::parse("(f3.1)")?)?;
assert_eq!(v, FortValue::Real(9.5));
let v: FortValue = from_str("abcde", &FortFormat::parse("(a5)")?)?;
assert_eq!(v, FortValue::Char("abcde".to_string()));
Ok(())
}
#[test]
fn test_de_vector_fort_values() -> DResult<()> {
let ff = FortFormat::parse("(l1,1x,i3,1x,i4,1x,f4.1,1x,a5)")?;
let v: Vec<FortValue> = from_str("F 987 -123 -1.5 ZYXWV", &ff)?;
let expected = vec![
FortValue::Logical(false),
FortValue::Integer(987),
FortValue::Integer(-123),
FortValue::Real(-1.5),
FortValue::Char("ZYXWV".to_string())
];
assert_eq!(v, expected);
Ok(())
}
#[test]
fn test_list_de_int() -> DResult<()> {
let ff = FortFormat::ListDirected;
let vspace: (i32, i32, i32) = from_str("1 2 34", &ff)?;
assert_eq!(vspace, (1, 2, 34));
let vcomma: (i32, i32, i32) = from_str("4, 56 , 7", &ff)?;
assert_eq!(vcomma, (4, 56, 7));
Ok(())
}
#[test]
fn test_list_de_vector_int() -> DResult<()> {
let ff = FortFormat::ListDirected;
let vspace: Vec<i32> = from_str("1 2 34", &ff)?;
assert_eq!(vspace, vec![1, 2, 34]);
let vcomma: Vec<i32> = from_str("4, 56 , 7", &ff)?;
assert_eq!(vcomma, vec![4, 56, 7]);
Ok(())
}
#[test]
fn test_list_de_str() -> DResult<()> {
let ff = FortFormat::ListDirected;
let vspace: (&str, &str) = from_str(r#"hello "my beautiful" world"#, &ff)?;
assert_eq!(vspace, ("hello", "my beautiful"));
let vcomma: (&str, &str, &str) = from_str("goodbye 'my frigid' world ", &ff)?;
assert_eq!(vcomma, ("goodbye", "my frigid", "world"));
let v_first_quote: &str = from_str("'who else' 1 2 3", &ff)?;
assert_eq!(v_first_quote, "who else");
let v_last_quote: (&str, &str) = from_str("and 'last but not least'", &ff)?;
assert_eq!(v_last_quote.1, "last but not least");
Ok(())
}
#[test]
fn test_list_de_structs() -> DResult<()> {
let ff = FortFormat::ListDirected;
#[derive(Debug, Deserialize, PartialEq)]
struct InsituCorr<'a> {
#[serde(rename="Gas")]
gas: &'a str,
#[serde(rename="AICF")]
aicf: f64,
#[serde(rename="AICF_Err")]
aicf_err: f64,
#[serde(rename="WMO_Scale")]
wmo_scale: &'a str
}
let s1de: InsituCorr = from_str_with_fields(
r#""xco2" 1.0101 0.0005 "WMO CO2 X2007""#,
&ff,
&["Gas", "AICF", "AICF_Err", "WMO_Scale"]
)?;
let s1true = InsituCorr {
gas: "xco2",
aicf: 1.0101,
aicf_err: 0.0005,
wmo_scale: "WMO CO2 X2007",
};
assert_eq!(s1de, s1true, "Deserialized InsituCorr test structure produced different values than expected.");
#[derive(Debug, Deserialize, PartialEq)]
struct AirmassCorr<'a> {
#[serde(rename="Gas")]
gas: &'a str,
#[serde(rename="ADCF")]
adcf: f64,
#[serde(rename="ADCF_Err")]
adcf_err: f64,
g: Option<f64>,
p: Option<f64>
}
let s2de: AirmassCorr = from_str_with_fields(
r#""xco2_6220" -0.00903 0.00025 15 4"#,
&ff,
&["Gas", "ADCF", "ADCF_Err", "g", "p"]
)?;
let s2true = AirmassCorr{
gas: "xco2_6220",
adcf: -0.00903,
adcf_err: 0.00025,
g: Some(15.0),
p: Some(4.0)
};
assert_eq!(s2de, s2true, "Deserializing AirmassCorr with the g and p values produced different values than expected.");
let s3de: AirmassCorr = from_str_with_fields(
r#""xco2" -0.0068 0.0050 "#,
&ff,
&["Gas", "ADCF", "ADCF_Err"]
)?;
let s3true = AirmassCorr{
gas: "xco2",
adcf: -0.0068,
adcf_err: 0.005,
g: None,
p: None
};
assert_eq!(s3de, s3true, "Deserialized AirmassCorr without the g and p value produced different values than expected.");
Ok(())
}
}