@@ -58,3 +58,139 @@ macro_rules! match_each_decimal_value_type {
5858 }
5959 } } ;
6060}
61+
62+ /// Dispatches a decimal input and output type, instantiating only `In <= Out`.
63+ /// This produces 21 type combinations instead of 36.
64+ ///
65+ /// The caller must choose an output type at least as wide as the input storage type.
66+ /// A decimal array's storage is no wider than
67+ /// [`DecimalType::smallest_decimal_value_type`](crate::dtype::DecimalType::smallest_decimal_value_type)
68+ /// for its precision, so using that type (or a wider working type) satisfies this contract.
69+ /// Narrowing casts must use unrestricted dispatch instead. Invalid combinations panic.
70+ /// Each type expression is evaluated once.
71+ ///
72+ /// ```
73+ /// use num_traits::AsPrimitive;
74+ /// use vortex_array::dtype::DecimalType;
75+ /// use vortex_array::match_decimal_unary;
76+ ///
77+ /// let value = match_decimal_unary!(DecimalType::I8, DecimalType::I64, |In, Out| {
78+ /// let input: In = 42i8.as_();
79+ /// <In as AsPrimitive<Out>>::as_(input).to_string()
80+ /// });
81+ /// assert_eq!(value, "42");
82+ /// ```
83+ #[ macro_export]
84+ macro_rules! match_decimal_unary {
85+ ( $input: expr, $output: expr, | $in: ident, $out: ident | $body: block) => { {
86+ let ( input, output) = ( $input, $output) ;
87+ match output {
88+ $crate:: dtype:: DecimalType :: I8 => {
89+ type $out = i8 ;
90+ $crate:: match_decimal_unary!( @input input, |$in| $body; I8 => i8 )
91+ }
92+ $crate:: dtype:: DecimalType :: I16 => {
93+ type $out = i16 ;
94+ $crate:: match_decimal_unary!( @input input, |$in| $body; I8 => i8 , I16 => i16 )
95+ }
96+ $crate:: dtype:: DecimalType :: I32 => {
97+ type $out = i32 ;
98+ $crate:: match_decimal_unary!( @input input, |$in| $body; I8 => i8 , I16 => i16 , I32 => i32 )
99+ }
100+ $crate:: dtype:: DecimalType :: I64 => {
101+ type $out = i64 ;
102+ $crate:: match_decimal_unary!( @input input, |$in| $body; I8 => i8 , I16 => i16 , I32 => i32 , I64 => i64 )
103+ }
104+ $crate:: dtype:: DecimalType :: I128 => {
105+ type $out = i128 ;
106+ $crate:: match_decimal_unary!( @input input, |$in| $body; I8 => i8 , I16 => i16 , I32 => i32 , I64 => i64 , I128 => i128 )
107+ }
108+ $crate:: dtype:: DecimalType :: I256 => {
109+ type $out = $crate:: dtype:: i256;
110+ $crate:: match_decimal_unary!( @input input, |$in| $body; I8 => i8 , I16 => i16 , I32 => i32 , I64 => i64 , I128 => i128 , I256 => $crate:: dtype:: i256)
111+ }
112+ }
113+ } } ;
114+ ( @input $input: expr, | $in: ident | $body: block; $( $variant: ident => $native: ty ) ,+) => { {
115+ #[ allow( unreachable_patterns) ]
116+ match $input {
117+ $(
118+ $crate:: dtype:: DecimalType :: $variant => {
119+ type $in = $native;
120+ $body
121+ }
122+ ) +
123+ _ => panic!( "decimal input storage type must be no wider than the output type" ) ,
124+ }
125+ } } ;
126+ }
127+
128+ /// Dispatches two decimal input types and an output type, instantiating only combinations
129+ /// where both inputs are no wider than the output (`Left <= Out` and `Right <= Out`).
130+ ///
131+ /// This produces 91 type combinations instead of the 216 from unrestricted nested dispatch.
132+ /// See [`match_decimal_unary!`] for the storage contract. Invalid combinations panic.
133+ /// Each type expression is evaluated once, from left to right.
134+ ///
135+ /// ```
136+ /// use num_traits::AsPrimitive;
137+ /// use vortex_array::dtype::DecimalType;
138+ /// use vortex_array::match_decimal_binary;
139+ ///
140+ /// let value = match_decimal_binary!(
141+ /// DecimalType::I8, DecimalType::I16, DecimalType::I64, |Left, Right, Out| {
142+ /// let lhs: Left = 1i8.as_();
143+ /// let rhs: Right = 2i8.as_();
144+ /// (<Left as AsPrimitive<Out>>::as_(lhs) + <Right as AsPrimitive<Out>>::as_(rhs)).to_string()
145+ /// }
146+ /// );
147+ /// assert_eq!(value, "3");
148+ /// ```
149+ #[ macro_export]
150+ macro_rules! match_decimal_binary {
151+ ( $left: expr, $right: expr, $output: expr, | $lhs: ident, $rhs: ident, $out: ident | $body: block) => { {
152+ let ( left, right, output) = ( $left, $right, $output) ;
153+ match output {
154+ $crate:: dtype:: DecimalType :: I8 => {
155+ type $out = i8 ;
156+ $crate:: match_decimal_unary!( @input left, |$lhs| {
157+ $crate:: match_decimal_unary!( @input right, |$rhs| $body; I8 => i8 )
158+ } ; I8 => i8 )
159+ }
160+ $crate:: dtype:: DecimalType :: I16 => {
161+ type $out = i16 ;
162+ $crate:: match_decimal_unary!( @input left, |$lhs| {
163+ $crate:: match_decimal_unary!( @input right, |$rhs| $body; I8 => i8 , I16 => i16 )
164+ } ; I8 => i8 , I16 => i16 )
165+ }
166+ $crate:: dtype:: DecimalType :: I32 => {
167+ type $out = i32 ;
168+ $crate:: match_decimal_unary!( @input left, |$lhs| {
169+ $crate:: match_decimal_unary!( @input right, |$rhs| $body; I8 => i8 , I16 => i16 , I32 => i32 )
170+ } ; I8 => i8 , I16 => i16 , I32 => i32 )
171+ }
172+ $crate:: dtype:: DecimalType :: I64 => {
173+ type $out = i64 ;
174+ $crate:: match_decimal_unary!( @input left, |$lhs| {
175+ $crate:: match_decimal_unary!( @input right, |$rhs| $body; I8 => i8 , I16 => i16 , I32 => i32 , I64 => i64 )
176+ } ; I8 => i8 , I16 => i16 , I32 => i32 , I64 => i64 )
177+ }
178+ $crate:: dtype:: DecimalType :: I128 => {
179+ type $out = i128 ;
180+ $crate:: match_decimal_unary!( @input left, |$lhs| {
181+ $crate:: match_decimal_unary!( @input right, |$rhs| $body; I8 => i8 , I16 => i16 , I32 => i32 , I64 => i64 , I128 => i128 )
182+ } ; I8 => i8 , I16 => i16 , I32 => i32 , I64 => i64 , I128 => i128 )
183+ }
184+ $crate:: dtype:: DecimalType :: I256 => {
185+ type $out = $crate:: dtype:: i256;
186+ $crate:: match_decimal_unary!( @input left, |$lhs| {
187+ $crate:: match_decimal_unary!( @input right, |$rhs| $body; I8 => i8 , I16 => i16 , I32 => i32 , I64 => i64 , I128 => i128 , I256 => $crate:: dtype:: i256)
188+ } ; I8 => i8 , I16 => i16 , I32 => i32 , I64 => i64 , I128 => i128 , I256 => $crate:: dtype:: i256)
189+ }
190+ }
191+ } } ;
192+ }
193+
194+ #[ cfg( test) ]
195+ #[ path = "macros_tests.rs" ]
196+ mod tests;
0 commit comments