Skip to content
Draft
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
*.aliases
*.lvlps
*.tdms_index
*.log
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ homepage = "https://github.com/WiresmithTech/tedium"
repository = "https://github.com/WiresmithTech/tedium"
description = "A fast and easy TDMS Library for Rust"
keywords = ["labview", "ni", "tdms"]
readme = ".\\README.md"
readme = "README.md"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

Expand Down
29 changes: 28 additions & 1 deletion src/file/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use std::{
};

use crate::meta_data::Segment;
use crate::{error::TdmsError, PropertyPath, PropertyValue};
use crate::{DataType, error::TdmsError, PropertyPath, PropertyValue};
use crate::{index::Index, ChannelPath};
use crate::{
io::writer::{LittleEndianWriter, TdmsWriter},
Expand Down Expand Up @@ -149,6 +149,15 @@ impl<F: Read + Seek> TdmsFile<F> {
let paths = self.index.paths_starting_with(group.path());
paths.filter_map(|path| ChannelPath::try_from(path).ok())
}

pub fn get_channel_type(&self, channel: &ChannelPath) -> Option<DataType> {
let data_type = self.index.channel_type(channel);
if let Some(data_type) = data_type {
Some(*data_type)
} else {
None
}
}
}

impl<F: Write + Read + Seek> TdmsFile<F> {
Expand Down Expand Up @@ -339,4 +348,22 @@ mod tests {
.collect();
assert_eq!(channels.len(), 0);
}

#[test]
fn test_get_channel_type() {
let mut file = new_empty_file();

let mut writer = file.writer().unwrap();
writer
.write_channels(
&[ChannelPath::new("group", "channel")],
&[1.0, 2.0, 3.0, 4.0, 5.0, 6.0],
DataLayout::Interleaved,
)
.unwrap();

drop(writer);
let channel_type = file.get_channel_type(&ChannelPath::new("group", "channel")).unwrap();
assert_eq!(channel_type, DataType::DoubleFloat);
}
}
19 changes: 18 additions & 1 deletion src/index/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::error::TdmsError;
use crate::meta_data::{ObjectMetaData, RawDataIndex, RawDataMeta};
use crate::paths::{ChannelPath, PropertyPath};
use crate::raw_data::DataBlock;
use crate::PropertyValue;
use crate::{DataType, PropertyValue};

/// A store for a given channel point to the data block with its data and the index within that.
#[derive(Debug, Clone, PartialEq, Eq)]
Expand Down Expand Up @@ -173,6 +173,23 @@ impl Index {
pub fn get_data_block(&self, index: usize) -> Option<&DataBlock> {
self.data_blocks.get(index)
}

// Get the data type for the given channel.
///
/// Returns None if the channel does not exist.
pub fn channel_type(&self, path: &ChannelPath) -> Option<&DataType> {
self.objects
.get(path.path())
.and_then(|object| {
object
.latest_data_format
.as_ref()
.and_then(|format| match format {
DataFormat::RawData(meta) => Some(&meta.data_type),
})
})
}

}

#[cfg(test)]
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ mod raw_data;
pub use error::TdmsError;
pub use file::TdmsFile;
pub use file::TdmsFileWriter;
pub use io::data_types::TdmsStorageType;
pub use io::data_types::{TdmsStorageType, DataType};
pub use paths::{ChannelPath, PropertyPath};
pub use properties::PropertyValue;
pub use raw_data::DataLayout;
Expand Down
138 changes: 138 additions & 0 deletions tests/defragment.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
mod common;
use tedium::{ChannelPath, PropertyPath, PropertyValue, TdmsFile, DataType, TdmsFileWriter};
use std::{
fs::File,
io::{Read, Seek, SeekFrom, Write},
path::Path,
};


