This makes me happy:
tpm_struct!(
#[derive(Debug, PartialEq, Eq, Clone)]
TpmPcrEventCommand,
TpmCc::PcrEvent,
TpmSt::Sessions,
1,
{
pub event_data: Tpm2b,
}
);
tpm_response!(
#[derive(Debug, Default, PartialEq, Eq, Clone)]
TpmPcrEventResponse,
TpmCc::PcrEvent,
TpmSt::Sessions,
{
pub digests: TpmlDigestValues,
}
);
Also the types inside use the same system (in fact tpm_struct is shared macro with data types and commands). This will generate full parsing and building for both commands and responses - all without heap involved.
It also optimizes performance as that zeros out marshalling and unmarshalling. Internal representation can be buffer to which data structures are mapped.
For capacity it’s not exact science i.e.:
/// Buffer properties for an object.
pub trait TpmBuffer {
/// Capacity at most required to strore an object implementing the type.
const BUFFER_CAPACITY: usize;
pub fn len() -> usize;
}
E.g., for digest this would the maximum digest. For TPMT_PUBLIC capacity would 640 bytes to fit 4096-bit RSA key.
At runtime, however, the exact size is calculated by summing up “recursively”. Lengths also when summed up point the exact location in the byte stream where an attribute is located. I.e., it’s a zerocopy. I