mirror of
https://github.com/redstrate/Physis.git
synced 2025-04-22 20:57:46 +00:00
141 lines
3.6 KiB
Rust
Executable file
141 lines
3.6 KiB
Rust
Executable file
// SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
use crate::{ByteBuffer, ByteSpan};
|
|
use std::io::{BufRead, BufReader, BufWriter, Cursor, Write};
|
|
|
|
/// 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)>,
|
|
}
|
|
|
|
impl EXL {
|
|
/// Initializes `EXL` from an existing list.
|
|
pub fn from_existing(buffer: ByteSpan) -> Option<EXL> {
|
|
let mut exl = Self {
|
|
version: 0,
|
|
entries: Vec::new(),
|
|
};
|
|
|
|
let cursor = Cursor::new(buffer);
|
|
let reader = BufReader::new(cursor);
|
|
|
|
for line in reader.lines().map_while(Result::ok) {
|
|
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
|
|
exl.entries.push((name.to_string(), parsed_value));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
|
|
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)
|
|
}
|
|
|
|
/// Checks whether or not the list contains a key.
|
|
///
|
|
/// # Example
|
|
///
|
|
/// ```
|
|
/// # use std::fs::read;
|
|
/// # use std::path::PathBuf;
|
|
/// # 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");
|
|
/// ```
|
|
pub fn contains(&self, key: &str) -> bool {
|
|
self.entries.iter().any(|t| t.0 == key)
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use std::fs::read;
|
|
use std::path::PathBuf;
|
|
|
|
use super::*;
|
|
|
|
fn common_setup() -> EXL {
|
|
let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
|
d.push("resources/tests");
|
|
d.push("test.exl");
|
|
|
|
EXL::from_existing(&read(d).unwrap()).unwrap()
|
|
}
|
|
|
|
#[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();
|
|
out.write_all(&existing_exl.write_to_buffer().unwrap())
|
|
.unwrap();
|
|
out.flush().unwrap();
|
|
|
|
assert_eq!(existing_exl.write_to_buffer().unwrap(), exl);
|
|
}
|
|
|
|
#[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());
|
|
}
|
|
}
|