mz_expr/scalar/func/impls/
uint32.rs

1// Copyright Materialize, Inc. and contributors. All rights reserved.
2//
3// Use of this software is governed by the Business Source License
4// included in the LICENSE file.
5//
6// As of the Change Date specified in that file, in accordance with
7// the Business Source License, use of this software will be governed
8// by the Apache License, Version 2.0.
9
10use std::fmt;
11
12use mz_lowertest::MzReflect;
13use mz_repr::adt::numeric::{self, Numeric, NumericMaxScale};
14use mz_repr::{ColumnType, ScalarType, strconv};
15use serde::{Deserialize, Serialize};
16
17use crate::EvalError;
18use crate::scalar::func::EagerUnaryFunc;
19
20sqlfunc!(
21    #[sqlname = "~"]
22    #[preserves_uniqueness = true]
23    #[inverse = to_unary!(super::BitNotUint32)]
24    fn bit_not_uint32(a: u32) -> u32 {
25        !a
26    }
27);
28
29sqlfunc!(
30    #[sqlname = "uint4_to_real"]
31    #[preserves_uniqueness = false]
32    #[inverse = to_unary!(super::CastFloat32ToUint32)]
33    #[is_monotone = true]
34    fn cast_uint32_to_float32(a: u32) -> f32 {
35        // TODO(benesch): remove potentially dangerous usage of `as`.
36        #[allow(clippy::as_conversions)]
37        {
38            a as f32
39        }
40    }
41);
42
43sqlfunc!(
44    #[sqlname = "uint4_to_double"]
45    #[preserves_uniqueness = true]
46    #[inverse = to_unary!(super::CastFloat64ToUint32)]
47    #[is_monotone = true]
48    fn cast_uint32_to_float64(a: u32) -> f64 {
49        f64::from(a)
50    }
51);
52
53sqlfunc!(
54    #[sqlname = "uint4_to_uint2"]
55    #[preserves_uniqueness = true]
56    #[inverse = to_unary!(super::CastUint16ToUint32)]
57    #[is_monotone = true]
58    fn cast_uint32_to_uint16(a: u32) -> Result<u16, EvalError> {
59        u16::try_from(a).or_else(|_| Err(EvalError::UInt16OutOfRange(a.to_string().into())))
60    }
61);
62
63sqlfunc!(
64    #[sqlname = "uint4_to_uint8"]
65    #[preserves_uniqueness = true]
66    #[inverse = to_unary!(super::CastUint64ToUint32)]
67    #[is_monotone = true]
68    fn cast_uint32_to_uint64(a: u32) -> u64 {
69        u64::from(a)
70    }
71);
72
73sqlfunc!(
74    #[sqlname = "uint4_to_smallint"]
75    #[preserves_uniqueness = true]
76    #[inverse = to_unary!(super::CastInt16ToUint32)]
77    #[is_monotone = true]
78    fn cast_uint32_to_int16(a: u32) -> Result<i16, EvalError> {
79        i16::try_from(a).or_else(|_| Err(EvalError::Int16OutOfRange(a.to_string().into())))
80    }
81);
82
83sqlfunc!(
84    #[sqlname = "uint4_to_integer"]
85    #[preserves_uniqueness = true]
86    #[inverse = to_unary!(super::CastInt32ToUint32)]
87    #[is_monotone = true]
88    fn cast_uint32_to_int32(a: u32) -> Result<i32, EvalError> {
89        i32::try_from(a).or_else(|_| Err(EvalError::Int32OutOfRange(a.to_string().into())))
90    }
91);
92
93sqlfunc!(
94    #[sqlname = "uint4_to_bigint"]
95    #[preserves_uniqueness = true]
96    #[inverse = to_unary!(super::CastInt64ToUint32)]
97    #[is_monotone = true]
98    fn cast_uint32_to_int64(a: u32) -> i64 {
99        i64::from(a)
100    }
101);
102
103sqlfunc!(
104    #[sqlname = "uint4_to_text"]
105    #[preserves_uniqueness = true]
106    #[inverse = to_unary!(super::CastStringToUint32)]
107    fn cast_uint32_to_string(a: u32) -> String {
108        let mut buf = String::new();
109        strconv::format_uint32(&mut buf, a);
110        buf
111    }
112);
113
114#[derive(Ord, PartialOrd, Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash, MzReflect)]
115pub struct CastUint32ToNumeric(pub Option<NumericMaxScale>);
116
117impl<'a> EagerUnaryFunc<'a> for CastUint32ToNumeric {
118    type Input = u32;
119    type Output = Result<Numeric, EvalError>;
120
121    fn call(&self, a: u32) -> Result<Numeric, EvalError> {
122        let mut a = Numeric::from(a);
123        if let Some(scale) = self.0 {
124            if numeric::rescale(&mut a, scale.into_u8()).is_err() {
125                return Err(EvalError::NumericFieldOverflow);
126            }
127        }
128        // Besides `rescale`, cast is infallible.
129        Ok(a)
130    }
131
132    fn output_type(&self, input: ColumnType) -> ColumnType {
133        ScalarType::Numeric { max_scale: self.0 }.nullable(input.nullable)
134    }
135
136    fn could_error(&self) -> bool {
137        self.0.is_some()
138    }
139
140    fn inverse(&self) -> Option<crate::UnaryFunc> {
141        to_unary!(super::CastNumericToUint32)
142    }
143
144    fn is_monotone(&self) -> bool {
145        true
146    }
147}
148
149impl fmt::Display for CastUint32ToNumeric {
150    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
151        f.write_str("uint4_to_numeric")
152    }
153}