valkey_module_macros/lib.rs
1use proc_macro::TokenStream;
2use quote::quote;
3use syn::ItemFn;
4
5mod command;
6mod info_section;
7mod valkey_value;
8
9/// This proc macro allow to specify that the follow function is a Valkey command.
10/// The macro accept the following arguments that discribe the command properties:
11/// * name (optional) - The command name. in case not given, the function name will be taken.
12/// * flags - An array of [`command::RedisCommandFlags`].
13/// * summary (optional) - Command summary
14/// * complexity (optional) - Command compexity
15/// * since (optional) - At which module version the command was first introduce
16/// * tips (optional) - Command tips for proxy, for more information please refer to https://redis.io/topics/command-tips
17/// * arity - Number of arguments, including the command name itself. A positive number specifies an exact number of arguments and a negative number
18/// specifies a minimum number of arguments.
19/// * key_spec - A list of specs representing how to find the keys that the command might touch. the following options are available:
20/// * notes (optional) - Some note about the key spec.
21/// * flags - List of flags reprenting how the keys are accessed, the following options are available:
22/// * Readonly - Read-Only. Reads the value of the key, but doesn't necessarily return it.
23/// * ReadWrite - Read-Write. Modifies the data stored in the value of the key or its metadata.
24/// * Overwrite - Overwrite. Overwrites the data stored in the value of the key.
25/// * Remove - Deletes the key.
26/// * Access - Returns, copies or uses the user data from the value of the key.
27/// * Update - Updates data to the value, new value may depend on the old value.
28/// * Insert - Adds data to the value with no chance of modification or deletion of existing data.
29/// * Delete - Explicitly deletes some content from the value of the key.
30/// * NotKey - The key is not actually a key, but should be routed in cluster mode as if it was a key.
31/// * Incomplete - The keyspec might not point out all the keys it should cover.
32/// * VariableFlags - Some keys might have different flags depending on arguments.
33/// * begin_search - Represents how Valkey should start looking for keys.
34/// There are 2 possible options:
35/// * Index - start looking for keys from a given position.
36/// * Keyword - Search for a specific keyward and start looking for keys from this keyword
37/// * FindKeys - After Valkey finds the location from where it needs to start looking for keys,
38/// Valkey will start finding keys base on the information in this struct.
39/// There are 2 possible options:
40/// * Range - An object of three element `last_key`, `steps`, `limit`.
41/// * last_key - Index of the last key relative to the result of the
42/// begin search step. Can be negative, in which case it's not
43/// relative. -1 indicates the last argument, -2 one before the
44/// last and so on.
45/// * steps - How many arguments should we skip after finding a
46/// key, in order to find the next one.
47/// * limit - If `lastkey` is -1, we use `limit` to stop the search
48/// by a factor. 0 and 1 mean no limit. 2 means 1/2 of the
49/// remaining args, 3 means 1/3, and so on.
50/// * Keynum - An object of 3 elements `keynumidx`, `firstkey`, `keystep`.
51/// * keynumidx - Index of the argument containing the number of
52/// keys to come, relative to the result of the begin search step.
53/// * firstkey - Index of the fist key relative to the result of the
54/// begin search step. (Usually it's just after `keynumidx`, in
55/// which case it should be set to `keynumidx + 1`.)
56/// * keystep - How many arguments should we skip after finding a
57/// key, in order to find the next one?
58///
59/// Example:
60/// The following example will register a command called `foo`.
61/// ```rust,no_run,ignore
62/// #[command(
63/// {
64/// name: "test",
65/// flags: [ReadOnly],
66/// arity: -2,
67/// key_spec: [
68/// {
69/// notes: "test command that define all the arguments at even possition as keys",
70/// flags: [ReadOnly, Access],
71/// begin_search: Keyword({ keyword : "foo", startfrom : 1 }),
72/// find_keys: Range({ last_key :- 1, steps : 2, limit : 0 }),
73/// }
74/// ]
75/// }
76/// )]
77/// fn test_command(_ctx: &Context, _args: Vec<RedisString>) -> RedisResult {
78/// Ok(ValkeyValue::SimpleStringStatic("OK"))
79/// }
80/// ```
81///
82/// **Notice**, by default Valkey does not validate the command spec. User should validate the command keys on the module command code. The command spec is used for validation on cluster so Valkey can raise a cross slot error when needed.
83#[proc_macro_attribute]
84pub fn command(attr: TokenStream, item: TokenStream) -> TokenStream {
85 command::valkey_command(attr, item)
86}
87
88/// Proc macro which is set on a function that need to be called whenever the server role changes.
89/// The function must accept a [Context] and [ServerRole].
90///
91/// Example:
92///
93/// ```rust,no_run,ignore
94/// #[role_changed_event_handler]
95/// fn role_changed_event_handler(ctx: &Context, values: ServerRole) { ... }
96/// ```
97#[proc_macro_attribute]
98pub fn role_changed_event_handler(_attr: TokenStream, item: TokenStream) -> TokenStream {
99 let ast: ItemFn = match syn::parse(item) {
100 Ok(res) => res,
101 Err(e) => return e.to_compile_error().into(),
102 };
103 let gen = quote! {
104 #[linkme::distributed_slice(valkey_module::server_events::ROLE_CHANGED_SERVER_EVENTS_LIST)]
105 #ast
106 };
107 gen.into()
108}
109
110/// Proc macro which is set on a function that need to be called whenever a loading event happened.
111/// The function must accept a [Context] and [LoadingSubevent].
112///
113/// Example:
114///
115/// ```rust,no_run,ignore
116/// #[loading_event_handler]
117/// fn loading_event_handler(ctx: &Context, values: LoadingSubevent) { ... }
118/// ```
119#[proc_macro_attribute]
120pub fn loading_event_handler(_attr: TokenStream, item: TokenStream) -> TokenStream {
121 let ast: ItemFn = match syn::parse(item) {
122 Ok(res) => res,
123 Err(e) => return e.to_compile_error().into(),
124 };
125 let gen = quote! {
126 #[linkme::distributed_slice(valkey_module::server_events::LOADING_SERVER_EVENTS_LIST)]
127 #ast
128 };
129 gen.into()
130}
131
132/// Proc macro which is set on a function that need to be called repeatedly
133/// while an RDB or AOF file is being loaded.
134/// The function must accept a [Context], [LoadingProgressSubevent], `hz: i32` and `progress: i32`.
135#[proc_macro_attribute]
136pub fn loading_progress_event_handler(_attr: TokenStream, item: TokenStream) -> TokenStream {
137 let ast: ItemFn = match syn::parse(item) {
138 Ok(res) => res,
139 Err(e) => return e.to_compile_error().into(),
140 };
141 let gen = quote! {
142 #[linkme::distributed_slice(valkey_module::server_events::LOADING_PROGRESS_SERVER_EVENTS_LIST)]
143 #ast
144 };
145 gen.into()
146}
147
148/// Proc macro which is set on a function that need to be called for every
149/// event loop iteration before the server sleeps or after it wakes up.
150/// The function must accept a [Context] and [EventLoopSubevent].
151#[proc_macro_attribute]
152pub fn event_loop_event_handler(_attr: TokenStream, item: TokenStream) -> TokenStream {
153 let ast: ItemFn = match syn::parse(item) {
154 Ok(res) => res,
155 Err(e) => return e.to_compile_error().into(),
156 };
157 let gen = quote! {
158 #[linkme::distributed_slice(valkey_module::server_events::EVENT_LOOP_SERVER_EVENTS_LIST)]
159 #ast
160 };
161 gen.into()
162}
163
164/// Proc macro which is set on a function that need to be called whenever a flush event happened.
165/// The function must accept a [Context] and [FlushSubevent].
166///
167/// Example:
168///
169/// ```rust,no_run,ignore
170/// #[flush_event_handler]
171/// fn flush_event_handler(ctx: &Context, values: FlushSubevent) { ... }
172/// ```
173#[proc_macro_attribute]
174pub fn flush_event_handler(_attr: TokenStream, item: TokenStream) -> TokenStream {
175 let ast: ItemFn = match syn::parse(item) {
176 Ok(res) => res,
177 Err(e) => return e.to_compile_error().into(),
178 };
179 let gen = quote! {
180 #[linkme::distributed_slice(valkey_module::server_events::FLUSH_SERVER_EVENTS_LIST)]
181 #ast
182 };
183 gen.into()
184}
185
186/// Proc macro which is set on a function that need to be called whenever a module is loaded or unloaded on the server.
187/// The function must accept a [Context] and [ModuleChangeSubevent].
188///
189/// Example:
190///
191/// ```rust,no_run,ignore
192/// #[module_changed_event_handler]
193/// fn module_changed_event_handler(ctx: &Context, values: ModuleChangeSubevent) { ... }
194/// ```
195#[proc_macro_attribute]
196pub fn module_changed_event_handler(_attr: TokenStream, item: TokenStream) -> TokenStream {
197 let ast: ItemFn = match syn::parse(item) {
198 Ok(res) => res,
199 Err(e) => return e.to_compile_error().into(),
200 };
201 let gen = quote! {
202 #[linkme::distributed_slice(valkey_module::server_events::MODULE_CHANGED_SERVER_EVENTS_LIST)]
203 #ast
204 };
205 gen.into()
206}
207
208/// Proc macro which is set on a function that need to be called whenever a client connects or disconnects on the server.
209/// The function must accept a [Context] and [ClientChangeSubEvent].
210///
211/// Example:
212///
213/// ```rust,no_run,ignore
214/// #[client_changed_event_handler]
215/// fn client_changed_event_handler(ctx: &Context, values: ClientChangeSubEvent) { ... }
216/// ```
217#[proc_macro_attribute]
218pub fn client_changed_event_handler(_attr: TokenStream, item: TokenStream) -> TokenStream {
219 let ast: ItemFn = match syn::parse(item) {
220 Ok(res) => res,
221 Err(e) => return e.to_compile_error().into(),
222 };
223 let gen = quote! {
224 #[linkme::distributed_slice(valkey_module::server_events::CLIENT_CHANGED_SERVER_EVENTS_LIST)]
225 #ast
226 };
227 gen.into()
228}
229
230/// Proc macro which is set on a function that need to be called whenever a shutdown event happens.
231/// The function must accept a [Context] and [u64].
232///
233/// Example:
234///
235/// ```rust,no_run,ignore
236/// #[shutdown_event_handler]
237/// fn shutdown_event_handler(ctx: &Context, subevent: u64) { ... }
238/// ```
239#[proc_macro_attribute]
240pub fn shutdown_event_handler(_attr: TokenStream, item: TokenStream) -> TokenStream {
241 let ast: ItemFn = match syn::parse(item) {
242 Ok(res) => res,
243 Err(e) => return e.to_compile_error().into(),
244 };
245 let gen = quote! {
246 #[linkme::distributed_slice(valkey_module::server_events::SHUTDOWN_SERVER_EVENT_LIST)]
247 #ast
248 };
249 gen.into()
250}
251
252/// Proc macro which is set on a function that need to be called whenever a configuration change
253/// event is happening. The function must accept a [Context] and [&[&str]] that contains the names
254/// of the configiration values that was changed.
255///
256/// Example:
257///
258/// ```rust,no_run,ignore
259/// #[config_changed_event_handler]
260/// fn configuration_changed_event_handler(ctx: &Context, values: &[&str]) { ... }
261/// ```
262#[proc_macro_attribute]
263pub fn config_changed_event_handler(_attr: TokenStream, item: TokenStream) -> TokenStream {
264 let ast: ItemFn = match syn::parse(item) {
265 Ok(res) => res,
266 Err(e) => return e.to_compile_error().into(),
267 };
268 let gen = quote! {
269 #[linkme::distributed_slice(valkey_module::server_events::CONFIG_CHANGED_SERVER_EVENTS_LIST)]
270 #ast
271 };
272 gen.into()
273}
274
275/// Proc macro which is set on a function that need to be called on Valkey cron.
276/// The function must accept a [Context] and [u64] that represent the cron hz.
277///
278/// Example:
279///
280/// ```rust,no_run,ignore
281/// #[cron_event_handler]
282/// fn cron_event_handler(ctx: &Context, hz: u64) { ... }
283/// ```
284#[proc_macro_attribute]
285pub fn cron_event_handler(_attr: TokenStream, item: TokenStream) -> TokenStream {
286 let ast: ItemFn = match syn::parse(item) {
287 Ok(res) => res,
288 Err(e) => return e.to_compile_error().into(),
289 };
290 let gen = quote! {
291 #[linkme::distributed_slice(valkey_module::server_events::CRON_SERVER_EVENTS_LIST)]
292 #ast
293 };
294 gen.into()
295}
296
297/// Proc macro which is set on a function that need to be called whenever a key event happened.
298/// The function must accept a [Context] and [KeyEventSubevent].
299/// Example:
300/// ```rust,no_run,ignore
301/// #[key_event_handler]
302/// fn key_event_handler(ctx: &Context, values: KeyEventSubevent) { ... }
303#[proc_macro_attribute]
304pub fn key_event_handler(_attr: TokenStream, item: TokenStream) -> TokenStream {
305 let ast: ItemFn = match syn::parse(item) {
306 Ok(res) => res,
307 Err(e) => return e.to_compile_error().into(),
308 };
309 let gen = quote! {
310 #[linkme::distributed_slice(valkey_module::server_events::KEY_SERVER_EVENTS_LIST)]
311 #ast
312 };
313 gen.into()
314}
315
316/// Proc macro which is set on a function that need to be called whenever a persistence event happened.
317/// The function must accept a [Context] and [PersistenceSubevent].
318/// Example:
319/// ```rust,no_run,ignore
320/// #[persistence_event_handler]
321/// fn persistence_event_handler(ctx: &Context, values: PersistenceSubevent) { ... }
322/// ```
323#[proc_macro_attribute]
324pub fn persistence_event_handler(_attr: TokenStream, item: TokenStream) -> TokenStream {
325 let ast: ItemFn = match syn::parse(item) {
326 Ok(res) => res,
327 Err(e) => return e.to_compile_error().into(),
328 };
329 let gen = quote! {
330 #[linkme::distributed_slice(valkey_module::server_events::PERSISTENCE_SERVER_EVENTS_LIST)]
331 #ast
332 };
333 gen.into()
334}
335
336/// Proc macro which is set on a function that need to be called whenever a master link change event happened.
337/// The function must accept a [Context] and [MasterLinkChangeSubevent].
338/// Example:
339/// ```rust,no_run,ignore
340/// #[master_link_change_event_handler]
341/// fn master_link_change_event_handler(ctx: &Context, values: MasterLinkChangeSubevent) { ... }
342/// ```
343#[proc_macro_attribute]
344pub fn master_link_change_event_handler(_attr: TokenStream, item: TokenStream) -> TokenStream {
345 let ast: ItemFn = match syn::parse(item) {
346 Ok(res) => res,
347 Err(e) => return e.to_compile_error().into(),
348 };
349 let gen = quote! {
350 #[linkme::distributed_slice(valkey_module::server_events::MASTER_LINK_CHANGE_SERVER_EVENTS_LIST)]
351 #ast
352 };
353 gen.into()
354}
355
356/// Proc macro which is set on a function that need to be called whenever a fork child event happened.
357/// The function must accept a [Context] and [ForkChildSubevent].
358/// Example:
359/// ```rust,no_run,ignore
360/// #[fork_child_event_handler]
361/// fn fork_child_event_handler(ctx: &Context, values: ForkChildSubevent) { ... }
362/// ```
363#[proc_macro_attribute]
364pub fn fork_child_event_handler(_attr: TokenStream, item: TokenStream) -> TokenStream {
365 let ast: ItemFn = match syn::parse(item) {
366 Ok(res) => res,
367 Err(e) => return e.to_compile_error().into(),
368 };
369 let gen = quote! {
370 #[linkme::distributed_slice(valkey_module::server_events::FORK_CHILD_SERVER_EVENTS_LIST)]
371 #ast
372 };
373 gen.into()
374}
375
376/// The macro auto generate a [From] implementation that can convert the struct into [ValkeyValue].
377///
378/// Example:
379///
380/// ```rust,no_run,ignore
381/// #[derive(ValkeyValue)]
382/// struct ValkeyValueDeriveInner {
383/// i: i64,
384/// }
385///
386/// #[derive(ValkeyValue)]
387/// struct ValkeyValueDerive {
388/// i: i64,
389/// f: f64,
390/// s: String,
391/// u: usize,
392/// v: Vec<i64>,
393/// v2: Vec<ValkeyValueDeriveInner>,
394/// hash_map: HashMap<String, String>,
395/// hash_set: HashSet<String>,
396/// ordered_map: BTreeMap<String, ValkeyValueDeriveInner>,
397/// ordered_set: BTreeSet<String>,
398/// }
399///
400/// #[command(
401/// {
402/// flags: [ReadOnly, NoMandatoryKeys],
403/// arity: -1,
404/// key_spec: [
405/// {
406/// notes: "test valkey value derive macro",
407/// flags: [ReadOnly, Access],
408/// begin_search: Index({ index : 0 }),
409/// find_keys: Range({ last_key : 0, steps : 0, limit : 0 }),
410/// }
411/// ]
412/// }
413/// )]
414/// fn valkey_value_derive(_ctx: &Context, _args: Vec<RedisString>) -> RedisResult {
415/// Ok(ValkeyValueDerive {
416/// i: 10,
417/// f: 1.1,
418/// s: "s".to_owned(),
419/// u: 20,
420/// v: vec![1, 2, 3],
421/// v2: vec![
422/// ValkeyValueDeriveInner { i: 1 },
423/// ValkeyValueDeriveInner { i: 2 },
424/// ],
425/// hash_map: HashMap::from([("key".to_owned(), "val`".to_owned())]),
426/// hash_set: HashSet::from(["key".to_owned()]),
427/// ordered_map: BTreeMap::from([("key".to_owned(), ValkeyValueDeriveInner { i: 10 })]),
428/// ordered_set: BTreeSet::from(["key".to_owned()]),
429/// }
430/// .into())
431/// }
432/// ```
433///
434/// The [From] implementation generates a [ValkeyValue::OrderMap] such that the fields names
435/// are the map keys and the values are the result of running [Into] function on the field
436/// value and convert it into a [ValkeyValue].
437///
438/// The code above will generate the following reply (in resp3):
439///
440/// ```bash
441/// 127.0.0.1:6379> valkey_value_derive
442/// 1# "f" => (double) 1.1
443/// 2# "hash_map" => 1# "key" => "val"
444/// 3# "hash_set" => 1~ "key"
445/// 4# "i" => (integer) 10
446/// 5# "ordered_map" => 1# "key" => 1# "i" => (integer) 10
447/// 6# "ordered_set" => 1~ "key"
448/// 7# "s" => "s"
449/// 8# "u" => (integer) 20
450/// 9# "v" =>
451/// 1) (integer) 1
452/// 2) (integer) 2
453/// 3) (integer) 3
454/// 10# "v2" =>
455/// 1) 1# "i" => (integer) 1
456/// 2) 1# "i" => (integer) 2
457/// ```
458///
459/// The derive proc macro can also be set on an Enum. In this case, the generated
460/// code will check the enum variant (using a match statement) and perform [Into]
461/// on the matched varient. This is usefull in case the command returns more than
462/// a single reply type and the reply type need to be decided at runtime.
463///
464/// It is possible to specify a field attribute that will define a specific behavior
465/// about the field. Supported attributes:
466///
467/// * flatten - indicate to inlines keys from a field into the parent struct.
468///
469/// Example:
470///
471/// ```rust,no_run,ignore
472/// #[derive(ValkeyValue)]
473/// struct ValkeyValueDeriveInner {
474/// i2: i64,
475/// }
476///
477/// #[derive(ValkeyValue)]
478/// struct ValkeyValueDerive {
479/// i1: i64,
480/// #[ValkeyValueAttr{flatten: true}]
481/// inner: ValkeyValueDeriveInner
482/// }
483///
484/// #[command(
485/// {
486/// flags: [ReadOnly, NoMandatoryKeys],
487/// arity: -1,
488/// key_spec: [
489/// {
490/// notes: "test valkey value derive macro",
491/// flags: [ReadOnly, Access],
492/// begin_search: Index({ index : 0 }),
493/// find_keys: Range({ last_key : 0, steps : 0, limit : 0 }),
494/// }
495/// ]
496/// }
497/// )]
498/// fn valkey_value_derive(_ctx: &Context, _args: Vec<RedisString>) -> RedisResult {
499/// Ok(ValkeyValueDerive {
500/// i1: 10,
501/// inner: ValkeyValueDeriveInner{ i2: 10 },
502/// }
503/// .into())
504/// }
505/// ```
506///
507/// The code above will generate the following reply (in resp3):
508///
509/// ```bash
510/// 127.0.0.1:6379> valkey_value_derive
511/// 1# "i1" => 10
512/// 2# "i2" => 10
513/// ```
514///
515#[proc_macro_derive(ValkeyValue, attributes(ValkeyValueAttr))]
516pub fn valkey_value(item: TokenStream) -> TokenStream {
517 valkey_value::valkey_value(item)
518}
519
520/// A procedural macro which registers this function as the custom
521/// `INFO` command handler. There might be more than one handler, each
522/// adding new information to the context.
523///
524/// Example:
525///
526/// ```rust,no_run,ignore
527/// #[info_command_handler]
528/// fn info_command_handler(
529/// ctx: &InfoContext,
530/// for_crash_report: bool) -> RedisResult
531/// {
532/// ctx.builder()
533/// .add_section("test_info")
534/// .field("test_field1", "test_value1")?
535/// .field("test_field2", "test_value2")?
536/// .build_section()?
537/// .build_info()?;
538///
539/// Ok(())
540/// }
541/// ```
542#[proc_macro_attribute]
543pub fn info_command_handler(_attr: TokenStream, item: TokenStream) -> TokenStream {
544 let ast: ItemFn = match syn::parse(item) {
545 Ok(res) => res,
546 Err(e) => return e.to_compile_error().into(),
547 };
548 let gen = quote! {
549 #[linkme::distributed_slice(valkey_module::server_events::INFO_COMMAND_HANDLER_LIST)]
550 #ast
551 };
552 gen.into()
553}
554
555/// Implements a corresponding [`From`] for this struct, to convert
556/// objects of this struct to an information object to be sent to the
557/// [`valkey_module::InfoContext`] as a reply.
558///
559/// Example:
560///
561/// ```rust,no_run,ignore
562/// #[derive(InfoSection)]
563/// struct Info {
564/// field_1: String,
565/// field_2: u64,
566/// dictionary_1: BTreeMap<String, String>,
567/// }
568/// ```
569///
570/// This procedural macro only implements an easy way to convert objects
571/// of this struct, it doesn't automatically do anything. To actually
572/// make use of this, we must return an object of this struct from the
573/// corresponding handler (`info` handler):
574///
575/// ```rust,no_run,ignore
576/// static mut INFO: Info = Info::new();
577///
578/// #[info_command_handler]
579/// fn info_command_handler(
580/// ctx: &InfoContext,
581/// _for_crash_report: bool) -> RedisResult
582/// {
583/// ctx.build_one_section(INFO)
584/// }
585/// ```
586///
587/// # Notes
588///
589/// 1. The name of the struct is taken "as is", so if it starts with
590/// a capital letter (written in the "Upper Camel Case"), like in this
591/// example - `Info`, then it will be compiled into a string prefixed
592/// with the module name, ending up being `"module_name_Info"`-named
593/// section. The fields of the struct are also prefixed with the module
594/// name, so the `field_1` will be prefixed with `module_name_` as well.
595/// 2. In dictionaries, the type of dictionaries supported varies,
596/// for now it is [`std::collections::BTreeMap`] and
597/// [`std::collections::HashMap`].
598/// 3. In dictionaries, the value type can be anything that can be
599/// converted into an object of type
600/// [`valkey_module::InfoContextBuilderFieldBottomLevelValue`], for
601/// example, a [`std::string::String`] or [`u64`]. Please, refer to
602/// [`valkey_module::InfoContextBuilderFieldBottomLevelValue`] for more
603/// information.
604#[proc_macro_derive(InfoSection)]
605pub fn info_section(item: TokenStream) -> TokenStream {
606 info_section::info_section(item)
607}
608
609
610/// Proc macro which is set on a function that need to be called whenever a replica change event happened.
611/// The function must accept a [Context] and [ReplicaChangeSubevent].
612/// Example:
613/// ```rust,no_run,ignore
614/// #[replica_change_event_handler]
615/// fn replica_change_event_handler(ctx: &Context, values: ReplicaChangeSubevent) { ... }
616/// ```
617#[proc_macro_attribute]
618pub fn replica_change_event_handler(_attr: TokenStream, item: TokenStream) -> TokenStream {
619 let ast: ItemFn = match syn::parse(item) {
620 Ok(res) => res,
621 Err(e) => return e.to_compile_error().into(),
622 };
623 let gen = quote! {
624 #[linkme::distributed_slice(valkey_module::server_events::REPLICA_CHANGE_SERVER_EVENTS_LIST)]
625 #ast
626 };
627 gen.into()
628}
629
630/// Proc macro which is set on a function that need to be called whenever a
631/// repl-diskless-load config is set to swapdb and a replication with a primary of same data set history occurs.
632/// The function must accept a [Context] and [ReplAsyncLoadSubevent].
633/// Example:
634/// ```rust,no_run,ignore
635/// #[repl_async_load_event_handler]
636/// fn repl_async_load_event_handler(ctx: &Context, values: ReplAsyncLoadSubevent) { ... }
637/// ```
638#[proc_macro_attribute]
639pub fn repl_async_load_event_handler(_attr: TokenStream, item: TokenStream) -> TokenStream {
640 let ast: ItemFn = match syn::parse(item) {
641 Ok(res) => res,
642 Err(e) => return e.to_compile_error().into(),
643 };
644 let gen = quote! {
645 #[linkme::distributed_slice(valkey_module::server_events::REPL_ASYNC_LOAD_SERVER_EVENTS_LIST)]
646 #ast
647 };
648 gen.into()
649}
650
651/// Proc macro which is set on a function that need to be called whenever a swapdb event happens.
652/// The function must accept a [Context] and [u64].
653///
654/// Example:
655///
656/// ```rust,no_run,ignore
657/// #[swapdb_event_handler]
658/// fn swapdb_event_handler(ctx: &Context, _: u64) { ... }
659/// ```
660#[proc_macro_attribute]
661pub fn swapdb_event_handler(_attr: TokenStream, item: TokenStream) -> TokenStream {
662 let ast: ItemFn = match syn::parse(item) {
663 Ok(res) => res,
664 Err(e) => return e.to_compile_error().into(),
665 };
666 let gen = quote! {
667 #[linkme::distributed_slice(valkey_module::server_events::SWAPDB_SERVER_EVENTS_LIST)]
668 #ast
669 };
670 gen.into()
671}