diff --git a/src/traft/raft_storage.rs b/src/traft/raft_storage.rs index cc5cf1643358572187faca85599f4d63fef80c64..d34a62985ebb7e9249ffeae4319eb7fd8a0cdb79 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 c3f9ec2b1f9904ad00051795938df807cb60c7fa..4125a7f05ed4b0904bab149d6d345989bf2a7404 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")); + } } ////////////////////////////////////////////////////////////////////////////////