tpm2_protocol/
list.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2// Copyright (c) 2025 Opinsys Oy
3// Copyright (c) 2024-2025 Jarkko Sakkinen
4
5use crate::{TpmBuild, TpmErrorKind, TpmParse, TpmResult, TpmSized};
6use core::{convert::TryFrom, mem::size_of, ops::Deref};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub struct TpmList<T: Copy + Default, const CAPACITY: usize> {
10    items: [T; CAPACITY],
11    len: usize,
12}
13
14impl<T: Copy + Default, const CAPACITY: usize> TpmList<T, CAPACITY> {
15    #[must_use]
16    pub fn new() -> Self {
17        Self {
18            items: [T::default(); CAPACITY],
19            len: 0,
20        }
21    }
22
23    /// Returns `true` if the list contains no elements.
24    #[must_use]
25    pub fn is_empty(&self) -> bool {
26        self.len == 0
27    }
28
29    /// Appends an element to the back of the list.
30    ///
31    /// # Errors
32    ///
33    /// Returns a `TpmErrorKind::CapacityExceeded` error if the list is already at
34    /// full capacity.
35    pub fn try_push(&mut self, item: T) -> Result<(), TpmErrorKind> {
36        if self.len >= CAPACITY {
37            return Err(TpmErrorKind::CapacityExceeded);
38        }
39        self.items[self.len] = item;
40        self.len += 1;
41        Ok(())
42    }
43}
44
45impl<T: Copy + Default, const CAPACITY: usize> Deref for TpmList<T, CAPACITY> {
46    type Target = [T];
47
48    fn deref(&self) -> &Self::Target {
49        &self.items[..self.len]
50    }
51}
52
53impl<T: Copy + Default, const CAPACITY: usize> Default for TpmList<T, CAPACITY> {
54    fn default() -> Self {
55        Self::new()
56    }
57}
58
59impl<T: TpmSized + Copy + Default, const CAPACITY: usize> TpmSized for TpmList<T, CAPACITY> {
60    const SIZE: usize = size_of::<u32>() + (T::SIZE * CAPACITY);
61    fn len(&self) -> usize {
62        size_of::<u32>() + self.iter().map(TpmSized::len).sum::<usize>()
63    }
64}
65
66impl<T: TpmBuild + Copy + Default, const CAPACITY: usize> TpmBuild for TpmList<T, CAPACITY> {
67    fn build(&self, writer: &mut crate::TpmWriter) -> TpmResult<()> {
68        let len_u32 = u32::try_from(self.len).map_err(|_| TpmErrorKind::ValueTooLarge)?;
69        TpmBuild::build(&len_u32, writer)?;
70        for item in &**self {
71            TpmBuild::build(item, writer)?;
72        }
73        Ok(())
74    }
75}
76
77impl<T: TpmParse + Copy + Default, const CAPACITY: usize> TpmParse for TpmList<T, CAPACITY> {
78    fn parse(buf: &[u8]) -> TpmResult<(Self, &[u8])> {
79        let (count_u32, mut buf) = u32::parse(buf)?;
80        let count = count_u32 as usize;
81        if count > CAPACITY {
82            return Err(TpmErrorKind::ValueTooLarge);
83        }
84
85        let mut list = Self::new();
86        for _ in 0..count {
87            let (item, rest) = T::parse(buf)?;
88            list.try_push(item)
89                .map_err(|_| TpmErrorKind::InternalError)?;
90            buf = rest;
91        }
92
93        Ok((list, buf))
94    }
95}