Just solved a Rust sudoku for the next version of tpm2-protocol
I think this is quite clever trick to surpass some of the limitation of syntax tree macros:
macro_rules! tpm_integer {
($ty:ty) => {
pub mod $ty {
#[derive(Clone, Copy, Debug)]
pub struct TpmView<'a> {
pub slice: &'a [u8],
}
}
};
}
Further, TpmView
implements a trait called TpmView
. This circulates around limitation that type cannot be used to name things in syntax tree macros.
Otherwise, unless moving into procedural macros, I’d end up ugly declarations along the lines of:
tpm_integer!(u8, TpmViewU8, Unsigned);
tpm_integer!(i8, TpmViewI8, Signed);
tpm_integer!(u16, TpmViewU16, Unsigned);
tpm_integer!(i32, TpmViewI32, Signed);
tpm_integer!(u32, TpmViewU32, Unsigned);
tpm_integer!(u64, TpmViewU64, Unsigned);
Transparency has been the single biggest blocker in moving forward with zerocopy parser and this sort of “nails it”.
EDIT
I was wrong in that you could type as module name. However, the trick does still resolve the name coflict with the original type and view type. The minor inconvience of having to repeat it twice is totally acceptable vs having to manually name stuff:
tpm_integer!(u8, u8, Unsigned);
tpm_integer!(i8, i8, Signed);
tpm_integer!(u16, u16, Unsigned);
tpm_integer!(i32, i32, Signed);
tpm_integer!(u32, u32, Unsigned);
tpm_integer!(u64, u64, Unsigned);
This is absolutely sustainable for me :-) I.e. second parameter is name of the module.
Here’s a working proof of concept: https://git.kernel.org/pub/scm/linux/kernel/git/jarkko/tpm2-protocol.git/commit/?h=zerocopy&id=42f61d9d85e17f784f71c8ac64ee6adbb7171997
@jarkko If you're okay requiring both be the same, you can just use a single `:ident` parameter, you can use an ident where a type is expected.
@jarkko No, I mean you don't need to take both an ident and a type, you can just take an ident, the macro can use an ident where a type is expected. This generates the same modules:
diff --git a/src/lib.rs b/src/lib.rs
index 6965d4a..afdc166 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -227,12 +227,12 @@ pub trait TpmParseTagged: Sized {
<Self as TpmTagged>::Tag: TpmParse + TpmBuild;
}
-tpm_integer!(u8, u8, Unsigned);
-tpm_integer!(i8, i8, Signed);
-tpm_integer!(u16, u16, Unsigned);
-tpm_integer!(i32, i32, Signed);
-tpm_integer!(u32, u32, Unsigned);
-tpm_integer!(u64, u64, Unsigned);
+tpm_integer!(u8, Unsigned);
+tpm_integer!(i8, Signed);
+tpm_integer!(u16, Unsigned);
+tpm_integer!(i32, Signed);
+tpm_integer!(u32, Unsigned);
+tpm_integer!(u64, Unsigned);
/// Builds a TPM2B sized buffer.
///
diff --git a/src/macro/integer.rs b/src/macro/integer.rs
index 8361407..0d8cb82 100644
--- a/src/macro/integer.rs
+++ b/src/macro/integer.rs
@@ -4,8 +4,8 @@
#[macro_export]
macro_rules! tpm_integer {
- ($ty:ty, $view_name:ident, $variant:ident) => {
- pub mod $view_name {
+ ($ty:ident, $variant:ident) => {
+ pub mod $ty {
#[derive(Clone, Copy)]
pub struct TpmView<'a> {
slice: &'a [u8],
Can you use ident to play a type e.g.,
impl<'a> PartialEq<$ty> for TpmView<'a> {
fn eq(&self, other: &$ty) -> bool {
self.get() == *other
}
}
If “$ty” was ident, would this work?