Conversation

Jarkko Sakkinen

Edited 3 days ago

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

#rust #rustlang

1
2
0

@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.

1
0
0
@Dr_Emann Absolutely 110% not as the whole point of view trait is to map a slice to a type.
2
0
0

Jarkko Sakkinen

Edited 3 days ago
[should be evident also from the git commit]
1
0
0
There's an astronomical difference between "having the same name" and "being the same".
0
0
0

@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],

1
0
1

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?

1
0
0
@Dr_Emann It's possible that I've missed something just learning by trial and error
1
0
0
@Dr_Emann I'm building the ladders up in a separate branch first getting basic types, lists and buffers right and finding most appropriate patterns. After I have those right it is easy to populate rest of the macro generation.

E.g. first PoC TpmBuffer I have from trait instead of get(), which I likely change also in integer: https://git.kernel.org/pub/scm/linux/kernel/git/jarkko/tpm2-protocol.git/commit/?h=zerocopy&id=68caecf1eceac25d8f3f819ef5f7c794ffcc9177. And next thing is TpmList and then some weeks bouncing around these basic data types until they "feel" right :-)

I.e. I try to create zerocopy non-destructively without breaking the working build/parse implementation while putting this stuff in...
1
0
0

Jarkko Sakkinen

Edited 3 days ago
@Dr_Emann OK I tested it and it looks like it is true. Thanks for the great remark!

Still leaves me a bit confused tho of when the "real" ty fragment is the only working option
0
0
0