#[test]
fn test_defragment() {
// get the test file
let mut input_file = common::open_test_file();

// create a new tdms file for our defragmented output
let path = std::path::Path::new("tests/test_defragment_output.tdms");
let mut output_file = TdmsFile::create(path).unwrap();

// get the properties of the input file and write them to the properties of the output file
let mut all_properties = input_file.read_all_properties(&PropertyPath::file()).unwrap();

let mut writer = output_file.writer().unwrap();

// convert all_properties to a `&[(&str, PropertyValue)]` we can pass to the writer.write_properties method
let mut properties: Vec<(&str, PropertyValue)> = Vec::new();
for (key, value) in all_properties.iter() {
let property = value.clone();
properties.push((key.as_str(), property.clone()));
}

writer.write_properties(&PropertyPath::file(), &properties).unwrap();

// First, collect all group names
let groups: Vec<PropertyPath> = input_file.list_groups().into_iter().collect();

// print the number of groups
println!("num groups: {:?}", groups.len());

// Then iterate over the collected group names
for group_path in groups {

println!("==== GROUP BEGIN =====");

// print the group path
println!("group_path: {:?}", group_path);

// Collect channel names for each group before mutating `input_file`
let channels: Vec<ChannelPath> = input_file.list_channels_in_group(&group_path).into_iter().collect();

// print the number of channels
println!("num channels: {:?}", channels.len());

for channel_path in channels {

println!("---- CHANNEL BEGIN ----");

// print the channel path
println!("channel_path: {:?}", channel_path);

// #todo: refactor this into a `copy_channel()` function

let channel_length = input_file.channel_length(&channel_path).unwrap();

// print the channel length
println!("channel_length: {:?}", channel_length);


// print the channel type
let channel_type = input_file.get_channel_type(&channel_path);
match channel_type {
Some(t) => println!("channel_type: {:?}", t),
None => println!("channel_type: None"),
}

let channel_type = input_file.get_channel_type(&channel_path);

match channel_type {

Some(DataType::SingleFloat) => {
let mut data: Vec<f32> = vec![0.0; channel_length as usize];
input_file.read_channel(&channel_path, &mut data).unwrap();
writer.write_channels(&[channel_path], &data, tedium::DataLayout::Interleaved).unwrap();
},
Some(DataType::DoubleFloat) => {
let mut data: Vec<f64> = vec![0.0; channel_length as usize];
input_file.read_channel(&channel_path, &mut data).unwrap();
writer.write_channels(&[channel_path], &data, tedium::DataLayout::Interleaved).unwrap();
},
Some(DataType::I8) => {
let mut data: Vec<i8> = vec![0; channel_length as usize];
input_file.read_channel(&channel_path, &mut data).unwrap();
writer.write_channels(&[channel_path], &data, tedium::DataLayout::Interleaved).unwrap();
},
Some(DataType::I16) => {
let mut data: Vec<i16> = vec![0; channel_length as usize];
input_file.read_channel(&channel_path, &mut data).unwrap();
writer.write_channels(&[channel_path], &data, tedium::DataLayout::Interleaved).unwrap();
},
Some(DataType::I32) => {
let mut data: Vec<i32> = vec![0; channel_length as usize];
input_file.read_channel(&channel_path, &mut data).unwrap();
writer.write_channels(&[channel_path], &data, tedium::DataLayout::Interleaved).unwrap();
},
Some(DataType::I64) => {
let mut data: Vec<i64> = vec![0; channel_length as usize];
input_file.read_channel(&channel_path, &mut data).unwrap();
writer.write_channels(&[channel_path], &data, tedium::DataLayout::Interleaved).unwrap();
},
Some(DataType::U8) => {
let mut data: Vec<u8> = vec![0; channel_length as usize];
input_file.read_channel(&channel_path, &mut data).unwrap();
writer.write_channels(&[channel_path], &data, tedium::DataLayout::Interleaved).unwrap();
},
Some(DataType::U16) => {
let mut data: Vec<u16> = vec![0; channel_length as usize];
},
Some(DataType::U32) => {
let mut data: Vec<u32> = vec![0; channel_length as usize];
input_file.read_channel(&channel_path, &mut data).unwrap();
writer.write_channels(&[channel_path], &data, tedium::DataLayout::Interleaved).unwrap();
},
Some(DataType::U64) => {
let mut data: Vec<u64> = vec![0; channel_length as usize];
input_file.read_channel(&channel_path, &mut data).unwrap();
writer.write_channels(&[channel_path], &data, tedium::DataLayout::Interleaved).unwrap();
},
Some(data_type) => println!("Unsupported data type: {}", data_type),
None => println!("None"),
}

println!("---- CHANNEL END ----");

};
println!("==== GROUP END =====");
}


}
Binary file added tests/test_defragment.tdms
Binary file not shown.
2 changes: 1 addition & 1 deletion tests/write_properties.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ fn write_properties<F: Write + Read + Seek + Debug>(file: &mut TdmsFile<F>, path
let mut writer = file.writer().unwrap();
writer.write_properties(path, TEST_PROPERTIES).unwrap();

//this one wont exist as a constant.
//this one won't exist as a constant.
writer
.write_properties(
&path,
Expand Down