use crate::{UtilsError, UtilsResult};
use scirs2_core::ndarray::{Array1, Array2};
use std::collections::HashMap;
use std::fs::{File, OpenOptions};
use std::io::{BufRead, BufReader, BufWriter, Read, Write};
use std::path::Path;
pub struct EfficientFileReader {
reader: BufReader<File>,
#[allow(dead_code)]
buffer_size: usize,
}
impl EfficientFileReader {
pub fn new<P: AsRef<Path>>(path: P, buffer_size: Option<usize>) -> UtilsResult<Self> {
let file = File::open(path)
.map_err(|e| UtilsError::InvalidParameter(format!("Failed to open file: {e}")))?;
let buffer_size = buffer_size.unwrap_or(8192);
let reader = BufReader::with_capacity(buffer_size, file);
Ok(Self {
reader,
buffer_size,
})
}
pub fn read_lines(&mut self) -> impl Iterator<Item = UtilsResult<String>> + '_ {
std::io::BufRead::lines(&mut self.reader).map(|line| {
line.map_err(|e| UtilsError::InvalidParameter(format!("Failed to read line: {e}")))
})
}
pub fn read_chunk(&mut self, size: usize) -> UtilsResult<Vec<u8>> {
let mut buffer = vec![0u8; size];
let bytes_read = self
.reader
.read(&mut buffer)
.map_err(|e| UtilsError::InvalidParameter(format!("Failed to read chunk: {e}")))?;
buffer.truncate(bytes_read);
Ok(buffer)
}
pub fn read_all(&mut self) -> UtilsResult<Vec<u8>> {
let mut content = Vec::new();
self.reader
.read_to_end(&mut content)
.map_err(|e| UtilsError::InvalidParameter(format!("Failed to read file: {e}")))?;
Ok(content)
}
pub fn read_array1(&mut self, delimiter: &str) -> UtilsResult<Array1<f64>> {
let mut line = String::new();
self.reader
.read_line(&mut line)
.map_err(|e| UtilsError::InvalidParameter(format!("Failed to read line: {e}")))?;
let values: Result<Vec<f64>, _> = line
.trim()
.split(delimiter)
.filter(|s| !s.is_empty())
.map(|s| s.parse::<f64>())
.collect();
let values = values
.map_err(|e| UtilsError::InvalidParameter(format!("Failed to parse numbers: {e}")))?;
Ok(Array1::from_vec(values))
}
pub fn read_array2(&mut self, delimiter: &str) -> UtilsResult<Array2<f64>> {
let mut rows = Vec::new();
let mut line = String::new();
while self.reader.read_line(&mut line).unwrap_or(0) > 0 {
if line.trim().is_empty() {
line.clear();
continue;
}
let values: Result<Vec<f64>, _> = line
.trim()
.split(delimiter)
.filter(|s| !s.is_empty())
.map(|s| s.parse::<f64>())
.collect();
let values = values.map_err(|e| {
UtilsError::InvalidParameter(format!("Failed to parse numbers: {e}"))
})?;
rows.push(values);
line.clear();
}
if rows.is_empty() {
return Err(UtilsError::EmptyInput);
}
let ncols = rows[0].len();
let nrows = rows.len();
for row in &rows {
if row.len() != ncols {
return Err(UtilsError::ShapeMismatch {
expected: vec![ncols],
actual: vec![row.len()],
});
}
}
let flat: Vec<f64> = rows.into_iter().flatten().collect();
Array2::from_shape_vec((nrows, ncols), flat)
.map_err(|e| UtilsError::InvalidParameter(format!("Failed to create array: {e}")))
}
}
pub struct EfficientFileWriter {
writer: BufWriter<File>,
}
impl EfficientFileWriter {
pub fn new<P: AsRef<Path>>(path: P, buffer_size: Option<usize>) -> UtilsResult<Self> {
let file = OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(path)
.map_err(|e| UtilsError::InvalidParameter(format!("Failed to create file: {e}")))?;
let buffer_size = buffer_size.unwrap_or(8192);
let writer = BufWriter::with_capacity(buffer_size, file);
Ok(Self { writer })
}
pub fn append<P: AsRef<Path>>(path: P, buffer_size: Option<usize>) -> UtilsResult<Self> {
let file = OpenOptions::new()
.create(true)
.append(true)
.open(path)
.map_err(|e| UtilsError::InvalidParameter(format!("Failed to open file: {e}")))?;
let buffer_size = buffer_size.unwrap_or(8192);
let writer = BufWriter::with_capacity(buffer_size, file);
Ok(Self { writer })
}
pub fn write_data(&mut self, data: &[u8]) -> UtilsResult<()> {
self.writer
.write_all(data)
.map_err(|e| UtilsError::InvalidParameter(format!("Failed to write data: {e}")))?;
Ok(())
}
pub fn write_lines<I>(&mut self, lines: I) -> UtilsResult<()>
where
I: IntoIterator<Item = String>,
{
for line in lines {
writeln!(self.writer, "{line}")
.map_err(|e| UtilsError::InvalidParameter(format!("Failed to write line: {e}")))?;
}
Ok(())
}
pub fn write_array1(&mut self, array: &Array1<f64>, delimiter: &str) -> UtilsResult<()> {
let line = array
.iter()
.map(|x| x.to_string())
.collect::<Vec<_>>()
.join(delimiter);
writeln!(self.writer, "{line}")
.map_err(|e| UtilsError::InvalidParameter(format!("Failed to write array: {e}")))?;
Ok(())
}
pub fn write_array2(&mut self, array: &Array2<f64>, delimiter: &str) -> UtilsResult<()> {
for row in array.outer_iter() {
let line = row
.iter()
.map(|x| x.to_string())
.collect::<Vec<_>>()
.join(delimiter);
writeln!(self.writer, "{line}")
.map_err(|e| UtilsError::InvalidParameter(format!("Failed to write row: {e}")))?;
}
Ok(())
}
pub fn flush(&mut self) -> UtilsResult<()> {
self.writer
.flush()
.map_err(|e| UtilsError::InvalidParameter(format!("Failed to flush: {e}")))?;
Ok(())
}
}
pub struct CompressionUtils;
impl CompressionUtils {
#[cfg(feature = "compression")]
pub fn compress_gzip(data: &[u8]) -> UtilsResult<Vec<u8>> {
oxiarc_deflate::gzip_compress(data, 6)
.map_err(|e| UtilsError::InvalidParameter(format!("Compression failed: {e}")))
}
#[cfg(feature = "compression")]
pub fn decompress_gzip(data: &[u8]) -> UtilsResult<Vec<u8>> {
oxiarc_deflate::gzip_decompress(data)
.map_err(|e| UtilsError::InvalidParameter(format!("Decompression failed: {e}")))
}
pub fn run_length_encode(data: &[u8]) -> Vec<(u8, usize)> {
if data.is_empty() {
return Vec::new();
}
let mut result = Vec::new();
let mut current_value = data[0];
let mut count = 1;
for &byte in &data[1..] {
if byte == current_value {
count += 1;
} else {
result.push((current_value, count));
current_value = byte;
count = 1;
}
}
result.push((current_value, count));
result
}
pub fn run_length_decode(encoded: &[(u8, usize)]) -> Vec<u8> {
let mut result = Vec::new();
for &(value, count) in encoded {
result.extend(std::iter::repeat_n(value, count));
}
result
}
}
pub struct StreamProcessor<R: Read> {
reader: R,
chunk_size: usize,
}
impl<R: Read> StreamProcessor<R> {
pub fn new(reader: R, chunk_size: usize) -> Self {
Self { reader, chunk_size }
}
pub fn process_chunks<F>(&mut self, mut processor: F) -> UtilsResult<()>
where
F: FnMut(&[u8]) -> UtilsResult<()>,
{
let mut buffer = vec![0u8; self.chunk_size];
loop {
let bytes_read = self
.reader
.read(&mut buffer)
.map_err(|e| UtilsError::InvalidParameter(format!("Failed to read chunk: {e}")))?;
if bytes_read == 0 {
break;
}
processor(&buffer[..bytes_read])?;
}
Ok(())
}
pub fn process_lines<F>(&mut self, mut processor: F) -> UtilsResult<()>
where
F: FnMut(&str) -> UtilsResult<()>,
R: BufRead,
{
let mut line = String::new();
loop {
line.clear();
let bytes_read = self
.reader
.read_line(&mut line)
.map_err(|e| UtilsError::InvalidParameter(format!("Failed to read line: {e}")))?;
if bytes_read == 0 {
break;
}
processor(line.trim_end())?;
}
Ok(())
}
}
pub struct FormatConverter;
impl FormatConverter {
pub fn csv_to_arrays<P: AsRef<Path>>(
path: P,
delimiter: char,
has_header: bool,
) -> UtilsResult<(Option<Vec<String>>, Array2<f64>)> {
let mut reader = EfficientFileReader::new(path, None)?;
let mut lines = reader.read_lines();
let header = if has_header {
if let Some(line_result) = lines.next() {
let line = line_result?;
Some(
line.split(delimiter)
.map(|s| s.trim().to_string())
.collect(),
)
} else {
return Err(UtilsError::EmptyInput);
}
} else {
None
};
let mut rows = Vec::new();
for line_result in lines {
let line = line_result?;
if line.trim().is_empty() {
continue;
}
let values: Result<Vec<f64>, _> = line
.split(delimiter)
.map(|s| s.trim().parse::<f64>())
.collect();
let values = values.map_err(|e| {
UtilsError::InvalidParameter(format!("Failed to parse CSV values: {e}"))
})?;
rows.push(values);
}
if rows.is_empty() {
return Err(UtilsError::EmptyInput);
}
let ncols = rows[0].len();
let nrows = rows.len();
for row in &rows {
if row.len() != ncols {
return Err(UtilsError::ShapeMismatch {
expected: vec![ncols],
actual: vec![row.len()],
});
}
}
let flat: Vec<f64> = rows.into_iter().flatten().collect();
let array = Array2::from_shape_vec((nrows, ncols), flat)
.map_err(|e| UtilsError::InvalidParameter(format!("Failed to create array: {e}")))?;
Ok((header, array))
}
pub fn arrays_to_csv<P: AsRef<Path>>(
path: P,
data: &Array2<f64>,
header: Option<&[String]>,
delimiter: char,
) -> UtilsResult<()> {
let mut writer = EfficientFileWriter::new(path, None)?;
if let Some(header) = header {
let header_line = header.join(&delimiter.to_string());
writeln!(writer.writer, "{header_line}").map_err(|e| {
UtilsError::InvalidParameter(format!("Failed to write header: {e}"))
})?;
}
for row in data.outer_iter() {
let line = row
.iter()
.map(|x| x.to_string())
.collect::<Vec<_>>()
.join(&delimiter.to_string());
writeln!(writer.writer, "{line}")
.map_err(|e| UtilsError::InvalidParameter(format!("Failed to write row: {e}")))?;
}
writer.flush()?;
Ok(())
}
pub fn json_to_map(json_str: &str) -> UtilsResult<HashMap<String, serde_json::Value>> {
serde_json::from_str(json_str)
.map_err(|e| UtilsError::InvalidParameter(format!("Failed to parse JSON: {e}")))
}
pub fn map_to_json(map: &HashMap<String, serde_json::Value>) -> UtilsResult<String> {
serde_json::to_string_pretty(map)
.map_err(|e| UtilsError::InvalidParameter(format!("Failed to serialize JSON: {e}")))
}
#[cfg(feature = "yaml")]
pub fn yaml_to_map(yaml_str: &str) -> UtilsResult<HashMap<String, serde_json::Value>> {
let yaml_value: serde_yaml::Value = serde_yaml::from_str(yaml_str)
.map_err(|e| UtilsError::InvalidParameter(format!("Failed to parse YAML: {e}")))?;
let json_str = serde_json::to_string(&yaml_value).map_err(|e| {
UtilsError::InvalidParameter(format!("Failed to convert YAML to JSON: {e}"))
})?;
Self::json_to_map(&json_str)
}
#[cfg(feature = "yaml")]
pub fn map_to_yaml(map: &HashMap<String, serde_json::Value>) -> UtilsResult<String> {
serde_yaml::to_string(map)
.map_err(|e| UtilsError::InvalidParameter(format!("Failed to serialize YAML: {e}")))
}
#[cfg(feature = "toml_support")]
pub fn toml_to_map(toml_str: &str) -> UtilsResult<HashMap<String, serde_json::Value>> {
let toml_value: toml::Value = toml::from_str(toml_str)
.map_err(|e| UtilsError::InvalidParameter(format!("Failed to parse TOML: {e}")))?;
let json_str = serde_json::to_string(&toml_value).map_err(|e| {
UtilsError::InvalidParameter(format!("Failed to convert TOML to JSON: {e}"))
})?;
Self::json_to_map(&json_str)
}
#[cfg(feature = "toml_support")]
pub fn map_to_toml(map: &HashMap<String, serde_json::Value>) -> UtilsResult<String> {
let toml_value = serde_json::from_str::<toml::Value>(&serde_json::to_string(map)?)
.map_err(|e| {
UtilsError::InvalidParameter(format!("Failed to convert to TOML value: {e}"))
})?;
toml::to_string_pretty(&toml_value)
.map_err(|e| UtilsError::InvalidParameter(format!("Failed to serialize TOML: {e}")))
}
#[cfg(feature = "xml")]
pub fn xml_to_simple_map(xml_str: &str) -> UtilsResult<HashMap<String, String>> {
use quick_xml::escape::unescape;
use quick_xml::events::Event;
use quick_xml::Reader;
let mut reader = Reader::from_str(xml_str);
reader.config_mut().trim_text(true);
let mut result = HashMap::new();
let mut current_element = String::new();
let mut buf = Vec::new();
loop {
match reader.read_event_into(&mut buf) {
Ok(Event::Start(ref e)) => {
current_element = String::from_utf8_lossy(e.name().as_ref()).to_string();
}
Ok(Event::Text(e)) if !current_element.is_empty() => {
let raw_text = e.decode().map_err(|e| {
UtilsError::InvalidParameter(format!("Failed to decode XML text: {}", e))
})?;
let text = unescape(&raw_text).map_err(|e| {
UtilsError::InvalidParameter(format!("Failed to unescape XML text: {}", e))
})?;
result.insert(current_element.clone(), text.into_owned());
}
Ok(Event::Text(_)) => {
}
Ok(Event::End(_)) => {
current_element.clear();
}
Ok(Event::Eof) => break,
Err(e) => {
return Err(UtilsError::InvalidParameter(format!(
"Failed to parse XML: {}",
e
)));
}
_ => {}
}
buf.clear();
}
Ok(result)
}
#[cfg(feature = "xml")]
pub fn simple_map_to_xml(
map: &HashMap<String, String>,
root_name: &str,
) -> UtilsResult<String> {
use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event};
use quick_xml::Writer;
use std::io::Cursor;
let mut writer = Writer::new(Cursor::new(Vec::new()));
writer
.write_event(Event::Decl(quick_xml::events::BytesDecl::new(
"1.0",
Some("UTF-8"),
None,
)))
.map_err(|e| {
UtilsError::InvalidParameter(format!("Failed to write XML declaration: {e}"))
})?;
writer
.write_event(Event::Start(BytesStart::new(root_name)))
.map_err(|e| {
UtilsError::InvalidParameter(format!("Failed to write root element: {e}"))
})?;
for (key, value) in map {
writer
.write_event(Event::Start(BytesStart::new(key)))
.map_err(|e| {
UtilsError::InvalidParameter(format!("Failed to write element start: {e}"))
})?;
writer
.write_event(Event::Text(BytesText::new(value)))
.map_err(|e| UtilsError::InvalidParameter(format!("Failed to write text: {e}")))?;
writer
.write_event(Event::End(BytesEnd::new(key)))
.map_err(|e| {
UtilsError::InvalidParameter(format!("Failed to write element end: {e}"))
})?;
}
writer
.write_event(Event::End(BytesEnd::new(root_name)))
.map_err(|e| UtilsError::InvalidParameter(format!("Failed to write root end: {e}")))?;
let result = writer.into_inner().into_inner();
String::from_utf8(result).map_err(|e| {
UtilsError::InvalidParameter(format!("Failed to convert XML to string: {e}"))
})
}
pub fn json_to_arrays(json_str: &str) -> UtilsResult<HashMap<String, Array2<f64>>> {
let data: HashMap<String, Vec<Vec<f64>>> = serde_json::from_str(json_str).map_err(|e| {
UtilsError::InvalidParameter(format!("Failed to parse JSON arrays: {e}"))
})?;
let mut result = HashMap::new();
for (key, matrix) in data {
if matrix.is_empty() {
continue;
}
let nrows = matrix.len();
let ncols = matrix[0].len();
for row in matrix.iter() {
if row.len() != ncols {
return Err(UtilsError::ShapeMismatch {
expected: vec![ncols],
actual: vec![row.len()],
});
}
}
let flat: Vec<f64> = matrix.into_iter().flatten().collect();
let array = Array2::from_shape_vec((nrows, ncols), flat).map_err(|e| {
UtilsError::InvalidParameter(format!("Failed to create array: {e}"))
})?;
result.insert(key, array);
}
Ok(result)
}
pub fn arrays_to_json(arrays: &HashMap<String, &Array2<f64>>) -> UtilsResult<String> {
let mut data = HashMap::new();
for (key, array) in arrays {
let matrix: Vec<Vec<f64>> = array.outer_iter().map(|row| row.to_vec()).collect();
data.insert(key.clone(), matrix);
}
serde_json::to_string_pretty(&data).map_err(|e| {
UtilsError::InvalidParameter(format!("Failed to serialize arrays to JSON: {e}"))
})
}
}
pub struct SerializationUtils;
impl SerializationUtils {
pub fn serialize_array2(array: &Array2<f64>) -> UtilsResult<Vec<u8>> {
let shape = array.shape();
let mut data = Vec::new();
data.extend_from_slice(&(shape[0] as u64).to_le_bytes());
data.extend_from_slice(&(shape[1] as u64).to_le_bytes());
for &value in array.iter() {
data.extend_from_slice(&value.to_le_bytes());
}
Ok(data)
}
pub fn deserialize_array2(data: &[u8]) -> UtilsResult<Array2<f64>> {
if data.len() < 16 {
return Err(UtilsError::InvalidParameter(
"Insufficient data for array header".to_string(),
));
}
let nrows = u64::from_le_bytes([
data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
]) as usize;
let ncols = u64::from_le_bytes([
data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15],
]) as usize;
let expected_len = 16 + nrows * ncols * 8;
if data.len() != expected_len {
return Err(UtilsError::InvalidParameter(format!(
"Data length mismatch: expected {}, got {}",
expected_len,
data.len()
)));
}
let mut values = Vec::with_capacity(nrows * ncols);
for i in 0..(nrows * ncols) {
let start = 16 + i * 8;
let bytes = [
data[start],
data[start + 1],
data[start + 2],
data[start + 3],
data[start + 4],
data[start + 5],
data[start + 6],
data[start + 7],
];
values.push(f64::from_le_bytes(bytes));
}
Array2::from_shape_vec((nrows, ncols), values)
.map_err(|e| UtilsError::InvalidParameter(format!("Failed to create array: {e}")))
}
pub fn serialize_to_file<P: AsRef<Path>>(path: P, array: &Array2<f64>) -> UtilsResult<()> {
let data = Self::serialize_array2(array)?;
let mut writer = EfficientFileWriter::new(path, None)?;
writer.write_data(&data)?;
writer.flush()?;
Ok(())
}
pub fn deserialize_from_file<P: AsRef<Path>>(path: P) -> UtilsResult<Array2<f64>> {
let mut reader = EfficientFileReader::new(path, None)?;
let data = reader.read_all()?;
Self::deserialize_array2(&data)
}
}
#[allow(non_snake_case)]
#[cfg(test)]
mod tests {
use super::*;
use std::io::Cursor;
use tempfile::NamedTempFile;
#[test]
fn test_efficient_file_reader_writer() {
let temp_file = NamedTempFile::new().expect("operation should succeed");
let path = temp_file.path();
let mut writer = EfficientFileWriter::new(path, None).expect("operation should succeed");
writer
.write_lines(vec!["line1".to_string(), "line2".to_string()])
.expect("operation should succeed");
writer.flush().expect("operation should succeed");
drop(writer);
let mut reader = EfficientFileReader::new(path, None).expect("operation should succeed");
let lines: Result<Vec<_>, _> = reader.read_lines().collect();
let lines = lines.expect("operation should succeed");
assert_eq!(lines.len(), 2);
assert_eq!(lines[0], "line1");
assert_eq!(lines[1], "line2");
}
#[test]
fn test_array_io() {
let temp_file = NamedTempFile::new().expect("operation should succeed");
let path = temp_file.path();
let original = Array2::from_shape_vec((2, 3), vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0])
.expect("operation should succeed");
FormatConverter::arrays_to_csv(path, &original, None, ',')
.expect("operation should succeed");
let (header, loaded) =
FormatConverter::csv_to_arrays(path, ',', false).expect("operation should succeed");
assert!(header.is_none());
assert_eq!(original.shape(), loaded.shape());
assert!((original - loaded).mapv(f64::abs).sum() < 1e-10);
}
#[test]
fn test_serialization() {
let original = Array2::from_shape_vec((2, 3), vec![1.1, 2.2, 3.3, 4.4, 5.5, 6.6])
.expect("operation should succeed");
let serialized =
SerializationUtils::serialize_array2(&original).expect("operation should succeed");
let deserialized =
SerializationUtils::deserialize_array2(&serialized).expect("operation should succeed");
assert_eq!(original.shape(), deserialized.shape());
assert!((original - deserialized).mapv(f64::abs).sum() < 1e-10);
}
#[test]
fn test_compression() {
let data = b"Hello, World! This is a test string for compression.";
let encoded = CompressionUtils::run_length_encode(data);
let decoded = CompressionUtils::run_length_decode(&encoded);
assert_eq!(data.to_vec(), decoded);
}
#[test]
fn test_stream_processor() {
let data = b"chunk1chunk2chunk3";
let cursor = Cursor::new(data);
let mut processor = StreamProcessor::new(cursor, 6);
let mut chunks = Vec::new();
processor
.process_chunks(|chunk| {
chunks.push(chunk.to_vec());
Ok(())
})
.expect("operation should succeed");
assert_eq!(chunks.len(), 3);
assert_eq!(&chunks[0], b"chunk1");
assert_eq!(&chunks[1], b"chunk2");
assert_eq!(&chunks[2], b"chunk3");
}
#[test]
fn test_format_conversion() {
let temp_file = NamedTempFile::new().expect("operation should succeed");
let path = temp_file.path();
std::fs::write(path, "age,score\n25,95.5\n30,87.2").expect("operation should succeed");
let (header, data) =
FormatConverter::csv_to_arrays(path, ',', true).expect("operation should succeed");
assert!(header.is_some());
let header = header.expect("operation should succeed");
assert_eq!(header, vec!["age", "score"]);
assert_eq!(data.shape(), &[2, 2]);
assert!((data[[0, 0]] - 25.0).abs() < 1e-10);
assert!((data[[0, 1]] - 95.5).abs() < 1e-10);
assert!((data[[1, 0]] - 30.0).abs() < 1e-10);
assert!((data[[1, 1]] - 87.2).abs() < 1e-10);
}
#[test]
fn test_enhanced_json_arrays() {
let json_data = r#"
{
"features": [[1.0, 2.0], [3.0, 4.0]],
"targets": [[5.0], [6.0]]
}"#;
let arrays = FormatConverter::json_to_arrays(json_data).expect("operation should succeed");
assert_eq!(arrays.len(), 2);
assert!(arrays.contains_key("features"));
assert!(arrays.contains_key("targets"));
let features = &arrays["features"];
assert_eq!(features.shape(), &[2, 2]);
assert!((features[[0, 0]] - 1.0).abs() < 1e-10);
assert!((features[[1, 1]] - 4.0).abs() < 1e-10);
let mut array_refs = HashMap::new();
array_refs.insert("features".to_string(), features);
let json_result =
FormatConverter::arrays_to_json(&array_refs).expect("operation should succeed");
assert!(json_result.contains("features"));
assert!(json_result.contains("1.0"));
}
#[test]
#[cfg(feature = "yaml")]
fn test_yaml_conversion() {
let yaml_data = r#"
name: test
value: 42
nested:
key: "hello"
"#;
let map = FormatConverter::yaml_to_map(yaml_data).expect("operation should succeed");
assert!(map.contains_key("name"));
assert!(map.contains_key("value"));
let yaml_result = FormatConverter::map_to_yaml(&map).expect("operation should succeed");
assert!(yaml_result.contains("name"));
assert!(yaml_result.contains("42"));
}
#[test]
#[cfg(feature = "toml_support")]
fn test_toml_conversion() {
let toml_data = r#"
name = "test"
value = 42
[nested]
key = "hello"
"#;
let map = FormatConverter::toml_to_map(toml_data).expect("operation should succeed");
assert!(map.contains_key("name"));
assert!(map.contains_key("value"));
let toml_result = FormatConverter::map_to_toml(&map).expect("operation should succeed");
assert!(toml_result.contains("name"));
assert!(toml_result.contains("42"));
}
#[test]
#[cfg(feature = "xml")]
fn test_xml_conversion() {
let xml_data = r#"<?xml version="1.0" encoding="UTF-8"?>
<root>
<name>test</name>
<value>42</value>
</root>"#;
let map = FormatConverter::xml_to_simple_map(xml_data).expect("operation should succeed");
assert!(map.contains_key("name"));
assert!(map.contains_key("value"));
assert_eq!(map["name"], "test");
assert_eq!(map["value"], "42");
let xml_result =
FormatConverter::simple_map_to_xml(&map, "root").expect("operation should succeed");
assert!(xml_result.contains("<name>test</name>"));
assert!(xml_result.contains("<value>42</value>"));
}
}