1
Fork 0
mirror of https://github.com/redstrate/Physis.git synced 2025-04-23 05:07:46 +00:00
physis/src/exl.rs

142 lines
3.6 KiB
Rust
Raw Normal View History

// SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
// SPDX-License-Identifier: GPL-3.0-or-later
use crate::{ByteBuffer, ByteSpan};
2024-04-20 13:18:03 -04:00
use std::io::{BufRead, BufReader, BufWriter, Cursor, Write};
2022-07-19 19:29:41 -04:00
/// Represents an Excel List.
pub struct EXL {
/// The version of the list.
pub version: i32,
/// The entries of the list.
pub entries: Vec<(String, i32)>,
2022-07-19 19:29:41 -04:00
}
impl EXL {
/// Initializes `EXL` from an existing list.
pub fn from_existing(buffer: ByteSpan) -> Option<EXL> {
2022-07-19 19:29:41 -04:00
let mut exl = Self {
version: 0,
entries: Vec::new(),
2022-07-19 19:29:41 -04:00
};
2022-07-21 19:58:58 -04:00
let cursor = Cursor::new(buffer);
let reader = BufReader::new(cursor);
2022-07-19 19:29:41 -04:00
2024-04-20 13:17:11 -04:00
for line in reader.lines().map_while(Result::ok) {
2024-04-15 18:50:01 -04:00
if let Some((name, value)) = line.split_once(',') {
if let Ok(parsed_value) = value.parse() {
if name == "EXLT" {
exl.version = parsed_value;
} else if !name.starts_with('#') {
// Ignore rows with comments
2024-04-15 18:50:01 -04:00
exl.entries.push((name.to_string(), parsed_value));
}
}
2022-07-19 19:29:41 -04:00
}
}
Some(exl)
}
pub fn write_to_buffer(&self) -> Option<ByteBuffer> {
let mut buffer = ByteBuffer::new();
{
let cursor = Cursor::new(&mut buffer);
let mut writer = BufWriter::new(cursor);
2024-04-20 13:18:03 -04:00
writer
.write_all(format!("EXLT,{}", self.version).as_ref())
.ok()?;
for (key, value) in &self.entries {
writer.write_all(format!("\n{key},{value}").as_ref()).ok()?;
}
}
Some(buffer)
}
2022-07-19 19:29:41 -04:00
/// Checks whether or not the list contains a key.
///
/// # Example
///
/// ```
/// # use std::fs::read;
/// # use std::path::PathBuf;
2022-07-19 19:29:41 -04:00
/// # use physis::exl::EXL;
/// # let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
/// # d.push("resources/tests");
/// # d.push("test.exl");
/// # let exl_file = read(d).unwrap();
/// let exl = EXL::from_existing(&exl_file).unwrap();
/// exl.contains("Foo");
2022-07-19 19:29:41 -04:00
/// ```
pub fn contains(&self, key: &str) -> bool {
self.entries.iter().any(|t| t.0 == key)
2022-07-19 19:29:41 -04:00
}
}
#[cfg(test)]
mod tests {
2022-07-27 20:58:51 -04:00
use std::fs::read;
2022-07-19 19:29:41 -04:00
use std::path::PathBuf;
use super::*;
2022-07-19 19:29:41 -04:00
fn common_setup() -> EXL {
let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
d.push("resources/tests");
d.push("test.exl");
2022-07-27 20:58:51 -04:00
EXL::from_existing(&read(d).unwrap()).unwrap()
2022-07-19 19:29:41 -04:00
}
#[test]
fn version_parsing() {
let exl = common_setup();
assert_eq!(exl.version, 2);
}
#[test]
fn contains() {
let exl = common_setup();
assert!(exl.contains("Foo"));
// should be case-sensitive
assert!(!exl.contains("foo"));
}
#[test]
fn test_write() {
let existing_exl = common_setup();
let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
d.push("resources/tests");
d.push("test.exl");
let exl = read(d).unwrap();
let mut out = std::io::stdout();
2024-04-20 13:18:03 -04:00
out.write_all(&existing_exl.write_to_buffer().unwrap())
.unwrap();
2023-09-24 15:40:55 -04:00
out.flush().unwrap();
assert_eq!(existing_exl.write_to_buffer().unwrap(), exl);
}
2024-04-20 13:18:03 -04:00
2024-04-16 21:53:10 -04:00
#[test]
fn test_invalid() {
let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
d.push("resources/tests");
d.push("random");
// Feeding it invalid data should not panic
EXL::from_existing(&read(d).unwrap());
}
2022-08-16 11:52:07 -04:00
}