risingwave_common/types/macros.rs
1// Copyright 2023 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 { Variant, Variant, variant, $crate::types::VariantVal, $crate::types::VariantRef<'scalar>, $crate::array::VariantArray, $crate::array::VariantArrayBuilder },
59 { Serial, Serial, serial, $crate::types::Serial, $crate::types::Serial, $crate::array::SerialArray, $crate::array::SerialArrayBuilder },
60 { Struct, Struct, struct, $crate::types::StructValue, $crate::types::StructRef<'scalar>, $crate::array::StructArray, $crate::array::StructArrayBuilder },
61 { List, List, list, $crate::types::ListValue, $crate::types::ListRef<'scalar>, $crate::array::ListArray, $crate::array::ListArrayBuilder },
62 { Map, Map, map, $crate::types::MapValue, $crate::types::MapRef<'scalar>, $crate::array::MapArray, $crate::array::MapArrayBuilder },
63 { Vector, Vector, vector, $crate::types::VectorVal, $crate::types::VectorRef<'scalar>, $crate::array::VectorArray, $crate::array::VectorArrayBuilder },
64 { Bytea, Bytea, bytea, Box<[u8]>, &'scalar [u8], $crate::array::BytesArray, $crate::array::BytesArrayBuilder }
65 }
66 };
67}
68
69/// Helper macro for expanding type aliases and constants. Internally used by `dispatch_` macros.
70#[macro_export]
71macro_rules! do_expand_alias {
72 ($array:ty, $variant_name:ident, (
73 $(Array, $array_alias:ident,)?
74 $(ArrayBuilder, $array_builder_alias:ident,)?
75 $(Scalar, $scalar_alias:ident,)?
76 $(ScalarRef, $scalar_ref_alias:ident,)?
77 $(VARIANT_NAME, $variant_name_alias:ident,)?
78 )) => {
79 $(type $array_alias = $array;)?
80 $(type $array_builder_alias = <$array as $crate::array::Array>::Builder;)?
81 $(type $scalar_alias = <$array as $crate::array::Array>::OwnedItem;)?
82 $(type $scalar_ref_alias<'scalar> = <$array as $crate::array::Array>::RefItem<'scalar>;)?
83 $(const $variant_name_alias: &'static str = stringify!($variant_name);)?
84 };
85}
86
87/// Helper macro for generating dispatching code. Internally used by `dispatch_xx_variants` macros.
88#[macro_export(local_inner_macros)]
89macro_rules! do_dispatch_variants {
90 // Use `tt` for `$alias` as a workaround of nested repetition.
91 ($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 } ),*) => {
92 match $impl {
93 $( $type::$variant_name($inner) => {
94 do_expand_alias!($array, $variant_name, $alias);
95 #[allow(unused_braces)]
96 $body
97 }, )*
98 }
99 };
100}
101
102/// Dispatch the code block to all variants of `ArrayImpl`.
103///
104/// # Usage
105///
106/// The basic usage to access the inner concrete `impl Array` value is:
107///
108/// ```ignore
109/// fn do_stuff<A: Array>(array: &A) { .. }
110///
111/// fn do_stuff_dispatch(array_impl: &ArrayImpl) {
112/// dispatch_array_variants!(array_impl, array, {
113/// do_stuff(array)
114/// })
115/// }
116/// ```
117///
118/// One can also bind the inner concrete `impl Array` type to an alias:
119///
120/// ```ignore
121/// fn do_stuff<A: Array>() { .. }
122///
123/// fn do_stuff_dispatch(array_impl: &ArrayImpl) {
124/// dispatch_array_variants!(array_impl, [A = Array], {
125/// do_stuff::<A>()
126/// })
127/// }
128/// ```
129///
130/// There're more to bind, including type aliases of associated `ArrayBuilder`, `Scalar`, and
131/// `ScalarRef`, or even the constant string of the variant name `VARIANT_NAME`. This can be
132/// achieved by writing one or more of them in the square brackets. Due to the limitation of macro,
133/// the order of the bindings matters.
134///
135/// ```ignore
136/// fn do_stuff_dispatch(array_impl: &ArrayImpl) {
137/// dispatch_array_variants!(
138/// array_impl,
139/// [A = Array, B = ArrayBuilder, S = Scalar, R = ScalarRef, N = VARIANT_NAME],
140/// { .. }
141/// )
142/// }
143/// ```
144///
145/// Alias bindings can also be used along with the inner value accessing:
146///
147/// ```ignore
148/// fn do_stuff<A: Array>(array: &A) { .. }
149///
150/// fn do_stuff_dispatch(array_impl: &ArrayImpl) {
151/// dispatch_array_variants!(array_impl, array, [A = Array], {
152/// do_stuff::<A>(array)
153/// })
154/// }
155/// ```
156#[macro_export(local_inner_macros)]
157macro_rules! dispatch_array_variants {
158 ($impl:expr, [$($k:ident = $v:ident),*], $body:tt) => {
159 dispatch_array_variants!($impl, _, [$($k = $v),*], $body)
160 };
161 ($impl:expr, $inner:pat, $body:tt) => {
162 dispatch_array_variants!($impl, $inner, [], $body)
163 };
164 // Switch the order of alias bindings to avoid ambiguousness.
165 ($impl:expr, $inner:pat, [$($k:ident = $v:ident),*], $body:tt) => {{
166 use $crate::array::ArrayImpl;
167 for_all_variants! { do_dispatch_variants, $impl, ArrayImpl, $inner, [($($v, $k,)*)], $body }
168 }};
169}
170
171/// Dispatch the code block to all variants of `ArrayBuilderImpl`.
172///
173/// Refer to [`dispatch_array_variants`] for usage.
174// TODO: avoid duplication by `macro_metavar_expr` feature
175#[macro_export(local_inner_macros)]
176macro_rules! dispatch_array_builder_variants {
177 ($impl:expr, [$($k:ident = $v:ident),*], $body:tt) => {
178 dispatch_array_builder_variants!($impl, _, [$($k = $v),*], $body)
179 };
180 ($impl:expr, $inner:pat, $body:tt) => {
181 dispatch_array_builder_variants!($impl, $inner, [], $body)
182 };
183 ($impl:expr, $inner:pat, [$($k:ident = $v:ident),*], $body:tt) => {{
184 use $crate::array::ArrayBuilderImpl;
185 for_all_variants! { do_dispatch_variants, $impl, ArrayBuilderImpl, $inner, [($($v, $k,)*)], $body }
186 }};
187}
188
189/// Dispatch the code block to all variants of `ScalarImpl`.
190///
191/// Refer to [`dispatch_array_variants`] for usage.
192// TODO: avoid duplication by `macro_metavar_expr` feature
193#[macro_export(local_inner_macros)]
194macro_rules! dispatch_scalar_variants {
195 ($impl:expr, [$($k:ident = $v:ident),*], $body:tt) => {
196 dispatch_scalar_variants!($impl, _, [$($k = $v),*], $body)
197 };
198 ($impl:expr, $inner:pat, $body:tt) => {
199 dispatch_scalar_variants!($impl, $inner, [], $body)
200 };
201 ($impl:expr, $inner:pat, [$($k:ident = $v:ident),*], $body:tt) => {{
202 use $crate::types::ScalarImpl;
203 for_all_variants! { do_dispatch_variants, $impl, ScalarImpl, $inner, [($($v, $k,)*)], $body }
204 }};
205}
206
207/// Dispatch the code block to all variants of `ScalarRefImpl`.
208///
209/// Refer to [`dispatch_array_variants`] for usage.
210// TODO: avoid duplication by `macro_metavar_expr` feature
211#[macro_export(local_inner_macros)]
212macro_rules! dispatch_scalar_ref_variants {
213 ($impl:expr, [$($k:ident = $v:ident),*], $body:tt) => {
214 dispatch_scalar_ref_variants!($impl, _, [$($k = $v),*], $body)
215 };
216 ($impl:expr, $inner:pat, $body:tt) => {
217 dispatch_scalar_ref_variants!($impl, $inner, [], $body)
218 };
219 ($impl:expr, $inner:pat, [$($k:ident = $v:ident),*], $body:tt) => {{
220 use $crate::types::ScalarRefImpl;
221 for_all_variants! { do_dispatch_variants, $impl, ScalarRefImpl, $inner, [($($v, $k,)*)], $body }
222 }};
223}
224
225/// Helper macro for generating dispatching code. Internally used by `dispatch_data_types` macros.
226#[macro_export(local_inner_macros)]
227macro_rules! do_dispatch_data_types {
228 ($impl:expr, [$alias:tt], $body:tt, $( { $data_type:ident, $variant_name:ident, $suffix_name:ident, $scalar:ty, $scalar_ref:ty, $array:ty, $builder:ty } ),*) => {
229 match $impl {
230 $( $crate::types::DataType::$data_type { .. } => {
231 do_expand_alias!($array, $variant_name, $alias);
232 #[allow(unused_braces)]
233 $body
234 }, )*
235 }
236 };
237}
238
239/// Dispatch the code block to all variants of `DataType`.
240///
241/// There's no inner value to access, so only alias bindings are supported. Refer to
242/// [`dispatch_array_variants`] for usage.
243#[macro_export(local_inner_macros)]
244macro_rules! dispatch_data_types {
245 ($impl:expr, [$($k:ident = $v:ident),*], $body:tt) => {
246 for_all_variants! { do_dispatch_data_types, $impl, [($($v, $k,)*)], $body }
247 };
248}