use crate::error::{Error, Result};
use crate::writer::Writer;
pub type Guid = [u8; 16];
#[derive(Debug, Clone, Default)]
pub struct GuidHeap {
data: Vec<u8>,
}
impl GuidHeap {
#[must_use]
pub fn new() -> Self {
Self { data: Vec::new() }
}
#[must_use]
pub fn parse(data: &[u8]) -> Self {
Self {
data: data.to_vec(),
}
}
pub fn get(&self, index: u32) -> Result<Guid> {
if index == 0 {
return Ok([0u8; 16]);
}
let offset = ((index - 1) as usize) * 16;
if offset + 16 > self.data.len() {
return Err(Error::InvalidGuidIndex(index));
}
let mut guid = [0u8; 16];
guid.copy_from_slice(&self.data[offset..offset + 16]);
Ok(guid)
}
pub fn add(&mut self, guid: &Guid) -> u32 {
let index = (self.data.len() / 16) + 1;
self.data.extend_from_slice(guid);
index as u32
}
#[must_use]
pub fn count(&self) -> usize {
self.data.len() / 16
}
#[must_use]
pub fn data(&self) -> &[u8] {
&self.data
}
#[must_use]
pub fn size(&self) -> usize {
self.data.len()
}
#[must_use]
pub fn uses_wide_indices(&self) -> bool {
self.count() > 0xFFFF
}
pub fn write_to(&self, writer: &mut Writer) {
writer.write_bytes(&self.data);
}
#[must_use]
pub fn write(&self) -> Vec<u8> {
self.data.clone()
}
pub fn iter(&self) -> GuidIter<'_> {
GuidIter {
chunks: self.data.chunks_exact(16),
index: 1,
}
}
}
pub struct GuidIter<'a> {
chunks: std::slice::ChunksExact<'a, u8>,
index: u32,
}
impl Iterator for GuidIter<'_> {
type Item = (u32, Guid);
fn next(&mut self) -> Option<Self::Item> {
self.chunks.next().map(|chunk| {
let mut guid = [0u8; 16];
guid.copy_from_slice(chunk);
let idx = self.index;
self.index += 1;
(idx, guid)
})
}
}
impl<'a> IntoIterator for &'a GuidHeap {
type Item = (u32, Guid);
type IntoIter = GuidIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
#[must_use]
pub fn format_guid(guid: &Guid) -> String {
format!(
"{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
guid[3],
guid[2],
guid[1],
guid[0], guid[5],
guid[4], guid[7],
guid[6], guid[8],
guid[9], guid[10],
guid[11],
guid[12],
guid[13],
guid[14],
guid[15] )
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_heap_is_empty() {
let heap = GuidHeap::new();
assert_eq!(heap.count(), 0);
}
#[test]
fn test_null_guid_index() {
let heap = GuidHeap::new();
let guid = heap.get(0).unwrap();
assert_eq!(guid, [0u8; 16]);
}
#[test]
fn test_add_and_get_guid() {
let mut heap = GuidHeap::new();
let guid: Guid = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
let index = heap.add(&guid);
assert_eq!(index, 1); assert_eq!(heap.get(index).unwrap(), guid);
}
#[test]
fn test_parse_heap() {
let data: [u8; 32] = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, ];
let heap = GuidHeap::parse(&data);
assert_eq!(heap.count(), 2);
assert_eq!(
heap.get(1).unwrap(),
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
);
assert_eq!(
heap.get(2).unwrap(),
[
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32
]
);
}
#[test]
fn test_format_guid() {
let guid: Guid = [
0x00, 0x84, 0x0e, 0x55, 0x9b, 0xe2, 0xd4, 0x41, 0xa7, 0x16, 0x44, 0x66, 0x55, 0x44, 0x00, 0x00, ];
let formatted = format_guid(&guid);
assert_eq!(formatted, "550e8400-e29b-41d4-a716-446655440000");
}
#[test]
fn test_iter() {
let data: [u8; 32] = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31, 32,
];
let heap = GuidHeap::parse(&data);
let guids: Vec<_> = heap.iter().collect();
assert_eq!(guids.len(), 2);
assert_eq!(guids[0].0, 1); assert_eq!(guids[1].0, 2);
}
}