Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ smart-default = "0.6.0"
flate2 = { version = "1.0.24", optional = true}
bzip2 = { version = "0.4.3", optional = true}
zip = { version = "0.6.3", default-features = false, features = [ "deflate", "bzip2" ], optional = true }
chrono = { version = "0.4.22", optional = true}
chrono = { version = "0.4.31", optional = true}
hex = { version = "0.4.3", optional = true }
serde = { version = "1.0.147", features = ["derive"], optional = true}
struct-field-names-as-array = { version = "0.1.4", optional = true}
Expand Down
1 change: 0 additions & 1 deletion example/stdf_to_xlsx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

use rust_stdf::{stdf_file::*, stdf_record_type::*, StdfRecord};
use rust_xlsxwriter::{Workbook, Worksheet, XlsxError};
use serde_json;
Comment thread
noonchen marked this conversation as resolved.
use std::collections::HashMap;
use std::env;

Expand Down
2 changes: 1 addition & 1 deletion src/atdf_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ impl<R: BufRead + Seek> AtdfReader<R> {
}

#[inline(always)]
pub fn get_record_iter(&mut self) -> AtdfRecordIter<R> {
pub fn get_record_iter(&mut self) -> AtdfRecordIter<'_, R> {
AtdfRecordIter {
inner: self,
incomplete_rec: String::new(),
Expand Down
16 changes: 8 additions & 8 deletions src/atdf_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

use self::atdf_record_field::*;
use crate::{stdf_error::StdfError, stdf_record_type::*, *};
use chrono::NaiveDateTime;
use chrono::DateTime;
use std::collections::hash_map::HashMap;

macro_rules! ser_optional {
Expand Down Expand Up @@ -332,15 +332,15 @@ pub(crate) mod atdf_record_field {
pub struct AtdfRecord {
rec_name: String,
type_code: u64,
scale_flag: bool, // currently not used... maybe in the future
#[allow(dead_code)] // currently not used... maybe in the future
scale_flag: bool,
data_map: HashMap<String, String>,
}

impl From<&AtdfRecord> for StdfRecord {
#[inline(always)]
fn from(atdf_rec: &AtdfRecord) -> Self {
//TODO
if atdf_rec.scale_flag {}
StdfRecord::new(atdf_rec.type_code)
}
}
Expand Down Expand Up @@ -935,7 +935,7 @@ pub(crate) fn atdf_data_from_ftr(rec: &FTR) -> Vec<String> {
]
}

/// ignored because I do not know ATDF structure in V4-2007
// ignored because I do not know ATDF structure in V4-2007
// pub(crate) fn atdf_data_from_str_rec(rec: &STR) -> Vec<String> {
// vec![]}

Expand Down Expand Up @@ -1104,11 +1104,11 @@ pub(crate) fn atdf_data_from_mir(rec: &MIR) -> Vec<String> {
rec.job_nam.clone(), //JOB_NAM
rec.node_nam.clone(), //NODE_NAM
rec.tstr_typ.clone(), //TSTR_TYP
NaiveDateTime::from_timestamp_opt(rec.setup_t as i64, 0)
DateTime::from_timestamp(rec.setup_t as i64, 0)
.expect("invalid or out-of-range datetime")
.format("%H:%M:%S %d-%b-%Y")
.to_string(), //SETUP_T
NaiveDateTime::from_timestamp_opt(rec.start_t as i64, 0)
DateTime::from_timestamp(rec.start_t as i64, 0)
.expect("invalid or out-of-range datetime")
.format("%H:%M:%S %d-%b-%Y")
.to_string(), //START_T
Expand Down Expand Up @@ -1149,7 +1149,7 @@ pub(crate) fn atdf_data_from_mir(rec: &MIR) -> Vec<String> {
#[inline(always)]
pub(crate) fn atdf_data_from_mrr(rec: &MRR) -> Vec<String> {
vec![
NaiveDateTime::from_timestamp_opt(rec.finish_t as i64, 0)
DateTime::from_timestamp(rec.finish_t as i64, 0)
.expect("invalid or out-of-range datetime")
.format("%H:%M:%S %d-%b-%Y")
.to_string(), //FINISH_T
Expand Down Expand Up @@ -1373,7 +1373,7 @@ pub(crate) fn atdf_data_from_far(rec: &FAR) -> Vec<String> {
#[inline(always)]
pub(crate) fn atdf_data_from_atr(rec: &ATR) -> Vec<String> {
vec![
NaiveDateTime::from_timestamp_opt(rec.mod_tim as i64, 0)
DateTime::from_timestamp(rec.mod_tim as i64, 0)
.expect("invalid or out-of-range datetime")
.format("%H:%M:%S %d-%b-%Y")
.to_string(), // MOD_TIM
Expand Down
23 changes: 21 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,7 @@ mod tests {
);
assert_eq!(pos, 12);
assert_eq!(
vec!["".to_string(); 0],
Vec::<String>::new(),
stdf_types::read_kx_cn(&raw_data, &mut pos, 0)
);
}
Expand Down Expand Up @@ -679,7 +679,7 @@ mod tests {
);
assert_eq!(pos, 15);
assert_eq!(
vec!["".to_string(); 0],
Vec::<String>::new(),
stdf_types::read_kx_sn(&raw_data, &mut pos, &order, 0)
);
}
Expand Down Expand Up @@ -709,6 +709,14 @@ mod tests {
stdf_types::read_kx_cf(&raw_data, &mut pos, 4, 0)
);
assert_eq!(pos, 3);
// k == 0 returns an empty vec without moving the cursor.
// Start from a distinct pos to prove non-advancement.
let mut pos = 5;
assert_eq!(
Vec::<String>::new(),
stdf_types::read_kx_cf(&raw_data, &mut pos, 0, 0)
);
assert_eq!(pos, 5);
}

#[test]
Expand Down Expand Up @@ -887,6 +895,17 @@ mod tests {
#[cfg(feature = "atdf")]
use atdf_types::atdf_record_field::*;

#[cfg(feature = "atdf")]
#[test]
fn test_atdf_timestamp_is_utc() {
// A fixed UTC instant, non-midnight so a local-tz or zeroed-time
// regression would change the rendered string.
let mut rec = ATR::new();
rec.mod_tim = 1_000_000_000;
let fields = atdf_types::atdf_data_from_atr(&rec);
assert_eq!(fields[0], "01:46:40 09-Sep-2001"); // MOD_TIM
}

#[cfg(feature = "atdf")]
#[test]
fn test_atdf_fields_duplicate() {
Expand Down
17 changes: 12 additions & 5 deletions src/stdf_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ impl<R: BufRead + Seek> StdfReader<R> {
/// Only the records after the current file position
/// can be read.
#[inline(always)]
pub fn get_record_iter(&mut self) -> RecordIter<R> {
pub fn get_record_iter(&mut self) -> RecordIter<'_, R> {
RecordIter {
inner: self,
buffer: Vec::new(),
Expand All @@ -217,7 +217,7 @@ impl<R: BufRead + Seek> StdfReader<R> {
/// beware that internal `offset` counter is starting
/// from the current position.
#[inline(always)]
pub fn get_rawdata_iter(&mut self) -> RawDataIter<R> {
pub fn get_rawdata_iter(&mut self) -> RawDataIter<'_, R> {
RawDataIter {
offset: 0,
inner: self,
Expand All @@ -233,18 +233,25 @@ impl<R: BufRead + Seek> ZipBundle<R> {
let archive = ZipArchive::new(stream)?;
let mut archive = Box::new(archive);

let file =
unsafe { std::mem::transmute::<_, ZipFile<'static>>(archive.by_index(file_index)?) };
// SAFETY: fakes a 'static borrow of `archive`. Sound because `archive` is
// boxed (address stable across the move below), `file` drops before
// `archive` (whose Drop reads it), and `archive` is never aliased while
// `file` is alive (reopen_file clears `file` before re-borrowing).
let file = unsafe {
std::mem::transmute::<ZipFile<'_>, ZipFile<'static>>(archive.by_index(file_index)?)
};
Ok(ZipBundle {
archive,
file: Some(file),
})
}

pub(crate) fn reopen_file(&mut self, file_index: usize) -> Result<(), StdfError> {
// Drop the outstanding borrow before re-borrowing `archive`.
self.file = None;
// SAFETY: same invariants as `new`. `file` was just cleared above.
let file = unsafe {
std::mem::transmute::<_, ZipFile<'static>>(self.archive.by_index(file_index)?)
std::mem::transmute::<ZipFile<'_>, ZipFile<'static>>(self.archive.by_index(file_index)?)
};
self.file = Some(file);
Ok(())
Expand Down
46 changes: 19 additions & 27 deletions src/stdf_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2533,17 +2533,13 @@ macro_rules! read_multi_byte_num {
}

macro_rules! read_multi_element {
($count:expr, $default:expr, $func:ident($($arg:tt)+)) => {
($count:expr, $func:ident($($arg:tt)+)) => {
{
if $count != 0 {
let mut value = Vec::with_capacity($count as usize);
for _ in 0..$count {
value.push( $func($($arg)+) );
}
value
} else {
vec![$default; 0]
let mut value = Vec::with_capacity($count as usize);
for _ in 0..$count {
value.push( $func($($arg)+) );
}
value
}
}
}
Expand Down Expand Up @@ -2679,7 +2675,7 @@ pub(crate) fn read_bn(raw_data: &[u8], pos: &mut usize) -> Bn {
#[inline(always)]
pub(crate) fn read_dn(raw_data: &[u8], pos: &mut usize, order: &ByteOrder) -> Dn {
let bitcount = read_u2(raw_data, pos, order) as usize;
let bytecount = (bitcount + 7) / 8;
let bytecount = bitcount.div_ceil(8);
if bytecount != 0 {
let min_pos = std::cmp::min(*pos + bytecount, raw_data.len());
let data_slice = &raw_data[*pos..min_pos];
Expand All @@ -2695,51 +2691,47 @@ pub(crate) fn read_dn(raw_data: &[u8], pos: &mut usize, order: &ByteOrder) -> Dn
/// Read KxCn (Vec<Cn>) from byte array with offset "pos", vector size is provide by "k"
#[inline(always)]
pub(crate) fn read_kx_cn(raw_data: &[u8], pos: &mut usize, k: u16) -> KxCn {
read_multi_element!(k, String::new(), read_cn(raw_data, pos))
read_multi_element!(k, read_cn(raw_data, pos))
}

/// Read KxSn (Vec<Sn>) from byte array with offset "pos", vector size is provide by "k"
#[inline(always)]
pub(crate) fn read_kx_sn(raw_data: &[u8], pos: &mut usize, order: &ByteOrder, k: u16) -> KxSn {
read_multi_element!(k, String::new(), read_sn(raw_data, pos, order))
read_multi_element!(k, read_sn(raw_data, pos, order))
}

/// Read KxCf (Vec<Cf>) from byte array with offset "pos", vector size is provide by "k", String size is "f"
#[inline(always)]
pub(crate) fn read_kx_cf(raw_data: &[u8], pos: &mut usize, k: u16, f: u8) -> KxCf {
if k != 0 {
let mut value = Vec::with_capacity(k as usize);
for _ in 0..k {
value.push(read_cf(raw_data, pos, f));
}
value
} else {
vec!["".to_string(); 0]
let mut value = Vec::with_capacity(k as usize);
for _ in 0..k {
value.push(read_cf(raw_data, pos, f));
}
value
}

/// Read KxU1 (Vec<u8>) from byte array with offset "pos", vector size is provide by "k"
#[inline(always)]
pub(crate) fn read_kx_u1(raw_data: &[u8], pos: &mut usize, k: u16) -> KxU1 {
read_multi_element!(k, 0, read_uint8(raw_data, pos))
read_multi_element!(k, read_uint8(raw_data, pos))
}

/// Read KxU2 (Vec<u16>) from byte array with offset "pos", vector size is provide by "k"
#[inline(always)]
pub(crate) fn read_kx_u2(raw_data: &[u8], pos: &mut usize, order: &ByteOrder, k: u16) -> KxU2 {
read_multi_element!(k, 0, read_u2(raw_data, pos, order))
read_multi_element!(k, read_u2(raw_data, pos, order))
}

/// Read KxU4 (Vec<u32>) from byte array with offset "pos", vector size is provide by "k"
#[inline(always)]
pub(crate) fn read_kx_u4(raw_data: &[u8], pos: &mut usize, order: &ByteOrder, k: u16) -> KxU4 {
read_multi_element!(k, 0, read_u4(raw_data, pos, order))
read_multi_element!(k, read_u4(raw_data, pos, order))
}

/// Read KxU8 (Vec<u64>) from byte array with offset "pos", vector size is provide by "k"
#[inline(always)]
pub(crate) fn read_kx_u8(raw_data: &[u8], pos: &mut usize, order: &ByteOrder, k: u16) -> KxU8 {
read_multi_element!(k, 0, read_u8(raw_data, pos, order))
read_multi_element!(k, read_u8(raw_data, pos, order))
}

/// Read KxUf (Vec<u8|u16|u32|u64>) from byte array with offset "pos", vector size is provide by "k", size of number is "f"
Expand Down Expand Up @@ -2767,7 +2759,7 @@ pub(crate) fn read_kx_uf(
/// Read KxR4 (Vec<f32>) from byte array with offset "pos", vector size is provide by "k"
#[inline(always)]
pub(crate) fn read_kx_r4(raw_data: &[u8], pos: &mut usize, order: &ByteOrder, k: u16) -> KxR4 {
read_multi_element!(k, 0.0, read_r4(raw_data, pos, order))
read_multi_element!(k, read_r4(raw_data, pos, order))
}

/// Read KxN1 (Vec<u8>) from byte array with offset "pos", vector size is provide by "k"
Expand All @@ -2794,7 +2786,7 @@ pub(crate) fn read_kx_n1(raw_data: &[u8], pos: &mut usize, k: u16) -> KxN1 {
/// Read V1 (u8 + generic value) from byte array with offset "pos"
#[inline(always)]
pub(crate) fn read_v1(raw_data: &[u8], pos: &mut usize, order: &ByteOrder) -> V1 {
let type_byte = if (*pos as usize) < raw_data.len() {
let type_byte = if *pos < raw_data.len() {
read_uint8(raw_data, pos)
} else {
0xF
Expand All @@ -2821,7 +2813,7 @@ pub(crate) fn read_v1(raw_data: &[u8], pos: &mut usize, order: &ByteOrder) -> V1
/// Read Vn (Vec<V1>) from byte array with offset "pos", vector size is provide by "k"
#[inline(always)]
pub(crate) fn read_vn(raw_data: &[u8], pos: &mut usize, order: &ByteOrder, k: u16) -> Vn {
read_multi_element!(k, V1::Invalid, read_v1(raw_data, pos, order))
read_multi_element!(k, read_v1(raw_data, pos, order))
}

#[inline(always)]
Expand Down
26 changes: 10 additions & 16 deletions tests/record_serialize_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,10 @@ use serde_json::{self, json};
#[cfg(feature = "serialize")]
fn record_ser_test() {
// check upper case
match StdfRecord::new(REC_FAR) {
StdfRecord::FAR(r) => {
let json = serde_json::to_value(&r).unwrap();
assert_eq!(json["CPU_TYPE"], json!(0));
assert_eq!(json["cpu_type"], serde_json::Value::Null);
}
_ => {}
if let StdfRecord::FAR(r) = StdfRecord::new(REC_FAR) {
let json = serde_json::to_value(&r).unwrap();
assert_eq!(json["CPU_TYPE"], json!(0));
assert_eq!(json["cpu_type"], serde_json::Value::Null);
}

// check GDR
Expand All @@ -36,15 +33,12 @@ fn record_ser_test() {
V1::N1(8),
],
});
match gdr_rec {
StdfRecord::GDR(r) => {
let json = serde_json::to_value(&r).unwrap();
assert_eq!(json["FLD_CNT"], json!(3));
assert_eq!(json["GEN_DATA"][0]["Cn"], json!("test"));
assert_eq!(json["GEN_DATA"][1]["Bn"], json!(vec![1, 2, 3, 4, 5, 6, 7]));
assert_eq!(json["GEN_DATA"][2]["N1"], json!(8));
}
_ => {}
if let StdfRecord::GDR(r) = gdr_rec {
let json = serde_json::to_value(&r).unwrap();
assert_eq!(json["FLD_CNT"], json!(3));
assert_eq!(json["GEN_DATA"][0]["Cn"], json!("test"));
assert_eq!(json["GEN_DATA"][1]["Bn"], json!(vec![1, 2, 3, 4, 5, 6, 7]));
assert_eq!(json["GEN_DATA"][2]["N1"], json!(8));
}

// check fields names
Expand Down
12 changes: 6 additions & 6 deletions tests/stdf_file_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ use rust_stdf::{stdf_file::*, stdf_record_type::*, StdfRecord};
use std::{
fs::{self, read_dir},
io::{Read, Seek, SeekFrom},
path::PathBuf,
path::{Path, PathBuf},
};

fn get_test_stdf_files() -> Vec<PathBuf> {
let mut test_folder = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
test_folder.push("demo_stdf");

fn supported_ext(p: &PathBuf) -> bool {
fn supported_ext(p: &Path) -> bool {
let p = p.display().to_string();
let file_ext = p.rsplit('.').next();
match file_ext {
Expand All @@ -43,7 +43,7 @@ fn get_test_stdf_files() -> Vec<PathBuf> {
read_dir(test_folder)
.unwrap()
.map(|ent| ent.unwrap().path().to_path_buf())
.filter(supported_ext)
.filter(|p| supported_ext(p))
.collect::<Vec<PathBuf>>()
}

Expand All @@ -53,8 +53,8 @@ fn supported_stdf_file_test() {
assert_ne!(stdf_file_list.len(), 0);

for file in stdf_file_list.iter() {
let mut reader =
StdfReader::new(file).expect(&format!("error when open {}", file.display()));
let mut reader = StdfReader::new(file)
.unwrap_or_else(|e| panic!("error when open {}: {e}", file.display()));

let mut record_positions_list = Vec::with_capacity(2048);

Expand All @@ -69,7 +69,7 @@ fn supported_stdf_file_test() {
raw_rec.header.get_type(),
raw_rec.offset,
raw_rec.raw_data.len(),
raw_rec.byte_order.clone(),
raw_rec.byte_order,
));

if count != 0 {
Expand Down
Loading