macros.rs 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. //! # Macros
  2. //!
  3. //! All macros are defined in this module
  4. /// Dispatcher macro
  5. ///
  6. /// In this macro all command and their definition are defined.
  7. ///
  8. /// This macro generates rust code for each command and encapsulates all the logic to fast
  9. /// execution.
  10. ///
  11. /// Using macros allow to generate pretty efficient code for run time and easy to extend at
  12. /// writting time.
  13. #[macro_export]
  14. macro_rules! dispatcher {
  15. {
  16. $($ns:ident {
  17. $($command:ident {
  18. $handler:expr,
  19. [$($tag:tt)+],
  20. $min_args:expr,
  21. $key_start:expr,
  22. $key_stop:expr,
  23. $key_step:expr,
  24. $is_queueable:expr,
  25. }),+$(,)?
  26. }),+$(,)?
  27. }=> {
  28. use futures::future::FutureExt;
  29. /// Metrics for all defined commands
  30. #[derive(serde::Serialize)]
  31. pub struct ServiceMetricRegistry<'a> {
  32. $($(
  33. $command: &'a command::Metrics,
  34. )+)+
  35. }
  36. /// Dispatcher struct
  37. ///
  38. /// The list of commands are generated in this strucutre by this macro.
  39. #[allow(non_snake_case, non_camel_case_types)]
  40. #[derive(Debug)]
  41. pub struct Dispatcher {
  42. $($(
  43. $command: command::Command,
  44. )+)+
  45. }
  46. impl Dispatcher {
  47. /// Creates a new dispatcher.
  48. pub fn new() -> Self {
  49. Self {
  50. $($(
  51. $command: command::Command::new(
  52. stringify!($command),
  53. stringify!($ns),
  54. &[$($tag,)+],
  55. $min_args,
  56. $key_start,
  57. $key_stop,
  58. $key_step,
  59. $is_queueable,
  60. ),
  61. )+)+
  62. }
  63. }
  64. /// Returns all metrics objects
  65. pub fn get_service_metric_registry(&self) -> ServiceMetricRegistry {
  66. ServiceMetricRegistry {
  67. $($(
  68. $command: self.$command.metrics(),
  69. )+)+
  70. }
  71. }
  72. /// Returns the handlers for defined commands.
  73. pub fn get_all_commands(&self) -> Vec<&command::Command> {
  74. vec![
  75. $($(
  76. &self.$command,
  77. )+)+
  78. ]
  79. }
  80. /// Returns a command handler for a given command
  81. #[inline(always)]
  82. pub fn get_handler_for_command(&self, command: &str) -> Result<&command::Command, Error> {
  83. match command.to_lowercase().as_str() {
  84. $($(
  85. stringify!($command) => Ok(&self.$command),
  86. )+)+
  87. _ => Err(Error::CommandNotFound(command.into())),
  88. }
  89. }
  90. /// Returns the command handler
  91. ///
  92. /// Before returning the command handler this function will make sure the minimum
  93. /// required arguments are provided. This pre-validation ensures each command handler
  94. /// has fewer logic when reading the provided arguments.
  95. #[inline(always)]
  96. pub fn get_handler(&self, args: &[Bytes]) -> Result<&command::Command, Error> {
  97. let command = String::from_utf8_lossy(&args[0]).to_lowercase();
  98. let command = self.get_handler_for_command(&command)?;
  99. if ! command.check_number_args(args.len()) {
  100. Err(Error::InvalidArgsCount(command.name().into()))
  101. } else {
  102. Ok(command)
  103. }
  104. }
  105. /// Returns the command handler
  106. ///
  107. /// Before returning the command handler this function will make sure the minimum
  108. /// required arguments are provided. This pre-validation ensures each command handler
  109. /// has fewer logic when reading the provided arguments.
  110. #[inline(always)]
  111. pub fn execute<'a>(&'a self, conn: &'a Connection, args: &'a [Bytes]) -> futures::future::BoxFuture<'a, Result<Value, Error>> {
  112. async move {
  113. let command = String::from_utf8_lossy(&args[0]);
  114. match command.to_lowercase().as_str() {
  115. $($(
  116. stringify!($command) => {
  117. let command = &self.$command;
  118. if ! command.check_number_args(args.len()) {
  119. Err(Error::InvalidArgsCount(command.name().into()))
  120. } else {
  121. let metrics = command.metrics();
  122. let hit_count = &metrics.hit_count;
  123. let error_count = &metrics.error_count;
  124. let in_flight = &metrics.in_flight;
  125. let response_time = &metrics.response_time;
  126. let throughput = &metrics.throughput;
  127. let status = conn.status();
  128. if status == ConnectionStatus::Multi && command.is_queueable() {
  129. conn.queue_command(args);
  130. conn.tx_keys(command.get_keys(args));
  131. return Ok(Value::Queued);
  132. } else if status == ConnectionStatus::Pubsub && ! command.is_pubsub_executable() {
  133. return Err(Error::PubsubOnly(stringify!($command).to_owned()));
  134. }
  135. metered::measure!(hit_count, {
  136. metered::measure!(response_time, {
  137. metered::measure!(throughput, {
  138. metered::measure!(in_flight, {
  139. metered::measure!(error_count, $handler(conn, args).await)
  140. })
  141. })
  142. })
  143. })
  144. }
  145. }
  146. )+)+,
  147. _ => Err(Error::CommandNotFound(command.into())),
  148. }
  149. }.boxed()
  150. }
  151. }
  152. }
  153. }
  154. /// Generate code for From/Into a type to a Value
  155. #[macro_export]
  156. macro_rules! value_try_from {
  157. {$type: ty, $value: expr} => {
  158. impl From<$type> for Value {
  159. fn from(value: $type) -> Value {
  160. $value(value.into())
  161. }
  162. }
  163. value_vec_try_from!($type);
  164. }
  165. }
  166. /// Generate code for From/Into a vec of type to a Value::Array
  167. #[macro_export]
  168. macro_rules! value_vec_try_from {
  169. {$type: ty} => {
  170. impl From<Vec<$type>> for Value {
  171. fn from(value: Vec<$type>) -> Value {
  172. Value::Array(value.iter().map(|x| (*x).into()).collect())
  173. }
  174. }
  175. }
  176. }
  177. /// Converts an Option<T> to Value. If the option is None Value::Null is returned.
  178. #[macro_export]
  179. macro_rules! option {
  180. {$type: expr} => {
  181. if let Some(val) = $type {
  182. val.into()
  183. } else {
  184. Value::Null
  185. }
  186. }
  187. }
  188. /// Check if a given command argument in a position $pos is eq to a $command
  189. #[macro_export]
  190. macro_rules! check_arg {
  191. {$args: tt, $pos: tt, $command: tt} => {{
  192. match $args.get($pos) {
  193. Some(bytes) => {
  194. String::from_utf8_lossy(&bytes).to_uppercase() == $command
  195. },
  196. None => false,
  197. }
  198. }}
  199. }
  200. /// Convert a stream to a Bytes
  201. #[macro_export]
  202. macro_rules! bytes {
  203. ($content:tt) => {
  204. Bytes::from(&$content[..])
  205. };
  206. }