Keystore 2.0: Refactor permissions. 1/5

Change the input syntax of implement_permission! to something more
rust-like.

Test: keystore2_test
Bug: 203555519

Change-Id: Ic7ce23e2fecb8351b5c8c2835c7baab1d73f2616
diff --git a/keystore2/src/permission.rs b/keystore2/src/permission.rs
index 4392acf..97b241f 100644
--- a/keystore2/src/permission.rs
+++ b/keystore2/src/permission.rs
@@ -79,7 +79,6 @@
 ///
 /// ## Example
 /// ```
-///
 /// implement_permission!(
 ///     /// MyPerm documentation.
 ///     #[derive(Clone, Copy, Debug, PartialEq)]
@@ -213,71 +212,229 @@
 ///    any variant not specified to the default.
 ///  * Every variant has a constructor with a name corresponding to its lower case SELinux string
 ///    representation.
-///  * `MyPerm.to_selinux(&self)` returns the SELinux string representation of the
-///    represented permission.
+///  * `MyPermission::to_selinux(&self)` returns the SELinux string representation of the
+///    corresponding permission.
+///  * An implicit default values `MyPermission::None` is created with a numeric representation
+///    of `0` and a string representation of `"none"`.
+///  * Specifying a value is optional. If the value is omitted it is set to the value of the
+///    previous variant left shifted by 1.
 ///
 /// ## Example
 /// ```
 /// implement_permission!(
-///     /// MyPerm documentation.
+///     /// MyPermission documentation.
 ///     #[derive(Clone, Copy, Debug, Eq, PartialEq)]
