From cc48211db16833c99243965563b1868149418183 Mon Sep 17 00:00:00 2001
From: Yaroslav Dynnikov <yaroslav.dynnikov@gmail.com>
Date: Thu, 15 Sep 2022 13:56:45 +0300
Subject: [PATCH] feature: check raft_storage auto_impl correctness

---
 src/traft/raft_storage.rs |  5 +++++
 src/util.rs               | 42 +++++++++++++++++++++++++++++++++++++--
 2 files changed, 45 insertions(+), 2 deletions(-)

diff --git a/src/traft/raft_storage.rs b/src/traft/raft_storage.rs
index cc5cf16433..d34a62985e 100644
--- a/src/traft/raft_storage.rs
+++ b/src/traft/raft_storage.rs
@@ -11,6 +11,7 @@ use crate::traft;
 use crate::traft::RaftId;
 use crate::traft::RaftIndex;
 use crate::traft::RaftTerm;
+use crate::util::str_eq;
 
 fn box_err(e: impl std::error::Error + Sync + Send + 'static) -> StorageError {
     StorageError::Other(Box::new(e))
@@ -57,6 +58,10 @@ macro_rules! auto_impl {
         $(
             $(#[$meta])*
             $vis fn $setter(&mut self, value: $ty) -> tarantool::Result<()> {
+                const _: () = assert!(str_eq(
+                    stringify!($setter),
+                    concat!("persist_", stringify!($key))
+                ));
                 let key: &str = stringify!($key);
                 self.space_raft_state.$mod(&(key, value))?;
                 Ok(())
diff --git a/src/util.rs b/src/util.rs
index c3f9ec2b1f..4125a7f05e 100644
--- a/src/util.rs
+++ b/src/util.rs
@@ -214,12 +214,33 @@ impl std::borrow::Borrow<str> for Uppercase {
     }
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Compare string literals at compile time.
+
+#[allow(dead_code)] // suppress the warning since it's only used at compile time
+pub const fn str_eq(lhs: &str, rhs: &str) -> bool {
+    let lhs = lhs.as_bytes();
+    let rhs = rhs.as_bytes();
+    if lhs.len() != rhs.len() {
+        return false;
+    }
+    let mut i = 0;
+    loop {
+        if i == lhs.len() {
+            return true;
+        }
+        if lhs[i] != rhs[i] {
+            return false;
+        }
+        i += 1;
+    }
+}
+
 #[cfg(test)]
 mod tests {
-    use super::*;
-
     #[test]
     fn uppercase() {
+        use super::Uppercase;
         assert_eq!(&*Uppercase::from(""), "");
         assert_eq!(&*Uppercase::from("hello"), "HELLO");
         assert_eq!(&*Uppercase::from("HELLO"), "HELLO");
@@ -227,6 +248,23 @@ mod tests {
         assert_eq!(&*Uppercase::from(String::from("hello")), "HELLO");
         assert_eq!(&*Uppercase::from(String::from("HELLO")), "HELLO");
     }
+
+    #[test]
+    fn str_eq() {
+        use super::str_eq;
+        assert!(str_eq("", ""));
+        assert!(str_eq("a", "a"));
+        assert!(str_eq("\0b", "\0b"));
+        assert!(str_eq("foobar", concat!("foo", "bar")));
+
+        assert!(!str_eq("", "x"));
+        assert!(!str_eq("x", ""));
+        assert!(!str_eq("x", "y"));
+        assert!(!str_eq("ы", "Ы"));
+        assert!(!str_eq("\0x", "\0y"));
+        assert!(!str_eq("foo1", "bar1"));
+        assert!(!str_eq("foo1", "foo2"));
+    }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-- 
GitLab