use crate::error::TdmsError;
use crate::index::{DataFormat, Index};
use crate::io::data_types::TdmsStorageType;
use crate::io::writer::TdmsWriter;
use crate::meta_data::{MetaData, ObjectMetaData, Segment, ToC};
use crate::paths::ChannelPath;
use crate::raw_data::{MultiChannelSlice, WriteBlock};
use crate::{DataLayout, PropertyPath, PropertyValue};
use std::io::Write;
use std::num::NonZeroUsize;
pub struct TdmsFileWriter<'a, F: Write + 'a, W: TdmsWriter<&'a mut F>> {
index: &'a mut Index,
writer: W,
_file: std::marker::PhantomData<F>,
}
impl<'a, F: Write, W: TdmsWriter<&'a mut F>> TdmsFileWriter<'a, F, W> {
pub fn new(index: &'a mut Index, writer: W) -> Self {
Self {
index,
writer,
_file: std::marker::PhantomData,
}
}
pub fn write_channels<'b, D: TdmsStorageType, C: AsRef<ChannelPath>>(
&mut self,
channels: &'b [C],
values: &'b [D],
layout: DataLayout,
) -> Result<(), TdmsError> {
let stream = DataStreamWriter::new(self.index, &mut self.writer, channels, values, layout)?;
stream.end_stream()?;
Ok(())
}
pub fn write_properties(
&mut self,
path: &PropertyPath,
properties: &[(&str, PropertyValue)],
) -> Result<(), TdmsError> {
let path = path.path();
let properties = properties
.iter()
.map(|(name, value)| (name.to_string(), (*value).clone()))
.collect();
let object = ObjectMetaData {
path: path.to_string(),
properties,
raw_data_index: crate::meta_data::RawDataIndex::None,
};
let meta = MetaData {
objects: vec![object],
};
let segment =
self.writer
.write_segment(ToC::default(), Some(meta), Option::<&[u8]>::None)?;
self.index.add_segment(segment)?;
Ok(())
}
pub fn sync(&mut self) -> Result<(), TdmsError> {
self.writer.sync()
}
}
struct DataStreamWriter<'a, F: Write, W: TdmsWriter<F>> {
index: &'a mut Index,
writer: &'a mut W,
_file: std::marker::PhantomData<F>,
segment: Segment,
}
impl<'a, F: Write, W: TdmsWriter<F>> DataStreamWriter<'a, F, W> {
pub fn new<'b, C: AsRef<ChannelPath>, D: TdmsStorageType>(
index: &'a mut Index,
writer: &'a mut W,
channels: &'b [C],
values: &'b [D],
layout: DataLayout,
) -> Result<Self, TdmsError> {
let channel_count = NonZeroUsize::new(channels.len()).ok_or(TdmsError::NoChannels)?;
let raw_data = MultiChannelSlice::from_slice(values, channel_count)?;
let data_structures = raw_data
.data_structure()
.into_iter()
.map(DataFormat::RawData);
let channels = channels
.iter()
.map(|path| path.as_ref().path()) .zip(data_structures)
.collect();
let (matches_live, channels) = index.check_write_values(channels);
let meta = if matches_live {
None
} else {
let objects: Vec<ObjectMetaData> = channels
.into_iter()
.map(|(path, raw_index)| ObjectMetaData {
path: path.to_string(),
properties: vec![],
raw_data_index: raw_index,
})
.collect();
Some(MetaData { objects })
};
let toc = ToC {
contains_new_object_list: !matches_live,
data_is_interleaved: layout == DataLayout::Interleaved,
..Default::default()
};
let segment = writer.write_segment(toc, meta, Some(raw_data))?;
Ok(Self {
index,
writer,
_file: std::marker::PhantomData,
segment,
})
}
pub fn end_stream(self) -> Result<(), TdmsError> {
self.index.add_segment(self.segment)?;
Ok(())
}
}