hff_core/utilities/
string_vec.rs

1use crate::{
2    byteorder::{ByteOrder, ReadBytesExt, WriteBytesExt},
3    Ecc, Endian, Error, Result, BE, LE, NE,
4};
5use std::{
6    io::{Read, Write},
7    ops::{Deref, DerefMut},
8};
9
10/// A simple helper to store a vector of strings as a chunk
11/// or metadata within an hff file.
12#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
13pub struct StringVec {
14    /// The vector of strings.
15    strings: Vec<String>,
16}
17
18impl StringVec {
19    /// Ecc identifier type.
20    const ID: Ecc = Ecc::new("STR_VEC");
21
22    /// Create a new empty string vector.
23    pub fn new() -> Self {
24        Self { strings: vec![] }
25    }
26
27    /// Get the string vector as a byte vector
28    /// for storage.
29    pub fn to_bytes<E: ByteOrder>(self) -> Result<Vec<u8>> {
30        let mut bytes = vec![];
31        let writer: &mut dyn Write = &mut bytes;
32
33        Self::ID.write::<E>(writer)?;
34        writer.write_u64::<E>(self.strings.len() as u64)?;
35
36        for s in self.strings {
37            let b = s.as_bytes();
38            writer.write_u64::<E>(b.len() as u64)?;
39            writer.write_all(b)?;
40        }
41
42        Ok(bytes)
43    }
44
45    /// Make a string vector out of the given bytes.
46    pub fn from_bytes(mut bytes: &[u8]) -> Result<Self> {
47        // Detect the endian via the initial ID.
48        let reader: &mut dyn Read = &mut bytes;
49        // Ecc's are written as u64, so we read it back in
50        // native endian and see which endian it was actually
51        // in.  (NOTE: Symetric ID's would not work for this
52        // so don't try it if you had an id like "ssssssss"
53        // since there is no way to detect endianness.)
54        let id = Ecc::from(reader.read_u64::<NE>()?);
55        match id.endian(Self::ID) {
56            Some(endian) => match endian {
57                Endian::Big => Self::from_bytes_endian::<BE>(reader),
58                Endian::Little => Self::from_bytes_endian::<LE>(reader),
59            },
60            None => Err(Error::Invalid("Not a string vector.".into())),
61        }
62    }
63
64    /// Helper for from bytes which deals with endian.
65    fn from_bytes_endian<E: ByteOrder>(reader: &mut dyn Read) -> Result<Self> {
66        let count = reader.read_u64::<E>()?;
67
68        let mut strings = StringVec::new();
69        for _ in 0..count {
70            let len = reader.read_u64::<E>()?;
71            let mut s = vec![0; len as usize];
72            reader.read_exact(&mut s)?;
73            strings.push(std::str::from_utf8(&s)?.to_string());
74        }
75
76        Ok(strings)
77    }
78}
79
80impl<I, V> From<I> for StringVec
81where
82    I: Iterator<Item = V>,
83    V: AsRef<str>,
84{
85    fn from(value: I) -> Self {
86        Self {
87            strings: value.map(|s| s.as_ref().to_owned()).collect(),
88        }
89    }
90}
91
92impl Deref for StringVec {
93    type Target = Vec<String>;
94
95    fn deref(&self) -> &Self::Target {
96        &self.strings
97    }
98}
99
100impl DerefMut for StringVec {
101    fn deref_mut(&mut self) -> &mut Self::Target {
102        &mut self.strings
103    }
104}
105
106#[cfg(test)]
107mod tests {
108    use super::*;
109
110    #[test]
111    fn simple() {
112        let test_data = ["This", "is", "some", "test", "data."];
113        let strings: StringVec = test_data.clone().iter().into();
114        let bytes = strings.to_bytes::<LE>().unwrap();
115
116        let result = StringVec::from_bytes(&bytes).unwrap();
117        assert!(
118            test_data
119                .iter()
120                .zip(result.iter())
121                .map(|(l, r)| if l == r { 0 } else { 1 })
122                .sum::<usize>()
123                == 0
124        );
125    }
126}