1use crate::{TpmBuild, TpmErrorKind, TpmParse, TpmResult, TpmSized};
6use core::{
7 convert::TryFrom,
8 fmt::Debug,
9 mem::{size_of, MaybeUninit},
10 ops::Deref,
11 slice,
12};
13
14#[derive(Clone, Copy)]
16pub struct TpmList<T: Copy, const CAPACITY: usize> {
17 items: [MaybeUninit<T>; CAPACITY],
18 len: usize,
19}
20
21impl<T: Copy, const CAPACITY: usize> TpmList<T, CAPACITY> {
22 #[allow(unsafe_code)]
30 #[must_use]
31 pub fn new() -> Self {
32 Self {
33 items: unsafe { MaybeUninit::uninit().assume_init() },
34 len: 0,
35 }
36 }
37
38 #[must_use]
40 pub fn is_empty(&self) -> bool {
41 self.len == 0
42 }
43
44 pub fn try_push(&mut self, item: T) -> Result<(), TpmErrorKind> {
51 if self.len >= CAPACITY {
52 return Err(TpmErrorKind::CapacityExceeded);
53 }
54 self.items[self.len].write(item);
55 self.len += 1;
56 Ok(())
57 }
58}
59
60#[allow(unsafe_code)]
61impl<T: Copy, const CAPACITY: usize> Deref for TpmList<T, CAPACITY> {
62 type Target = [T];
63
64 fn deref(&self) -> &Self::Target {
71 unsafe { slice::from_raw_parts(self.items.as_ptr().cast::<T>(), self.len) }
72 }
73}
74
75impl<T: Copy, const CAPACITY: usize> Default for TpmList<T, CAPACITY> {
76 fn default() -> Self {
77 Self::new()
78 }
79}
80
81impl<T: Copy + Debug, const CAPACITY: usize> Debug for TpmList<T, CAPACITY> {
82 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
83 f.debug_list().entries(self.iter()).finish()
84 }
85}
86
87impl<T: Copy + PartialEq, const CAPACITY: usize> PartialEq for TpmList<T, CAPACITY> {
88 fn eq(&self, other: &Self) -> bool {
89 **self == **other
90 }
91}
92
93impl<T: Copy + Eq, const CAPACITY: usize> Eq for TpmList<T, CAPACITY> {}
94
95impl<T: TpmSized + Copy, const CAPACITY: usize> TpmSized for TpmList<T, CAPACITY> {
96 const SIZE: usize = size_of::<u32>() + (T::SIZE * CAPACITY);
97 fn len(&self) -> usize {
98 size_of::<u32>() + self.iter().map(TpmSized::len).sum::<usize>()
99 }
100}
101
102impl<T: TpmBuild + Copy, const CAPACITY: usize> TpmBuild for TpmList<T, CAPACITY> {
103 fn build(&self, writer: &mut crate::TpmWriter) -> TpmResult<()> {
104 let len_u32 = u32::try_from(self.len).map_err(|_| TpmErrorKind::ValueTooLarge)?;
105 TpmBuild::build(&len_u32, writer)?;
106 for item in &**self {
107 TpmBuild::build(item, writer)?;
108 }
109 Ok(())
110 }
111}
112
113impl<T: TpmParse + Copy, const CAPACITY: usize> TpmParse for TpmList<T, CAPACITY> {
114 fn parse(buf: &[u8]) -> TpmResult<(Self, &[u8])> {
115 let (count_u32, mut buf) = u32::parse(buf)?;
116 let count = count_u32 as usize;
117 if count > CAPACITY {
118 return Err(TpmErrorKind::ValueTooLarge);
119 }
120
121 let mut list = Self::new();
122 for _ in 0..count {
123 let (item, rest) = T::parse(buf)?;
124 list.try_push(item).map_err(|_| TpmErrorKind::Unreachable)?;
125 buf = rest;
126 }
127
128 Ok((list, buf))
129 }
130}