-///     MyPerm with default (None = 0, none) {
-///         Foo = 1,           selinux name: foo;
-///         Bar = 2,           selinux name: bar;
+///     pub enum MyPermission {
+///         #[selinux(name = foo)]
+///         Foo = 1,
+///         #[selinux(name = bar)]
+///         Bar = 2,
+///         #[selinux(name = snafu)]
+///         Snafu, // Implicit value: MyPermission::Bar << 1 = 4
 ///     }
 /// );
 /// ```
 macro_rules! implement_permission {
-    // This rule provides the public interface of the macro. And starts the preprocessing
-    // recursion (see below).
-    ($(#[$m:meta])* $name:ident with default
-        ($def_name:ident = $def_val:expr, $def_selinux_name:ident)
-        {
-            $($(#[$element_meta:meta])*
-            $element_name:ident = $element_val:expr, selinux name: $selinux_name:ident;)*
-        })
-    => {
-        $(#[$m])*
-        pub enum $name {
-            /// The default variant of an enum.
-            $def_name = $def_val,
+    (
+        $(#[$enum_meta:meta])*
+        $enum_vis:vis enum $enum_name:ident {
             $(
-                $(#[$element_meta])*
-                $element_name = $element_val,
+                $(#[$($emeta:tt)+])*
+                $vname:ident$( = $vval:tt)?
+            ),* $(,)?
+        }
+    ) => {
+        implement_permission!{
+            @extract_attr
+            $(#[$enum_meta])*
+            $enum_vis enum $enum_name {
+                1
+                []
+                [$(
+                    [] [$(#[$($emeta)+])*]
+                    $vname$( = $vval)?,
+                )*]
+            }
+        }
+    };
+
+    (
+        @extract_attr
+        $(#[$enum_meta:meta])*
+        $enum_vis:vis enum $enum_name:ident {
+            $next_val:tt
+            [$($out:tt)*]
+            [
+                [$(#[$mout:meta])*]
+                [
+                    #[selinux(name = $selinux_name:ident)]
+                    $(#[$($mtail:tt)+])*
+                ]
+                $vname:ident = $vval:tt,
+                $($tail:tt)*
+            ]
+        }
+    ) => {
+        implement_permission!{
+            @extract_attr
+            $(#[$enum_meta])*
+            $enum_vis enum $enum_name {
+                ($vval << 1)
+                [
+                    $($out)*
+                    $(#[$mout])*
+                    $(#[$($mtail)+])*
+                    $selinux_name $vname = $vval,
+                ]
+                [$($tail)*]
+            }
+        }
+    };
+
+    (
+        @extract_attr
+        $(#[$enum_meta:meta])*
+        $enum_vis:vis enum $enum_name:ident {
+            $next_val:tt
+            [$($out:tt)*]
+            [
+                [$(#[$mout:meta])*]
+                [
+                    #[selinux(name = $selinux_name:ident)]
+                    $(#[$($mtail:tt)+])*
+                ]
+                $vname:ident,
+                $($tail:tt)*
+            ]
+        }
+    ) => {
+        implement_permission!{
+            @extract_attr
+            $(#[$enum_meta])*
+            $enum_vis enum $enum_name {
+                ($next_val << 1)
+                [
+                    $($out)*
+                    $(#[$mout])*
+                    $(#[$($mtail)+])*
+                    $selinux_name $vname = $next_val,
+                ]
+                [$($tail)*]
+            }
+        }
+    };
+
+
+    (
+        @extract_attr
+        $(#[$enum_meta:meta])*
+        $enum_vis:vis enum $enum_name:ident {
+            $next_val:tt
+            [$($out:tt)*]
+            [
+                [$(#[$mout:meta])*]
+                [
+                    #[$front:meta]
+                    $(#[$($mtail:tt)+])*
+                ]
+                $vname:ident$( = $vval:tt)?,
+                $($tail:tt)*
+            ]
+        }
+    ) => {
+        implement_permission!{
+            @extract_attr
+            $(#[$enum_meta])*
+            $enum_vis enum $enum_name {
+                $next_val
+                [$($out)*]
+                [
+                    [
+                        $(#[$mout])*
+                        #[$front]
+                    ]
+                    [$(#[$($mtail)+])*]
+                    $vname$( = $vval)?,
+                    $($tail)*
+                ]
+            }
+        }
+    };
+
+    (
+        @extract_attr
+        $(#[$enum_meta:meta])*
+        $enum_vis:vis enum $enum_name:ident {
+            $next_val:tt
+            [$($out:tt)*]
+            []
+        }
+    ) => {
+        implement_permission!{
+            @spill
+            $(#[$enum_meta])*
+            $enum_vis enum $enum_name {
+                $($out)*
+            }
+        }
+    };
+
+    (
+        @spill
+        $(#[$enum_meta:meta])*
+        $enum_vis:vis enum $enum_name:ident {
+            $(
+                $(#[$emeta:meta])*
+                $selinux_name:ident $vname:ident = $vval:tt,
+            )*
+        }
+    ) => {
+        $(#[$enum_meta])*
+        $enum_vis enum $enum_name {
+            /// The default variant of an enum.
+            None = 0,
+            $(
+                $(#[$emeta])*
+                $vname = $vval,
             )*
         }
 
-        impl From<i32> for $name {
+        impl From<i32> for $enum_name {
+            #[allow(non_upper_case_globals)]
             fn from (p: i32) -> Self {
+                // Creating constants forces the compiler to evaluate the value expressions
+                // so that they can be used in the match statement below.
+                $(const $vname: i32 = $vval;)*
                 match p {
-                    $def_val => Self::$def_name,
-                    $($element_val => Self::$element_name,)*
-                    _ => Self::$def_name,
+                    0 => Self::None,
+                    $($vname => Self::$vname,)*
+                    _ => Self::None,
                 }
             }
         }
 
-        impl From<$name> for i32 {
-            fn from(p: $name) -> i32 {
+        impl From<$enum_name> for i32 {
+            fn from(p: $enum_name) -> i32 {
                 p as i32
             }
         }
 
-        impl $name {
+        impl $enum_name {
+
             /// Returns a string representation of the permission as required by
             /// `selinux::check_access`.
             pub fn to_selinux(self) -> &'static str {
                 match self {
-                    Self::$def_name => stringify!($def_selinux_name),
-                    $(Self::$element_name => stringify!($selinux_name),)*
+                    Self::None => &"none",
+                    $(Self::$vname => stringify!($selinux_name),)*
                 }
             }
 
             /// Creates an instance representing a permission with the same name.
-            pub const fn $def_selinux_name() -> Self { Self::$def_name }
+            pub const fn none() -> Self { Self::None }
             $(
                 /// Creates an instance representing a permission with the same name.
-                pub const fn $selinux_name() -> Self { Self::$element_name }
+                pub const fn $selinux_name() -> Self { Self::$vname }
             )*
         }
     };
@@ -287,38 +444,53 @@
     /// KeystorePerm provides a convenient abstraction from the SELinux class `keystore2`.
     /// Using the implement_permission macro we get the same features as `KeyPerm`.
     #[derive(Clone, Copy, Debug, PartialEq)]
-    KeystorePerm with default (None = 0, none) {
+    pub enum KeystorePerm {
         /// Checked when a new auth token is installed.
-        AddAuth = 1,    selinux name: add_auth;
+        #[selinux(name = add_auth)]
+        AddAuth,
         /// Checked when an app is uninstalled or wiped.
-        ClearNs = 2,    selinux name: clear_ns;
+        #[selinux(name = clear_ns)]
+        ClearNs,
         /// Checked when the user state is queried from Keystore 2.0.
-        GetState = 4,   selinux name: get_state;
+        #[selinux(name = get_state)]
+        GetState,
         /// Checked when Keystore 2.0 is asked to list a namespace that the caller
         /// does not have the get_info permission for.
-        List = 8,       selinux name: list;
+        #[selinux(name = list)]
+        List,
         /// Checked when Keystore 2.0 gets locked.
-        Lock = 0x10,       selinux name: lock;
+        #[selinux(name = lock)]
+        Lock,
         /// Checked when Keystore 2.0 shall be reset.
-        Reset = 0x20,    selinux name: reset;
+        #[selinux(name = reset)]
+        Reset,
         /// Checked when Keystore 2.0 shall be unlocked.
-        Unlock = 0x40,    selinux name: unlock;
+        #[selinux(name = unlock)]
+        Unlock,
         /// Checked when user is added or removed.
-        ChangeUser = 0x80,    selinux name: change_user;
+        #[selinux(name = change_user)]
+        ChangeUser,
         /// Checked when password of the user is changed.
-        ChangePassword = 0x100,    selinux name: change_password;
+        #[selinux(name = change_password)]
+        ChangePassword,
         /// Checked when a UID is cleared.
-        ClearUID = 0x200,    selinux name: clear_uid;
+        #[selinux(name = clear_uid)]
+        ClearUID,
         /// Checked when Credstore calls IKeystoreAuthorization to obtain auth tokens.
-        GetAuthToken = 0x400,  selinux name: get_auth_token;
+        #[selinux(name = get_auth_token)]
+        GetAuthToken,
         /// Checked when earlyBootEnded() is called.
-        EarlyBootEnded = 0x800,   selinux name: early_boot_ended;
+        #[selinux(name = early_boot_ended)]
+        EarlyBootEnded,
         /// Checked when IKeystoreMaintenance::onDeviceOffBody is called.
-        ReportOffBody = 0x1000, selinux name: report_off_body;
-        /// Checked when IkeystoreMetrics::pullMetris is called.
-        PullMetrics = 0x2000, selinux name: pull_metrics;
+        #[selinux(name = report_off_body)]
+        ReportOffBody,
+        /// Checked when IkeystoreMetrics::pullMetrics is called.
+        #[selinux(name = pull_metrics)]
+        PullMetrics,
         /// Checked when IKeystoreMaintenance::deleteAllKeys is called.
-        DeleteAllKeys = 0x4000, selinux name: delete_all_keys;
+        #[selinux(name = delete_all_keys)]
+        DeleteAllKeys,
     }
 );