risingwave_common/types/macros.rs
1// Copyright 2025 RisingWave Labs
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15/// `for_all_variants` includes all variants of our type system. If you introduced a new array type
16/// (also known as scalar type or physical type), be sure to add a variant here.
17///
18/// It is used to simplify the boilerplate code of repeating all array types, while each type
19/// has exactly the same code.
20///
21/// Take `Utf8` as an example, the layout of the variant is:
22/// - `$data_type: Varchar` data type variant name, e.g. `DataType::Varchar`
23/// - `$variant_name: Utf8` array type variant name, e.g. `ArrayImpl::Utf8`, `ScalarImpl::Utf8`
24/// - `$suffix_name: utf8` the suffix of some functions, e.g. `ArrayImpl::as_utf8`
25/// - `$scalar: Box<str>` the scalar type, e.g. `ScalarImpl::Utf8(Box<str>)`
26/// - `$scalar_ref: &'scalar str` the scalar reference type, e.g. `ScalarRefImpl::Utf8(&'scalar
27/// str)`
28/// - `$array: Utf8Array` the array type, e.g. `ArrayImpl::Utf8(Utf8Array)`
29/// - `$builder: Utf8ArrayBuilder` the array builder type, e.g.
30/// `ArrayBuilderImpl::Utf8(Utf8ArrayBuilder)`
31///
32/// To use it, one need to provide another macro which accepts arguments in the layout described
33/// above. Refer to the following implementations as examples.
34///
35/// **Note**: See also `dispatch_xx_variants` and `dispatch_data_types` which doesn't require
36/// another macro for the implementation and can be easier to use in most cases.
37#[macro_export]
38macro_rules! for_all_variants {
39 ($macro:ident $(, $x:tt)*) => {
40 $macro! {
41 $($x, )*
42 //data_type variant_name suffix_name scalar scalar_ref array builder
43 { Int16, Int16, int16, i16, i16, $crate::array::I16Array, $crate::array::I16ArrayBuilder },
44 { Int32, Int32, int32, i32, i32, $crate::array::I32Array, $crate::array::I32ArrayBuilder },
45 { Int64, Int64, int64, i64, i64, $crate::array::I64Array, $crate::array::I64ArrayBuilder },
46 { Int256, Int256, int256, $crate::types::Int256, $crate::types::Int256Ref<'scalar>, $crate::array::Int256Array, $crate::array::Int256ArrayBuilder },
47 { Float32, Float32, float32, $crate::types::F32, $crate::types::F32, $crate::array::F32Array, $crate::array::F32ArrayBuilder },
48 { Float64, Float64, float64, $crate::types::F64, $crate::types::F64, $crate::array::F64Array, $crate::array::F64ArrayBuilder },
49 { Varchar, Utf8, utf8, Box<str>, &'scalar str, $crate::array::Utf8Array, $crate::array::Utf8ArrayBuilder },
50 { Boolean, Bool, bool, bool, bool, $crate::array::BoolArray, $crate::array::BoolArrayBuilder },
51 { Decimal, Decimal, decimal, $crate::types::Decimal, $crate::types::Decimal, $crate::array::DecimalArray, $crate::array::DecimalArrayBuilder },
52 { Interval, Interval, interval, $crate::types::Interval, $crate::types::Interval, $crate::array::IntervalArray, $crate::array::IntervalArrayBuilder },
53 { Date, Date, date, $crate::types::Date, $crate::types::Date, $crate::array::DateArray, $crate::array::DateArrayBuilder },
54 { Time, Time, time, $crate::types::Time, $crate::types::Time, $crate::array::TimeArray, $crate::array::TimeArrayBuilder },
55 { Timestamp, Timestamp, timestamp, $crate::types::Timestamp, $crate::types::Timestamp, $crate::array::TimestampArray, $crate::array::TimestampArrayBuilder },
56 { Timestamptz, Timestamptz, timestamptz, $crate::types::Timestamptz, $crate::types::Timestamptz, $crate::array::TimestamptzArray, $crate::array::TimestamptzArrayBuilder },
57 { Jsonb, Jsonb, jsonb, $crate::types::JsonbVal, $crate::types::JsonbRef<'scalar>, $crate::array::JsonbArray, $crate::array::JsonbArrayBuilder },
58 { Serial, Serial, serial, $crate::types::Serial, $crate::types::Serial, $crate::array::SerialArray, $crate::array::SerialArrayBuilder },
59 { Struct, Struct, struct, $crate::types::StructValue, $crate::types::StructRef<'scalar>, $crate::array::StructArray, $crate::array::StructArrayBuilder },
60 { List, List, list, $crate::types::ListValue, $crate::types::ListRef<'scalar>, $crate::array::ListArray, $crate::array::ListArrayBuilder },
61 { Map, Map, map, $crate::types::MapValue, $crate::types::MapRef<'scalar>, $crate::array::MapArray, $crate::array::MapArrayBuilder },
62 { Vector, Vector, vector, $crate::types::VectorVal, $crate::types::VectorRef<'scalar>, $crate::array::VectorArray, $crate::array::VectorArrayBuilder },
63 { Bytea, Bytea, bytea, Box<[u8]>, &'scalar [u8], $crate::array::BytesArray, $crate::array::BytesArrayBuilder }
64 }
65 };
66}
67
68/// Helper macro for expanding type aliases and constants. Internally used by `dispatch_` macros.
69#[macro_export]
70macro_rules! do_expand_alias {
71 ($array:ty, $variant_name:ident, (
72 $(Array, $array_alias:ident,)?
73 $(ArrayBuilder, $array_builder_alias:ident,)?
74 $(Scalar, $scalar_alias:ident,)?
75 $(ScalarRef, $scalar_ref_alias:ident,)?
76 $(VARIANT_NAME, $variant_name_alias:ident,)?
77 )) => {
78 $(type $array_alias = $array;)?
79 $(type $array_builder_alias = <$array as $crate::array::Array>::Builder;)?
80 $(type $scalar_alias = <$array as $crate::array::Array>::OwnedItem;)?
81 $(type $scalar_ref_alias<'scalar> = <$array as $crate::array::Array>::RefItem<'scalar>;)?
82 $(const $variant_name_alias: &'static str = stringify!($variant_name);)?
83 };
84}
85
86/// Helper macro for generating dispatching code. Internally used by `dispatch_xx_variants` macros.
87#[macro_export(local_inner_macros)]
88macro_rules! do_dispatch_variants {
89 // Use `tt` for `$alias` as a workaround of nested repetition.
90 ($impl:expr, $type:ident, $inner:pat, [$alias:tt], $body:tt, $( { $data_type:ident, $variant_name:ident, $suffix_name:ident, $scalar:ty, $scalar_ref:ty, $array:ty, $builder:ty } ),*) => {
91 match $impl {
92 $( $type::$variant_name($inner) => {
93 do_expand_alias!($array, $variant_name, $alias);
94 #[allow(unused_braces)]
95 $body
96 }, )*
97 }
98 };
99}
100
101/// Dispatch the code block to all variants of `ArrayImpl`.
102///
103/// # Usage
104///
105/// The basic usage to access the inner concrete `impl Array` value is:
106///
107/// ```ignore
108/// fn do_stuff<A: Array>(array: &A) { .. }
109///
110/// fn do_stuff_dispatch(array_impl: &ArrayImpl) {
111/// dispatch_array_variants!(array_impl, array, {
112/// do_stuff(array)
113/// })
114/// }
115/// ```
116///
117/// One can also bind the inner concrete `impl Array` type to an alias:
118///
119/// ```ignore
120/// fn do_stuff<A: Array>() { .. }
121///
122/// fn do_stuff_dispatch(array_impl: &ArrayImpl) {
123/// dispatch_array_variants!(array_impl, [A = Array], {
124/// do_stuff::<A>()
125/// })
126/// }
127/// ```
128///
129/// There're more to bind, including type aliases of associated `ArrayBuilder`, `Scalar`, and
130/// `ScalarRef`, or even the constant string of the variant name `VARIANT_NAME`. This can be
131/// achieved by writing one or more of them in the square brackets. Due to the limitation of macro,
132/// the order of the bindings matters.
133///
134/// ```ignore
135/// fn do_stuff_dispatch(array_impl: &ArrayImpl) {
136/// dispatch_array_variants!(
137/// array_impl,
138/// [A = Array, B = ArrayBuilder, S = Scalar, R = ScalarRef, N = VARIANT_NAME],
139/// { .. }
140/// )
141/// }
142/// ```
143///
144/// Alias bindings can also be used along with the inner value accessing:
145///
146/// ```ignore
147/// fn do_stuff<A: Array>(array: &A) { .. }
148///
149/// fn do_stuff_dispatch(array_impl: &ArrayImpl) {
150/// dispatch_array_variants!(array_impl, array, [A = Array], {
151/// do_stuff::<A>(array)
152/// })
153/// }
154/// ```
155#[macro_export(local_inner_macros)]
156macro_rules! dispatch_array_variants {
157 ($impl:expr, [$($k:ident = $v:ident),*], $body:tt) => {
158 dispatch_array_variants!($impl, _, [$($k = $v),*], $body)
159 };
160 ($impl:expr, $inner:pat, $body:tt) => {
161 dispatch_array_variants!($impl, $inner, [], $body)
162 };
163 // Switch the order of alias bindings to avoid ambiguousness.
164 ($impl:expr, $inner:pat, [$($k:ident = $v:ident),*], $body:tt) => {{
165 use $crate::array::ArrayImpl;
166 for_all_variants! { do_dispatch_variants, $impl, ArrayImpl, $inner, [($($v, $k,)*)], $body }
167 }};
168}
169
170/// Dispatch the code block to all variants of `ArrayBuilderImpl`.
171///
172/// Refer to [`dispatch_array_variants`] for usage.
173// TODO: avoid duplication by `macro_metavar_expr` feature
174#[macro_export(local_inner_macros)]
175macro_rules! dispatch_array_builder_variants {
176 ($impl:expr, [$($k:ident = $v:ident),*], $body:tt) => {
177 dispatch_array_builder_variants!($impl, _, [$($k = $v),*], $body)
178 };
179 ($impl:expr, $inner:pat, $body:tt) => {
180 dispatch_array_builder_variants!($impl, $inner, [], $body)
181 };
182 ($impl:expr, $inner:pat, [$($k:ident = $v:ident),*], $body:tt) => {{
183 use $crate::array::ArrayBuilderImpl;
184 for_all_variants! { do_dispatch_variants, $impl, ArrayBuilderImpl, $inner, [($($v, $k,)*)], $body }
185 }};
186}
187
188/// Dispatch the code block to all variants of `ScalarImpl`.
189///
190/// Refer to [`dispatch_array_variants`] for usage.
191// TODO: avoid duplication by `macro_metavar_expr` feature
192#[macro_export(local_inner_macros)]
193macro_rules! dispatch_scalar_variants {
194 ($impl:expr, [$($k:ident = $v:ident),*], $body:tt) => {
195 dispatch_scalar_variants!($impl, _, [$($k = $v),*], $body)
196 };
197 ($impl:expr, $inner:pat, $body:tt) => {
198 dispatch_scalar_variants!($impl, $inner, [], $body)
199 };
200 ($impl:expr, $inner:pat, [$($k:ident = $v:ident),*], $body:tt) => {{
201 use $crate::types::ScalarImpl;
202 for_all_variants! { do_dispatch_variants, $impl, ScalarImpl, $inner, [($($v, $k,)*)], $body }
203 }};
204}
205
206/// Dispatch the code block to all variants of `ScalarRefImpl`.
207///
208/// Refer to [`dispatch_array_variants`] for usage.
209// TODO: avoid duplication by `macro_metavar_expr` feature
210#[macro_export(local_inner_macros)]
211macro_rules! dispatch_scalar_ref_variants {
212 ($impl:expr, [$($k:ident = $v:ident),*], $body:tt) => {
213 dispatch_scalar_ref_variants!($impl, _, [$($k = $v),*], $body)
214 };
215 ($impl:expr, $inner:pat, $body:tt) => {
216 dispatch_scalar_ref_variants!($impl, $inner, [], $body)
217 };
218 ($impl:expr, $inner:pat, [$($k:ident = $v:ident),*], $body:tt) => {{
219 use $crate::types::ScalarRefImpl;
220 for_all_variants! { do_dispatch_variants, $impl, ScalarRefImpl, $inner, [($($v, $k,)*)], $body }
221 }};
222}
223
224/// Helper macro for generating dispatching code. Internally used by `dispatch_data_types` macros.
225#[macro_export(local_inner_macros)]
226macro_rules! do_dispatch_data_types {
227 ($impl:expr, [$alias:tt], $body:tt, $( { $data_type:ident, $variant_name:ident, $suffix_name:ident, $scalar:ty, $scalar_ref:ty, $array:ty, $builder:ty } ),*) => {
228 match $impl {
229 $( $crate::types::DataType::$data_type { .. } => {
230 do_expand_alias!($array, $variant_name, $alias);
231 #[allow(unused_braces)]
232 $body
233 }, )*
234 }
235 };
236}
237
238/// Dispatch the code block to all variants of `DataType`.
239///
240/// There's no inner value to access, so only alias bindings are supported. Refer to
241/// [`dispatch_array_variants`] for usage.
242#[macro_export(local_inner_macros)]
243macro_rules! dispatch_data_types {
244 ($impl:expr, [$($k:ident = $v:ident),*], $body:tt) => {
245 for_all_variants! { do_dispatch_data_types, $impl, [($($v, $k,)*)], $body }
246 };
247}