use std::{
fmt::{Octal, UpperHex},
io::Write,
string::FromUtf8Error,
sync::Arc,
};
use crate::{
de::FortFormat,
format_specs::{FortField, IntBase, RealFmt},
serde_common::{NoneFill, SError, SResult},
};
use ryu_floating_decimal::d2d;
use serde::ser;
static DEFAULT_SER_SETTINGS: SerSettings = SerSettings {
fill_method: NoneFill::default_inner(),
newline: b"\n",
align_left_str: false,
};
pub fn to_string<T>(value: T, fmt: &FortFormat) -> SResult<String>
where
T: ser::Serialize,
{
let mut serializer = Serializer::<_, &str>::new(fmt);
value.serialize(&mut serializer)?;
Ok(serializer.try_into_string()?)
}
pub fn to_string_with_fields<T, F>(value: T, fmt: &FortFormat, fields: &[F]) -> SResult<String>
where
T: ser::Serialize,
F: AsRef<str>,
{
let mut serializer = Serializer::new_with_fields(fmt, fields);
value.serialize(&mut serializer)?;
Ok(serializer.try_into_string()?)
}
pub fn to_string_custom<T, F>(
value: T,
fmt: &FortFormat,
fields: Option<&[F]>,
settings: &SerSettings,
) -> SResult<String>
where
T: ser::Serialize,
F: AsRef<str>,
{
let mut serializer = Serializer::new_custom(fmt, fields, settings);
value.serialize(&mut serializer)?;
Ok(serializer.try_into_string()?)
}
pub fn to_bytes<T>(value: T, fmt: &FortFormat) -> SResult<Vec<u8>>
where
T: ser::Serialize,
{
let mut serializer = Serializer::<_, &str>::new(fmt);
value.serialize(&mut serializer)?;
Ok(serializer.into_bytes())
}
pub fn to_bytes_with_fields<T, F: AsRef<str>>(
value: T,
fmt: &FortFormat,
fields: &[F],
) -> SResult<Vec<u8>>
where
T: ser::Serialize,
{
let mut serializer = Serializer::new_with_fields(fmt, fields);
value.serialize(&mut serializer)?;
Ok(serializer.into_bytes())
}
pub fn to_bytes_custom<T, F: AsRef<str>>(
value: T,
fmt: &FortFormat,
fields: Option<&[F]>,
settings: &SerSettings,
) -> SResult<Vec<u8>>
where
T: ser::Serialize,
{
let mut serializer = Serializer::new_custom(fmt, fields, settings);
value.serialize(&mut serializer)?;
Ok(serializer.into_bytes())
}
pub fn to_writer<T, W>(value: T, fmt: &FortFormat, writer: W) -> SResult<()>
where
T: ser::Serialize,
W: Write,
{
let mut serializer = Serializer::<_, &str>::new_writer(fmt, writer);
value.serialize(&mut serializer)?;
serializer.end_record()?;
Ok(())
}
pub fn to_writer_with_fields<T, W, F: AsRef<str>>(
value: T,
fmt: &FortFormat,
fields: &[F],
writer: W,
) -> SResult<()>
where
T: ser::Serialize,
W: Write,
{
let mut serializer = Serializer::new_writer_with_fields(fmt, fields, writer);
value.serialize(&mut serializer)?;
serializer.end_record()?;
Ok(())
}
pub fn to_writer_custom<T, W, F: AsRef<str>>(
value: T,
fmt: &FortFormat,
fields: Option<&[F]>,
settings: &SerSettings,
writer: W,
) -> SResult<()>
where
T: ser::Serialize,
W: Write,
{
let mut serializer = Serializer::new_writer_custom(fmt, fields, settings, writer);
value.serialize(&mut serializer)?;
serializer.end_record()?;
Ok(())
}
pub fn many_to_writer_custom<T, W, F>(
values: &[T],
fmt: &FortFormat,
fields: Option<&[F]>,
settings: &SerSettings,
writer: W,
) -> SResult<()>
where
T: ser::Serialize,
W: Write,
F: AsRef<str>,
{
let mut serializer = Serializer::new_writer_custom(fmt, fields, settings, writer);
for val in values.iter() {
val.serialize(&mut serializer)?;
serializer.end_record()?;
}
Ok(())
}
#[derive(Debug, Clone)]
pub struct SerSettings {
fill_method: NoneFill,
newline: &'static [u8],
align_left_str: bool,
}
impl Default for SerSettings {
fn default() -> Self {
DEFAULT_SER_SETTINGS.clone()
}
}
impl SerSettings {
pub fn fill_method(mut self, fill_method: NoneFill) -> Self {
self.fill_method = fill_method;
self
}
pub fn newline(mut self, newline: &'static [u8]) -> Self {
self.newline = newline;
self
}
pub fn align_left_str(mut self, align_left: bool) -> Self {
self.align_left_str = align_left;
self
}
}
#[derive(Debug, Default)]
struct MapSerHelper {
next_field_index: Option<usize>,
next_field_fmt: Option<FortField>,
data: Vec<Option<Vec<u8>>>,
in_use: bool,
}
impl MapSerHelper {
fn take_validate_data(&mut self) -> Vec<Option<Vec<u8>>> {
let data = std::mem::take(&mut self.data);
self.next_field_fmt = None;
self.next_field_index = None;
self.in_use = false;
data
}
}
struct Serializer<'f, W: Write, F: AsRef<str>> {
buf: W,
fmt: &'f FortFormat,
fmt_idx: usize,
fields: Option<&'f [F]>,
field_idx: usize,
map_helper: MapSerHelper,
settings: &'f SerSettings,
}
impl<'f, F: AsRef<str>> Serializer<'f, Vec<u8>, F> {
pub fn new(fmt: &'f FortFormat) -> Self {
Self {
buf: vec![],
fmt,
fmt_idx: 0,
fields: None,
field_idx: 0,
map_helper: MapSerHelper::default(),
settings: &DEFAULT_SER_SETTINGS,
}
}
pub fn new_with_fields(fmt: &'f FortFormat, fields: &'f [F]) -> Self {
Self {
buf: vec![],
fmt,
fmt_idx: 0,
fields: Some(fields),
field_idx: 0,
map_helper: MapSerHelper::default(),
settings: &DEFAULT_SER_SETTINGS,
}
}
pub fn new_custom(
fmt: &'f FortFormat,
fields: Option<&'f [F]>,
settings: &'f SerSettings,
) -> Self {
Self {
buf: vec![],
fmt,
fmt_idx: 0,
fields,
field_idx: 0,
map_helper: MapSerHelper::default(),
settings,
}
}
pub fn into_bytes(self) -> Vec<u8> {
self.buf.to_vec()
}
pub fn try_into_string(self) -> Result<String, FromUtf8Error> {
String::from_utf8(self.buf)
}
}
impl<'f, W: Write, F: AsRef<str>> Serializer<'f, W, F> {
pub fn new_writer(fmt: &'f FortFormat, writer: W) -> Self {
Self {
buf: writer,
fmt,
fmt_idx: 0,
fields: None,
field_idx: 0,
map_helper: MapSerHelper::default(),
settings: &DEFAULT_SER_SETTINGS,
}
}
pub fn new_writer_with_fields(fmt: &'f FortFormat, fields: &'f [F], writer: W) -> Self {
Self {
buf: writer,
fmt,
fmt_idx: 0,
fields: Some(fields),
field_idx: 0,
map_helper: MapSerHelper::default(),
settings: &DEFAULT_SER_SETTINGS,
}
}
pub fn new_writer_custom(
fmt: &'f FortFormat,
fields: Option<&'f [F]>,
settings: &'f SerSettings,
writer: W,
) -> Self {
Self {
buf: writer,
fmt,
fmt_idx: 0,
fields: fields,
field_idx: 0,
map_helper: MapSerHelper::default(),
settings,
}
}
}
impl<'f, W: Write + 'f, F: AsRef<str>> Serializer<'f, W, F> {
fn advance_over_skips(&mut self) -> std::io::Result<()> {
loop {
let peeked_fmt = self.fmt.get_field(self.fmt_idx);
match peeked_fmt {
Some(&FortField::Skip) => {
self.buf.write(b" ")?;
self.fmt_idx += 1;
}
_ => return Ok(()),
}
}
}
fn next_fmt(&mut self) -> SResult<&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(SError::FormatSpecTooShort),
}
}
}
fn curr_field(&mut 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())
}
fn peek_fmt(&mut self) -> Option<&FortField> {
let mut i = self.fmt_idx;
loop {
let fmt = self.fmt.get_field(i)?;
if !fmt.is_positional() {
return Some(fmt);
}
i += 1;
}
}
fn get_nth_nonskip_fmt(&self, n: usize) -> Option<&FortField> {
let mut i = 0;
let mut j = 0;
loop {
let fmt = self.fmt.get_field(j)?;
if !fmt.is_positional() && i == n {
return Some(fmt);
} else if !fmt.is_positional() {
i += 1;
}
j += 1;
}
}
fn get_fmt_and_index_offset_for_field(&self, field_name: &str) -> Option<(usize, FortField)> {
if let Some(fields) = self.fields {
let mut i = 0;
for fname in &fields[self.field_idx..] {
if field_name == fname.as_ref() {
let fmt = self.get_nth_nonskip_fmt(self.field_idx + i)?;
return Some((i, *fmt));
}
i += 1;
}
None
} else {
panic!("Called get_fmt_and_index_offset_for_field on a serializer without field names");
}
}
fn write_next_entry_raw(&mut self, bytes: &[u8], fmt: Option<FortField>) -> SResult<()> {
let fmt = if let Some(fmt) = fmt {
fmt
} else {
self.advance_over_skips()?;
*self.next_fmt()?
};
let nbytes = match fmt {
FortField::Char { width } => width,
FortField::Logical { width } => Some(width),
FortField::Integer {
width,
zeros: _,
base: _,
} => Some(width),
FortField::Real {
width,
precision: _,
fmt: _,
scale: _,
} => Some(width),
FortField::Any => Some(bytes.len() as u32),
FortField::Skip => {
panic!("Should not get a skip format, should have advanced over all skips")
}
};
if let Some(n) = nbytes {
if n != bytes.len() as u32 {
panic!("Called write_next_entry_raw with a slice of {} bytes, expected a slice of {} bytes", bytes.len(), n);
}
}
self.buf.write(bytes)?;
if let FortField::Any = fmt {
self.buf.write(b" ")?;
}
Ok(())
}
fn serialize_integer<I: itoa::Integer + Octal + UpperHex>(
&mut self,
abs_value: I,
is_neg: bool,
) -> SResult<()> {
let next_fmt = *self.next_fmt()?;
if let FortField::Integer { width, zeros, base } = next_fmt {
serialize_integer(width, zeros, base, &mut self.buf, abs_value, is_neg)
} else {
Err(SError::FormatTypeMismatch {
spec_type: next_fmt,
serde_type: "integer",
field_name: self.try_prev_field().map(|f| f.to_string()),
})
}
}
fn serialize_real(&mut self, v: f64) -> SResult<()> {
let next_fmt = *self.next_fmt()?;
if let FortField::Real {
width,
precision,
fmt,
scale,
} = next_fmt
{
let precision = precision.ok_or_else(|| {
SError::InvalidOutputFmt(
next_fmt,
"real number formats must include a precision for output".to_string(),
)
})?;
match fmt {
RealFmt::D => {
serialize_real_exp(&mut self.buf, v, width, precision, scale, "D", None)
}
RealFmt::E => {
serialize_real_exp(&mut self.buf, v, width, precision, scale, "E", None)
}
RealFmt::F => serialize_real_f(&mut self.buf, v, width, precision, scale),
RealFmt::G => todo!(),
}
} else {
Err(SError::FormatTypeMismatch {
spec_type: next_fmt,
serde_type: "float",
field_name: self.try_prev_field().map(|f| f.to_string()),
})
}
}
fn serialize_key_helper(&mut self, field: &str) -> SResult<()> {
if self.fields.is_some() {
let (offset, fmt) = self
.get_fmt_and_index_offset_for_field(field)
.ok_or_else(|| SError::FieldMissingError(field.to_string()))?;
self.map_helper.next_field_index = Some(offset);
self.map_helper.next_field_fmt = Some(fmt);
Ok(())
} else {
Ok(())
}
}
fn serialize_value_helper<T: ?Sized>(&mut self, value: &T) -> SResult<()>
where
T: serde::Serialize,
{
if self.fields.is_none() {
return value.serialize(&mut *self);
}
if let (Some(offset), Some(fmt)) = (
self.map_helper.next_field_index,
self.map_helper.next_field_fmt,
) {
while self.map_helper.data.len() <= offset {
self.map_helper.data.push(None);
}
let fortfmt = FortFormat::Fixed(vec![fmt]);
let bytes = to_bytes_custom::<_, &str>(value, &fortfmt, None, self.settings)?;
self.map_helper.data[offset] = Some(bytes);
} else {
panic!(
"serialize_key must be called before serialize_value when field names are given."
);
}
Ok(())
}
fn end_helper(&mut self) -> SResult<()> {
if self.map_helper.next_field_index.is_some() {
for maybe_bytes in self.map_helper.take_validate_data() {
if let Some(bytes) = maybe_bytes {
self.write_next_entry_raw(&bytes, None)?;
} else {
let field_name = self.curr_field().unwrap_or("?");
unimplemented!("The field {field_name} did not have a value, but a later field did. This is not handled yet.");
}
}
}
Ok(())
}
fn end_record(&mut self) -> SResult<()> {
self.buf.write(self.settings.newline)?;
self.fmt_idx = 0;
self.field_idx = 0;
Ok(())
}
}
impl<'a, 'f, W: Write + 'f, F: AsRef<str>> ser::Serializer for &'a mut Serializer<'f, W, F> {
type Ok = ();
type Error = SError;
type SerializeSeq = Self;
type SerializeTuple = Self;
type SerializeTupleStruct = Self;
type SerializeTupleVariant = Self;
type SerializeMap = Self;
type SerializeStruct = Self;
type SerializeStructVariant = Self;
fn serialize_bool(self, v: bool) -> Result<Self::Ok, Self::Error> {
let next_fmt = *self.next_fmt()?;
if let FortField::Logical { width } = next_fmt {
serialize_logical(v, width, &mut self.buf)
} else {
Err(SError::FormatTypeMismatch {
spec_type: next_fmt,
serde_type: "bool",
field_name: self.try_prev_field().map(|f| f.to_string()),
})
}
}
fn serialize_i8(self, v: i8) -> Result<Self::Ok, Self::Error> {
self.serialize_integer(v.abs(), v < 0)
}
fn serialize_i16(self, v: i16) -> Result<Self::Ok, Self::Error> {
self.serialize_integer(v.abs(), v < 0)
}
fn serialize_i32(self, v: i32) -> Result<Self::Ok, Self::Error> {
self.serialize_integer(v.abs(), v < 0)
}
fn serialize_i64(self, v: i64) -> Result<Self::Ok, Self::Error> {
self.serialize_integer(v.abs(), v < 0)
}
fn serialize_i128(self, v: i128) -> Result<Self::Ok, Self::Error> {
self.serialize_integer(v.abs(), v < 0)
}
fn serialize_u8(self, v: u8) -> Result<Self::Ok, Self::Error> {
self.serialize_integer(v, false)
}
fn serialize_u16(self, v: u16) -> Result<Self::Ok, Self::Error> {
self.serialize_integer(v, false)
}
fn serialize_u32(self, v: u32) -> Result<Self::Ok, Self::Error> {
self.serialize_integer(v, false)
}
fn serialize_u64(self, v: u64) -> Result<Self::Ok, Self::Error> {
self.serialize_integer(v, false)
}
fn serialize_u128(self, v: u128) -> Result<Self::Ok, Self::Error> {
self.serialize_integer(v, false)
}
fn serialize_f32(self, v: f32) -> Result<Self::Ok, Self::Error> {
self.serialize_real(v as f64)
}
fn serialize_f64(self, v: f64) -> Result<Self::Ok, Self::Error> {
self.serialize_real(v)
}
fn serialize_char(self, v: char) -> Result<Self::Ok, Self::Error> {
self.serialize_str(&v.to_string())
}
fn serialize_str(self, v: &str) -> Result<Self::Ok, Self::Error> {
self.serialize_bytes(v.as_bytes())
}
fn serialize_bytes(self, v: &[u8]) -> Result<Self::Ok, Self::Error> {
let next_fmt = *self.next_fmt()?;
if let FortField::Char { width } = next_fmt {
serialize_characters(v, width, &mut self.buf, self.settings.align_left_str)
} else {
Err(SError::FormatTypeMismatch {
spec_type: next_fmt,
serde_type: "char/str/bytes",
field_name: self.try_prev_field().map(|f| f.to_string()),
})
}
}
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
let next_fmt = *self.next_fmt()?;
let fill_bytes = self
.settings
.fill_method
.make_fill_bytes(&next_fmt, self.settings.align_left_str)?;
self.write_next_entry_raw(&fill_bytes, Some(next_fmt))
}
fn serialize_some<T: ?Sized>(self, value: &T) -> Result<Self::Ok, Self::Error>
where
T: serde::Serialize,
{
value.serialize(self)
}
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
self.serialize_none()
}
fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
self.serialize_none()
}
fn serialize_unit_variant(
self,
_name: &'static str,
variant_index: u32,
variant: &'static str,
) -> Result<Self::Ok, Self::Error> {
let peeked_fmt = *self.peek_fmt().ok_or_else(|| SError::FormatSpecTooShort)?;
if let FortField::Integer {
width: _,
zeros: _,
base: _,
} = peeked_fmt
{
self.serialize_u32(variant_index)
} else if let FortField::Char { width: _ } = peeked_fmt {
self.serialize_str(variant)
} else {
Err(SError::FormatTypeMismatch {
spec_type: peeked_fmt,
serde_type: "str or integer",
field_name: self.try_prev_field().map(|f| f.to_string()),
})
}
}
fn serialize_newtype_struct<T: ?Sized>(
self,
_name: &'static str,
value: &T,
) -> Result<Self::Ok, Self::Error>
where
T: serde::Serialize,
{
value.serialize(self)
}
fn serialize_newtype_variant<T: ?Sized>(
self,
name: &'static str,
variant_index: u32,
variant: &'static str,
value: &T,
) -> Result<Self::Ok, Self::Error>
where
T: serde::Serialize,
{
self.serialize_unit_variant(name, variant_index, variant)?;
value.serialize(self)
}
fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
Ok(self)
}
fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
Ok(self)
}
fn serialize_tuple_struct(
self,
_name: &'static str,
_len: usize,
) -> Result<Self::SerializeTupleStruct, Self::Error> {
Ok(self)
}
fn serialize_tuple_variant(
self,
name: &'static str,
variant_index: u32,
variant: &'static str,
_len: usize,
) -> Result<Self::SerializeTupleVariant, Self::Error> {
self.serialize_unit_variant(name, variant_index, variant)?;
Ok(self)
}
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
if self.map_helper.in_use {
unimplemented!("Can't yet recursively call serialize_map - the map_helper must be reset before the next call")
}
Ok(self)
}
fn serialize_struct(
self,
_name: &'static str,
_len: usize,
) -> Result<Self::SerializeStruct, Self::Error> {
if self.map_helper.in_use {
unimplemented!("Can't yet recursively call serialize_map - the map_helper must be reset before the next call")
}
Ok(self)
}
fn serialize_struct_variant(
self,
name: &'static str,
variant_index: u32,
variant: &'static str,
_len: usize,
) -> Result<Self::SerializeStructVariant, Self::Error> {
if self.map_helper.in_use {
unimplemented!("Can't yet recursively call serialize_map - the map_helper must be reset before the next call")
}
self.serialize_unit_variant(name, variant_index, variant)?;
Ok(self)
}
}
impl<'a, 'f, W: Write + 'f, F: AsRef<str>> ser::SerializeSeq for &'a mut Serializer<'f, W, F> {
type Ok = ();
type Error = SError;
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
where
T: serde::Serialize,
{
value.serialize(&mut **self)
}
fn end(self) -> Result<Self::Ok, Self::Error> {
Ok(())
}
}
impl<'a, 'f, W: Write + 'f, F: AsRef<str>> ser::SerializeTuple for &'a mut Serializer<'f, W, F> {
type Ok = ();
type Error = SError;
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
where
T: serde::Serialize,
{
value.serialize(&mut **self)
}
fn end(self) -> Result<Self::Ok, Self::Error> {
Ok(())
}
}
impl<'a, 'f, W: Write + 'f, F: AsRef<str>> ser::SerializeTupleStruct
for &'a mut Serializer<'f, W, F>
{
type Ok = ();
type Error = SError;
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
where
T: serde::Serialize,
{
value.serialize(&mut **self)
}
fn end(self) -> Result<Self::Ok, Self::Error> {
Ok(())
}
}
impl<'a, 'f, W: Write + 'f, F: AsRef<str>> ser::SerializeTupleVariant
for &'a mut Serializer<'f, W, F>
{
type Ok = ();
type Error = SError;
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
where
T: serde::Serialize,
{
value.serialize(&mut **self)
}
fn end(self) -> Result<Self::Ok, Self::Error> {
Ok(())
}
}
impl<'a, 'f, W: Write + 'f, F: AsRef<str>> ser::SerializeMap for &'a mut Serializer<'f, W, F> {
type Ok = ();
type Error = SError;
fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<(), Self::Error>
where
T: serde::Serialize,
{
if self.fields.is_some() {
let fmt = FortFormat::parse("(a512)").unwrap();
let key_string =
to_string(key, &fmt).map_err(|e| SError::KeyToFieldError(Arc::new(e)))?;
self.serialize_key_helper(key_string.trim())
} else {
Ok(())
}
}
fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
where
T: serde::Serialize,
{
self.serialize_value_helper(value)
}
fn end(self) -> Result<Self::Ok, Self::Error> {
self.end_helper()
}
}
impl<'a, 'f, W: Write + 'f, F: AsRef<str>> ser::SerializeStruct for &'a mut Serializer<'f, W, F> {
type Ok = ();
type Error = SError;
fn serialize_field<T: ?Sized>(
&mut self,
key: &'static str,
value: &T,
) -> Result<(), Self::Error>
where
T: serde::Serialize,
{
if self.fields.is_some() {
self.serialize_key_helper(key)?;
}
self.serialize_value_helper(value)
}
fn end(self) -> Result<Self::Ok, Self::Error> {
self.end_helper()
}
}
impl<'a, 'f, W: Write + 'f, F: AsRef<str>> ser::SerializeStructVariant
for &'a mut Serializer<'f, W, F>
{
type Ok = ();
type Error = SError;
fn serialize_field<T: ?Sized>(
&mut self,
key: &'static str,
value: &T,
) -> Result<(), Self::Error>
where
T: serde::Serialize,
{
if self.fields.is_some() {
self.serialize_key_helper(key)?;
}
self.serialize_value_helper(value)
}
fn end(self) -> Result<Self::Ok, Self::Error> {
self.end_helper()
}
}
pub(crate) fn serialize_logical<W: Write>(v: bool, width: u32, mut buf: W) -> SResult<()> {
let b = if v { b"T" } else { b"F" };
for _ in 0..width - 1 {
buf.write(b" ")?;
}
buf.write(b)?;
Ok(())
}
pub(crate) fn serialize_characters<W: Write>(
v: &[u8],
width: Option<u32>,
mut buf: W,
left_align: bool,
) -> SResult<()> {
if let Some(width) = width {
let w = width as usize;
if v.len() >= w {
buf.write(&v[..w])?;
} else if left_align {
buf.write(v)?;
for _ in 0..(w - v.len()) {
buf.write(b" ")?;
}
} else {
for _ in 0..(w - v.len()) {
buf.write(b" ")?;
}
buf.write(v)?;
}
Ok(())
} else {
buf.write(v)?;
Ok(())
}
}
pub(crate) fn serialize_integer<W: Write, I: itoa::Integer + Octal + UpperHex>(
width: u32,
zeros: Option<u32>,
base: IntBase,
mut buf: W,
abs_value: I,
is_neg: bool,
) -> SResult<()> {
let (s, is_dec): (Vec<u8>, bool) = match base {
IntBase::Decimal => {
let mut b = itoa::Buffer::new();
(
b.format(abs_value)
.as_bytes()
.into_iter()
.copied()
.collect(),
true,
)
}
IntBase::Octal => (
format!("{abs_value:o}")
.as_bytes()
.into_iter()
.copied()
.collect(),
false,
),
IntBase::Hexadecimal => (
format!("{abs_value:X}")
.as_bytes()
.into_iter()
.copied()
.collect(),
false,
),
};
let nsign = if is_neg { 1 } else { 0 };
let nzeros = zeros.map(|n| n.saturating_sub(s.len() as u32)).unwrap_or(0);
let nchar = nzeros + nsign + s.len() as u32;
let bad_output = nchar > width || (is_neg && !is_dec);
if bad_output {
for _ in 0..width {
buf.write(b"*")?;
}
} else {
let nspace = width - nchar;
for _ in 0..nspace {
buf.write(b" ")?;
}
if is_neg {
buf.write(b"-")?;
}
for _ in 0..nzeros {
buf.write(b"0")?;
}
buf.write(&s)?;
}
Ok(())
}
fn d2d_helper(v: f64) -> ryu_floating_decimal::FloatingDecimal64 {
if v == 0.0 {
ryu_floating_decimal::FloatingDecimal64 {
mantissa: 0,
exponent: 0,
}
} else {
d2d(v)
}
}
pub(crate) fn serialize_real_f<W: Write>(
mut buf: W,
v: f64,
width: u32,
precision: u32,
scale: i32,
) -> SResult<()> {
let v_is_neg = v < 0.0;
let signed_prec = precision as i32;
let rv = (v * 10.0_f64.powi(signed_prec)).round_ties_even() * 10.0_f64.powi(-signed_prec);
let v = d2d_helper(rv);
let mut b = itoa::Buffer::new();
let s = b.format(v.mantissa);
let m_bytes = s.as_bytes();
let exponent = v.exponent;
let width = width as usize;
let n_reserved = if v_is_neg {
2 + precision
} else {
1 + precision
} as usize;
let exp_plus_scale = (exponent + scale) as isize;
let n_leading_digits = m_bytes.len().saturating_add_signed(exp_plus_scale);
if n_leading_digits + n_reserved > width {
for _ in 0..width {
buf.write(b"*")?;
}
return Ok(());
}
let wants_leading_zero = n_leading_digits == 0;
let (n_spaces, print_leading_zero) = if !wants_leading_zero {
(width - n_reserved - n_leading_digits, false)
} else if n_leading_digits + n_reserved < width {
(width - n_reserved - n_leading_digits - 1, true)
} else {
(0, false)
};
let zeros_after_decimal = if exp_plus_scale >= 0 {
0
} else {
let nexp = (-exp_plus_scale) as usize;
nexp.saturating_sub(m_bytes.len())
};
for _ in 0..n_spaces {
buf.write(b" ")?;
}
if v_is_neg {
buf.write(b"-")?;
}
if print_leading_zero {
buf.write(b"0")?;
}
for i in 0..(n_leading_digits + precision as usize - zeros_after_decimal) {
if i == n_leading_digits {
buf.write(b".")?;
for _ in 0..zeros_after_decimal {
buf.write(b"0")?;
}
}
let i = i as usize;
let c = m_bytes.get(i..i + 1).unwrap_or(b"0");
buf.write(c)?;
}
if n_leading_digits + precision as usize == zeros_after_decimal {
buf.write(b".")?;
for _ in 0..zeros_after_decimal {
buf.write(b"0")?;
}
}
Ok(())
}
pub(crate) fn serialize_real_exp<W: Write>(
mut buf: W,
v: f64,
width: u32,
precision: u32,
scale: i32,
exp_ch: &str,
n_exp_digits: Option<u32>,
) -> SResult<()> {
let v_is_neg = v < 0.0;
let v_orig = v;
let v = d2d_helper(v);
let n_digits_avail = ((precision as i32) + scale).max(0) as u32;
let n_digits_wanted = if v.mantissa == 0 {
1
} else {
v.mantissa.ilog10() + 1
};
let mantissa = if n_digits_wanted <= n_digits_avail || v.mantissa == 0 {
v.mantissa
} else {
let m = 10u64.pow(n_digits_wanted - n_digits_avail);
let r = v.mantissa % m;
let round_down = if r == m / 2 {
(v.mantissa / m) % 2 == 0
} else {
r < m / 2
};
let tmp = v.mantissa.checked_next_multiple_of(m).ok_or_else(|| {
SError::SerializationFailure(format!("overflow while rounding {v_orig}"))
})?;
if round_down {
tmp - m
} else {
tmp
}
};
let mut b = itoa::Buffer::new();
let s = b.format(mantissa);
let m_bytes = s.as_bytes();
let exponent = if v.mantissa == 0 {
0
} else {
v.exponent + m_bytes.len() as i32 - scale
};
let mut b = itoa::Buffer::new();
let s = b.format(exponent.abs());
let e_bytes = s.as_bytes();
let exp_nchar = if let Some(n) = n_exp_digits {
if e_bytes.len() > n as usize {
for _ in 0..width {
buf.write(b"*")?;
}
return Ok(());
}
n + 2
} else {
if e_bytes.len() > 3 {
for _ in 0..width {
buf.write(b"*")?;
}
return Ok(());
}
4
};
let min_width = if v_is_neg {
precision + 2 + exp_nchar
} else {
precision + 1 + exp_nchar
};
if width < min_width {
for _ in 0..width {
buf.write(b"*")?;
}
return Ok(());
}
let nspaces = if width > min_width {
width - min_width - 1
} else {
0
};
for _ in 0..nspaces {
buf.write(b" ")?;
}
if v_is_neg {
buf.write(b"-")?;
}
if scale > 0 {
let mut i = 0;
for _ in 0..scale {
let c = m_bytes.get(i..i + 1).unwrap_or(b"0");
buf.write(c)?;
i += 1;
}
buf.write(b".")?;
let n_after_decimal = if scale <= 1 {
precision
} else {
precision - scale as u32 + 1
};
for _ in 0..n_after_decimal {
let c = m_bytes.get(i..i + 1).unwrap_or(b"0");
buf.write(c)?;
i += 1;
}
} else {
if width > min_width {
buf.write(b"0")?;
}
buf.write(b".")?;
let mut i = 0;
for _ in 0..precision {
if i < -scale {
buf.write(b"0")?;
} else {
let j = (i + scale) as usize;
let c = m_bytes.get(j..j + 1).unwrap_or(b"0");
buf.write(c)?;
}
i += 1;
}
}
let n_digits = if e_bytes.len() <= (exp_nchar as usize) - 2 {
buf.write(exp_ch.as_bytes())?;
exp_nchar - 2
} else {
exp_nchar - 1
};
if exponent < 0 {
buf.write(b"-")?;
} else {
buf.write(b"+")?;
}
for _ in 0..(n_digits as usize - e_bytes.len()) {
buf.write(b"0")?;
}
buf.write(e_bytes)?;
Ok(())
}
#[cfg(test)]
mod tests {
use std::collections::HashMap;
use super::*;
#[derive(Debug, serde::Serialize)]
struct Test {
a: &'static str,
b: i32,
c: f64,
}
#[derive(Debug, serde::Serialize)]
struct HasFlat {
name: &'static str,
#[serde(flatten)]
data: HashMap<String, i32>,
}
#[derive(Debug, serde::Serialize)]
struct Nested {
db_id: i64,
inner: Test,
}
#[test]
fn test_ser_bool() {
let fmt = FortFormat::parse("(l1)").unwrap();
let s = to_string(true, &fmt).unwrap();
assert_eq!(s, "T");
let s = to_string(false, &fmt).unwrap();
assert_eq!(s, "F");
let fmt = FortFormat::parse("(l3)").unwrap();
let s = to_string(true, &fmt).unwrap();
assert_eq!(s, " T");
let s = to_string(false, &fmt).unwrap();
assert_eq!(s, " F");
}
#[test]
fn test_ser_dec_int() {
let fmt = FortFormat::parse("(i4)").unwrap();
let s = to_string(42, &fmt).unwrap();
assert_eq!(s, " 42");
let s = to_string(-42, &fmt).unwrap();
assert_eq!(s, " -42");
let s = to_string(12345, &fmt).unwrap();
assert_eq!(s, "****");
let fmt = FortFormat::parse("(i4.3)").unwrap();
let s = to_string(42, &fmt).unwrap();
assert_eq!(s, " 042");
let s = to_string(-42, &fmt).unwrap();
assert_eq!(s, "-042");
let s = to_string(123, &fmt).unwrap();
assert_eq!(s, " 123");
let s = to_string(-123, &fmt).unwrap();
assert_eq!(s, "-123");
let fmt = FortFormat::parse("(i3.3)").unwrap();
let s = to_string(42, &fmt).unwrap();
assert_eq!(s, "042");
let s = to_string(-42, &fmt).unwrap();
assert_eq!(s, "***");
}
#[test]
fn test_octal_int() {
let fmt = FortFormat::parse("(o5)").unwrap();
let s = to_string(42, &fmt).unwrap();
assert_eq!(s, " 52");
let s = to_string(-42, &fmt).unwrap();
assert_eq!(s, "*****");
let fmt = FortFormat::parse("(o5.3)").unwrap();
let s = to_string(42, &fmt).unwrap();
assert_eq!(s, " 052");
let s = to_string(-42, &fmt).unwrap();
assert_eq!(s, "*****");
}
#[test]
fn test_hex_int() {
let fmt = FortFormat::parse("(z5)").unwrap();
let s = to_string(42, &fmt).unwrap();
assert_eq!(s, " 2A");
let s = to_string(-42, &fmt).unwrap();
assert_eq!(s, "*****");
let fmt = FortFormat::parse("(z5.3)").unwrap();
let s = to_string(42, &fmt).unwrap();
assert_eq!(s, " 02A");
let s = to_string(-42, &fmt).unwrap();
assert_eq!(s, "*****");
}
#[test]
fn test_char() {
let fmt = FortFormat::parse("(a)").unwrap();
let s = to_string('x', &fmt).unwrap();
assert_eq!(s, "x");
let fmt = FortFormat::parse("(a2)").unwrap();
let s = to_string('x', &fmt).unwrap();
assert_eq!(s, " x");
}
#[test]
fn test_str() {
let fmt = FortFormat::parse("(a)").unwrap();
let s = to_string("abcde", &fmt).unwrap();
assert_eq!(s, "abcde");
let fmt = FortFormat::parse("(a5)").unwrap();
let s = to_string("abc", &fmt).unwrap();
assert_eq!(s, " abc");
let s = to_string("abcde", &fmt).unwrap();
assert_eq!(s, "abcde");
let s = to_string("abcdefg", &fmt).unwrap();
assert_eq!(s, "abcde");
let settings = SerSettings::default().align_left_str(true);
let s = to_string_custom::<_, &str>("abc", &fmt, None, &settings).unwrap();
assert_eq!(s, "abc ");
}
#[test]
fn test_real_f() {
let fmt = FortFormat::parse("(f9.4)").unwrap();
let s = to_string(8e-5, &fmt).unwrap();
assert_eq!(s, " 0.0001");
let fmt = FortFormat::parse("(f9.4)").unwrap();
let s = to_string(4e-5, &fmt).unwrap();
assert_eq!(s, " 0.0000");
let fmt = FortFormat::parse("(f5.3)").unwrap();
let s = to_string(-0.01, &fmt).unwrap();
assert_eq!(s, "-.010");
let fmt = FortFormat::parse("(f4.3)").unwrap();
let s = to_string(0.314, &fmt).unwrap();
assert_eq!(s, ".314");
let fmt = FortFormat::parse("(f8.3)").unwrap();
let s = to_string(3.14, &fmt).unwrap();
assert_eq!(s, " 3.140");
let fmt = FortFormat::parse("(2pf8.3)").unwrap();
let s = to_string(3.14, &fmt).unwrap();
assert_eq!(s, " 314.000");
let fmt = FortFormat::parse("(-2pf8.3)").unwrap();
let s = to_string(3.14, &fmt).unwrap();
assert_eq!(s, " 0.031");
let fmt = FortFormat::parse("(2pf5.3)").unwrap();
let s = to_string(3.14, &fmt).unwrap();
assert_eq!(s, "*****");
}
#[test]
fn test_real_e() {
let fmt = FortFormat::parse("(e12.3)").unwrap();
let s = to_string(0.0314, &fmt).unwrap();
assert_eq!(s, " 0.314E-01");
let s = to_string(3.14, &fmt).unwrap();
assert_eq!(s, " 0.314E+01");
let s = to_string(3140.0, &fmt).unwrap();
assert_eq!(s, " 0.314E+04");
let s = to_string(3141.59, &fmt).unwrap();
assert_eq!(s, " 0.314E+04");
let s = to_string(3.14e120, &fmt).unwrap();
assert_eq!(s, " 0.314+121");
let fmt = FortFormat::parse("(1pe12.3)").unwrap();
let s = to_string(3.14, &fmt).unwrap();
assert_eq!(s, " 3.140E+00");
let s = to_string(3.1415, &fmt).unwrap();
assert_eq!(s, " 3.142E+00");
let fmt = FortFormat::parse("(2pe12.3)").unwrap();
let s = to_string(3.14, &fmt).unwrap();
assert_eq!(s, " 31.40E-01");
let fmt = FortFormat::parse("(-1pe12.3)").unwrap();
let s = to_string(3.14, &fmt).unwrap();
assert_eq!(s, " 0.031E+02");
let fmt = FortFormat::parse("(-2pe12.3)").unwrap();
let s = to_string(3.14, &fmt).unwrap();
assert_eq!(s, " 0.003E+03");
let fmt = FortFormat::parse("(e7.3)").unwrap();
let s = to_string(3.14, &fmt).unwrap();
assert_eq!(s, "*******");
let s = to_string(-3.14, &fmt).unwrap();
assert_eq!(s, "*******");
let fmt = FortFormat::parse("(e8.3)").unwrap();
let s = to_string(3.14, &fmt).unwrap();
assert_eq!(s, ".314E+01");
let s = to_string(-3.14, &fmt).unwrap();
assert_eq!(s, "********");
let fmt = FortFormat::parse("(e9.3)").unwrap();
let s = to_string(3.14, &fmt).unwrap();
assert_eq!(s, "0.314E+01");
let s = to_string(-3.14, &fmt).unwrap();
assert_eq!(s, "-.314E+01");
let fmt = FortFormat::parse("(-2pe13.5)").unwrap();
let s = to_string(0.999999, &fmt).unwrap();
assert_eq!(s, " 0.00100E+03");
let fmt = FortFormat::parse("(-1pe13.5)").unwrap();
let s = to_string(0.999999, &fmt).unwrap();
assert_eq!(s, " 0.01000E+02");
let fmt = FortFormat::parse("(e13.5)").unwrap();
let s = to_string(0.999999, &fmt).unwrap();
assert_eq!(s, " 0.10000E+01");
let fmt = FortFormat::parse("(1pe13.5)").unwrap();
let s = to_string(0.999999, &fmt).unwrap();
assert_eq!(s, " 9.99999E-01");
let fmt = FortFormat::parse("(2pe13.5)").unwrap();
let s = to_string(0.999999, &fmt).unwrap();
assert_eq!(s, " 99.9999E-02");
let fmt = FortFormat::parse("(1pe12.4)").unwrap();
let s = to_string(9.8765e35, &fmt).unwrap();
assert_eq!(s, " 9.8765E+35");
let fmt = FortFormat::parse("(e12.4)").unwrap();
let s = to_string(1.0, &fmt).unwrap();
assert_eq!(s, " 0.1000E+01");
let fmt = FortFormat::parse("(1pe12.4)").unwrap();
let s = to_string(1.0, &fmt).unwrap();
assert_eq!(s, " 1.0000E+00");
let fmt = FortFormat::parse("(2pe12.4)").unwrap();
let s = to_string(1.0, &fmt).unwrap();
assert_eq!(s, " 10.000E-01");
let fmt = FortFormat::parse("(-1pe12.4)").unwrap();
let s = to_string(1.0, &fmt).unwrap();
assert_eq!(s, " 0.0100E+02");
let fmt = FortFormat::parse("(-2pe12.4)").unwrap();
let s = to_string(1.0, &fmt).unwrap();
assert_eq!(s, " 0.0010E+03");
let fmt = FortFormat::parse("(e12.4)").unwrap();
let s = to_string(-1.0, &fmt).unwrap();
assert_eq!(s, " -0.1000E+01");
let fmt = FortFormat::parse("(1pe12.4)").unwrap();
let s = to_string(-1.0, &fmt).unwrap();
assert_eq!(s, " -1.0000E+00");
let fmt = FortFormat::parse("(2pe12.4)").unwrap();
let s = to_string(-1.0, &fmt).unwrap();
assert_eq!(s, " -10.000E-01");
let fmt = FortFormat::parse("(-1pe12.4)").unwrap();
let s = to_string(-1.0, &fmt).unwrap();
assert_eq!(s, " -0.0100E+02");
let fmt = FortFormat::parse("(-2pe12.4)").unwrap();
let s = to_string(-1.0, &fmt).unwrap();
assert_eq!(s, " -0.0010E+03");
let fmt = FortFormat::parse("(e12.4)").unwrap();
let s = to_string(0.0, &fmt).unwrap();
assert_eq!(s, " 0.0000E+00");
let fmt = FortFormat::parse("(1pe12.4)").unwrap();
let s = to_string(0.0, &fmt).unwrap();
assert_eq!(s, " 0.0000E+00");
let fmt = FortFormat::parse("(2pe12.4)").unwrap();
let s = to_string(0.0, &fmt).unwrap();
assert_eq!(s, " 00.000E+00");
let fmt = FortFormat::parse("(-1pe12.4)").unwrap();
let s = to_string(0.0, &fmt).unwrap();
assert_eq!(s, " 0.0000E+00");
let fmt = FortFormat::parse("(-2pe12.4)").unwrap();
let s = to_string(0.0, &fmt).unwrap();
assert_eq!(s, " 0.0000E+00");
}
#[test]
fn test_real_d() {
let fmt = FortFormat::parse("(d12.3)").unwrap();
let s = to_string(3.14, &fmt).unwrap();
assert_eq!(s, " 0.314D+01");
let s = to_string(3.14e120, &fmt).unwrap();
assert_eq!(s, " 0.314+121");
let fmt = FortFormat::parse("(1pd12.3)").unwrap();
let s = to_string(3.14, &fmt).unwrap();
assert_eq!(s, " 3.140D+00");
let fmt = FortFormat::parse("(-1pd12.3)").unwrap();
let s = to_string(3.14, &fmt).unwrap();
assert_eq!(s, " 0.031D+02");
let fmt = FortFormat::parse("(-2pd12.3)").unwrap();
let s = to_string(3.14, &fmt).unwrap();
assert_eq!(s, " 0.003D+03");
let fmt = FortFormat::parse("(d12.4)").unwrap();
let s = to_string(0.0, &fmt).unwrap();
assert_eq!(s, " 0.0000D+00");
let fmt = FortFormat::parse("(1pd12.4)").unwrap();
let s = to_string(0.0, &fmt).unwrap();
assert_eq!(s, " 0.0000D+00");
let fmt = FortFormat::parse("(2pd12.4)").unwrap();
let s = to_string(0.0, &fmt).unwrap();
assert_eq!(s, " 00.000D+00");
let fmt = FortFormat::parse("(-1pd12.4)").unwrap();
let s = to_string(0.0, &fmt).unwrap();
assert_eq!(s, " 0.0000D+00");
let fmt = FortFormat::parse("(-2pd12.4)").unwrap();
let s = to_string(0.0, &fmt).unwrap();
assert_eq!(s, " 0.0000D+00");
}
#[test]
fn test_vec() {
let fmt = FortFormat::parse("(i3.3,1x,i4.4,1x,i5.5)").unwrap();
let s = to_string(vec![10, 200, 3000], &fmt).unwrap();
assert_eq!(s, "010 0200 03000");
}
#[test]
fn test_tuple() {
let fmt = FortFormat::parse("(a3,1x,i3.3)").unwrap();
let s = to_string(("Hi!", 42), &fmt).unwrap();
assert_eq!(s, "Hi! 042");
}
#[test]
fn test_struct_by_order() {
let fmt = FortFormat::parse("(a6,1x,i3,1x,e8.3)").unwrap();
let value = Test {
a: "Hello",
b: 42,
c: 3.14,
};
let s = to_string(value, &fmt).unwrap();
assert_eq!(s, " Hello 42 .314E+01");
}
#[test]
fn test_struct_by_name() {
let fmt = FortFormat::parse("(i3,1x,e8.3,1x,a6)").unwrap();
let value = Test {
a: "Hello",
b: 42,
c: 3.14,
};
let s = to_string_with_fields(value, &fmt, &["b", "c", "a"]).unwrap();
assert_eq!(s, " 42 .314E+01 Hello");
}
#[test]
fn test_map_by_name() {
let value = HashMap::from([("a", 2), ("b", 4), ("c", 8)]);
let fmt = FortFormat::parse("(3i2)").unwrap();
let s = to_string_with_fields(value, &fmt, &["b", "a", "c"]).unwrap();
assert_eq!(s, " 4 2 8");
}
#[test]
fn test_struct_with_flattened_map() {
let data = HashMap::from([
("co2".to_string(), 400_000),
("ch4".to_string(), 1900),
("n2o".to_string(), 310),
("co".to_string(), 100),
]);
let value = HasFlat { name: "pa", data };
let fmt = FortFormat::parse("(a2,4(1x,i6))").unwrap();
let s = to_string_with_fields(value, &fmt, &["name", "n2o", "co", "co2", "ch4"]).unwrap();
assert_eq!(s, "pa 310 100 400000 1900");
}
#[test]
fn test_nested_struct_by_order() {
let inner = Test {
a: "Hello",
b: 42,
c: 3.14,
};
let value = Nested { db_id: 1, inner };
let fmt = FortFormat::parse("(i2,1x,a5,1x,i2,1x,e8.3)").unwrap();
let s = to_string(value, &fmt).unwrap();
assert_eq!(s, " 1 Hello 42 .314E+01");
}
#[test]
fn test_nested_struct_by_name() {
let inner = Test {
a: "Hello",
b: 42,
c: 3.14,
};
let value = Nested { db_id: 1, inner };
let fmt = FortFormat::parse("(e8.3,1x,i2,1x,a5,1x,i1)").unwrap();
let e = to_string_with_fields(value, &fmt, &["c", "b", "a", "db_id"]);
assert!(e.is_err());
}
#[test]
fn test_external_enums() {
#[derive(Debug, serde::Serialize)]
enum External {
Alpha(i32),
Beta(i32),
}
let ex_vec = vec![External::Alpha(12), External::Beta(24)];
let ex_ff = FortFormat::parse("(2(a6,i3))").unwrap();
let ex_s = to_string(&ex_vec, &ex_ff).unwrap();
assert_eq!(ex_s, " Alpha 12 Beta 24");
}
#[test]
fn test_internal_enums() {
#[derive(Debug, serde::Serialize)]
#[serde(tag = "type")]
enum Internal {
Alpha { value: i32 },
Beta { value: i32 },
}
let in_vec = vec![Internal::Alpha { value: 12 }, Internal::Beta { value: 24 }];
let in_ff = FortFormat::parse("(2(a6,i3))").unwrap();
let in_s = to_string(&in_vec, &in_ff).unwrap();
assert_eq!(in_s, " Alpha 12 Beta 24");
let fields = ["type", "value"];
let ff = FortFormat::parse("(a5,1x,i2)").unwrap();
let s = to_string_with_fields(Internal::Alpha { value: 42 }, &ff, &fields).unwrap();
assert_ne!(s, "42 Alpha");
}
#[test]
fn test_adjacent_enums() {
#[derive(Debug, serde::Serialize)]
#[serde(tag = "key", content = "value")]
enum Adjacent {
Alpha(i32),
Beta(i32),
}
let adj_vec = vec![Adjacent::Alpha(12), Adjacent::Beta(24)];
let adj_ff = FortFormat::parse("(2(a6,i3))").unwrap();
let adj_s = to_string(&adj_vec, &adj_ff).unwrap();
assert_eq!(adj_s, " Alpha 12 Beta 24");
}
#[test]
fn test_untagged_enums() {
#[derive(Debug, serde::Serialize)]
#[serde(untagged)]
enum Untagged {
Alpha(i32),
Beta(f32),
}
let un_vec = vec![Untagged::Alpha(12), Untagged::Beta(24.0)];
let un_ff = FortFormat::parse("(i3,f6.1)").unwrap();
let un_s = to_string(&un_vec, &un_ff).unwrap();
assert_eq!(un_s, " 12 24.0");
}
#[test]
fn test_enum_into() {
#[derive(Debug, Clone, serde::Serialize)]
#[serde(into = "String")]
enum InstrumentValue {
Nothing,
Value(f32),
ValueWithError(f32, f32),
}
impl From<InstrumentValue> for String {
fn from(value: InstrumentValue) -> Self {
match value {
InstrumentValue::Nothing => "Nothing".to_string(),
InstrumentValue::Value(v) => format!("{v:.3}"),
InstrumentValue::ValueWithError(v, e) => format!("{v:.1}+/-{e:.1}"),
}
}
}
let values = [
InstrumentValue::Nothing,
InstrumentValue::Value(1.0),
InstrumentValue::ValueWithError(2.0, 0.2),
];
let ff = FortFormat::parse("(3a12)").unwrap();
let s = to_string(values, &ff).unwrap();
assert_eq!(s, " Nothing 1.000 2.0+/-0.2");
}
#[test]
fn test_none_default_fill() {
let fmt = FortFormat::parse("(a,1x,a3,1x,l1,1x,i5,1x,f8.3)").unwrap();
let value: (
Option<String>,
Option<String>,
Option<bool>,
Option<i32>,
Option<f32>,
) = (None, None, None, None, None);
let s = to_string(value, &fmt).unwrap();
assert_eq!(s, "* *** * ***** ********");
}
#[test]
fn test_none_string_fill() {
let settings =
SerSettings::default().fill_method(NoneFill::String("FILL_VAL".as_bytes().to_vec()));
let fmt = FortFormat::parse("(a,1x,a3,1x,l1,1x,i5,1x,f8.3)").unwrap();
let value: (
Option<String>,
Option<String>,
Option<bool>,
Option<i32>,
Option<f32>,
) = (None, None, None, None, None);
let s = to_string_custom::<_, &str>(value, &fmt, None, &settings).unwrap();
assert_eq!(s, "F FIL F FILL_ FILL_VAL");
}
#[test]
fn test_none_partial_typed_fill() {
let settings =
SerSettings::default().fill_method(NoneFill::new_partial_typed(-999, -999.999));
let fmt = FortFormat::parse("(a,1x,a3,1x,l1,1x,i5,1x,f8.3)").unwrap();
let value: (
Option<String>,
Option<String>,
Option<bool>,
Option<i32>,
Option<f32>,
) = (None, None, None, None, None);
let s = to_string_custom::<_, &str>(value, &fmt, None, &settings).unwrap();
assert_eq!(s, "* *** * -999 -999.999");
}
#[test]
fn test_none_typed_fill() {
let settings =
SerSettings::default().fill_method(NoneFill::new_typed(false, -999, -999.999, "N/A"));
let fmt = FortFormat::parse("(a,1x,a3,1x,l1,1x,i5,1x,f8.3)").unwrap();
let value: (
Option<String>,
Option<String>,
Option<bool>,
Option<i32>,
Option<f32>,
) = (None, None, None, None, None);
let s = to_string_custom::<_, &str>(value, &fmt, None, &settings).unwrap();
assert_eq!(s, "N/A N/A F -999 -999.999");
}
#[test]
fn test_unit_type_fills() {
#[derive(serde::Serialize)]
struct Empty;
let fmt = FortFormat::parse("(i5,1x,f8.3)").unwrap();
let value = ((), Empty);
let s = to_string(value, &fmt).unwrap();
assert_eq!(s, "***** ********");
}
#[test]
fn test_multi_rec_write() {
let values = [
("pa", 45.945, -90.273),
("db", -12.45, 130.93),
("lh", -45.038, 169.684),
];
let fmt = FortFormat::parse("(a2,1x,f7.3,1x,f8.3)").unwrap();
let mut buf = vec![];
many_to_writer_custom::<_, _, &str>(&values, &fmt, None, &SerSettings::default(), &mut buf)
.unwrap();
let s = String::from_utf8(buf).unwrap();
assert_eq!(
s,
"pa 45.945 -90.273\ndb -12.450 130.930\nlh -45.038 169.684\n"
);
}
#[test]
fn test_multi_rec_struct_write() {
let values = [
Test {
a: "alpha",
b: 1,
c: 100.0,
},
Test {
a: "beta",
b: 2,
c: 200.0,
},
Test {
a: "gamma",
b: 3,
c: 300.0,
},
];
let fmt = FortFormat::parse("(i1,1x,f5.1,1x,a5)").unwrap();
let mut buf = vec![];
many_to_writer_custom(
&values,
&fmt,
Some(&["b", "c", "a"]),
&SerSettings::default(),
&mut buf,
)
.unwrap();
let s = String::from_utf8(buf).unwrap();
assert_eq!(s, "1 100.0 alpha\n2 200.0 beta\n3 300.0 gamma\n");
}
#[test]
fn test_string_justification() {
let fmt = FortFormat::parse("(a8,i2)").unwrap();
let values = ("abcde", 42);
let settings = SerSettings::default().align_left_str(true);
let s = to_string_custom::<_, &str>(values, &fmt, None, &settings).unwrap();
assert_eq!(s, "abcde 42");
#[derive(Debug, serde::Serialize)]
struct Test1 {
s: &'static str,
n: i32,
}
let values = Test1 { s: "abcde", n: 42 };
let s = to_string_custom::<_, &str>(&values, &fmt, None, &settings).unwrap();
assert_eq!(s, "abcde 42");
let s = to_string_custom::<_, &str>(&values, &fmt, Some(&["s", "n"]), &settings).unwrap();
assert_eq!(s, "abcde 42");
let mut buf = vec![];
to_writer_custom::<_, _, &str>(&values, &fmt, None, &settings, &mut buf).unwrap();
let s = String::from_utf8(buf).unwrap();
assert_eq!(s, "abcde 42\n");
let mut buf = vec![];
to_writer_custom::<_, _, &str>(&values, &fmt, Some(&["s", "n"]), &settings, &mut buf)
.unwrap();
let s = String::from_utf8(buf).unwrap();
assert_eq!(s, "abcde 42\n");
#[derive(Debug, serde::Serialize)]
struct Test2 {
s: String,
n: i32,
}
let values = Test2 {
s: "abcde".to_string(),
n: 42,
};
let s = to_string_custom::<_, &str>(&values, &fmt, None, &settings).unwrap();
assert_eq!(s, "abcde 42");
let s = to_string_custom::<_, &str>(&values, &fmt, Some(&["s", "n"]), &settings).unwrap();
assert_eq!(s, "abcde 42");
let mut buf = vec![];
to_writer_custom::<_, _, &str>(&values, &fmt, None, &settings, &mut buf).unwrap();
let s = String::from_utf8(buf).unwrap();
assert_eq!(s, "abcde 42\n");
let mut buf = vec![];
to_writer_custom::<_, _, &str>(&values, &fmt, Some(&["s", "n"]), &settings, &mut buf)
.unwrap();
let s = String::from_utf8(buf).unwrap();
assert_eq!(s, "abcde 42\n");
#[derive(Debug, serde::Serialize)]
struct Test3 {
#[serde(flatten)]
inner: Test2,
}
let values = Test3 { inner: values };
let s = to_string_custom::<_, &str>(&values, &fmt, None, &settings).unwrap();
assert_eq!(s, "abcde 42");
let s = to_string_custom::<_, &str>(&values, &fmt, Some(&["s", "n"]), &settings).unwrap();
assert_eq!(s, "abcde 42");
let mut buf = vec![];
to_writer_custom::<_, _, &str>(&values, &fmt, None, &settings, &mut buf).unwrap();
let s = String::from_utf8(buf).unwrap();
assert_eq!(s, "abcde 42\n");
let mut buf = vec![];
to_writer_custom::<_, _, &str>(&values, &fmt, Some(&["s", "n"]), &settings, &mut buf)
.unwrap();
let s = String::from_utf8(buf).unwrap();
assert_eq!(s, "abcde 42\n");
let hfmt = FortFormat::parse("(a8,a2)").unwrap();
let values =
HashMap::<_, _, std::hash::RandomState>::from_iter(vec![("s", "abcde"), ("n", "42")]);
let s = to_string_custom::<_, &str>(&values, &hfmt, Some(&["s", "n"]), &settings).unwrap();
assert_eq!(s, "abcde 42");
let mut buf = vec![];
to_writer_custom::<_, _, &str>(&values, &hfmt, Some(&["s", "n"]), &settings, &mut buf)
.unwrap();
let s = String::from_utf8(buf).unwrap();
assert_eq!(s, "abcde 42\n");
}
}