substrait_validator/input/
proto.rs

1// SPDX-License-Identifier: Apache-2.0
2
3//! Module for representing Substrait protobuf input.
4//!
5//! The structures here are generated using [`prost`], but have a bunch of
6//! extra traits from [`traits`] associated with them,
7//! for which the implementations are generated using
8//! [`substrait_validator_derive`]. The purpose of these traits is to add basic
9//! introspection capabilities to the prost structures. One of the use cases
10//! for this is to let the parsing code automatically detect when the
11//! validation code ignored a subtree while validating, which implies that the
12//! validator hasn't checked everything and thus should not warrant that the
13//! received plan is valid.
14
15use crate::input::traits;
16use crate::output::primitive_data;
17
18use heck::ToUpperCamelCase;
19
20#[allow(
21    clippy::large_enum_variant,
22    clippy::derive_partial_eq_without_eq,
23    clippy::doc_lazy_continuation
24)] // caused by generated code
25pub mod substrait {
26    include!(concat!(env!("OUT_DIR"), "/substrait.rs"));
27    pub mod extensions {
28        include!(concat!(env!("OUT_DIR"), "/substrait.extensions.rs"));
29    }
30    pub mod validator {
31        include!(concat!(env!("OUT_DIR"), "/substrait.validator.rs"));
32    }
33}
34
35/// Converts a Rust module path and name (the latter already processed by
36/// cook_ident()) to a protobuf type path.
37pub fn cook_path(module_path: &str, type_name: &str) -> String {
38    let mut iter = module_path
39        .split("::")
40        .skip(module_path!().split("::").count())
41        .map(cook_ident)
42        .chain(::std::iter::once(type_name))
43        .peekable();
44    let mut items = vec![];
45    if matches!(iter.peek(), Some(&"substrait")) {
46        items.push(iter.next().unwrap().to_string());
47        if matches!(iter.peek(), Some(&"extensions") | Some(&"validator")) {
48            items.push(iter.next().unwrap().to_string());
49        }
50    }
51    items.extend(iter.map(|x| x.to_upper_camel_case()));
52    ::itertools::Itertools::intersperse(items.iter().map(|x| x.as_ref()), ".").collect()
53}
54
55/// Converts a Rust identifier string generated via stringify!() to the
56/// original identifier by "cooking" raw identifiers.
57pub fn cook_ident(ident: &str) -> &str {
58    if let Some((_, keyword)) = ident.split_once('#') {
59        keyword
60    } else {
61        ident
62    }
63}
64
65impl traits::ProtoPrimitive for bool {
66    fn proto_primitive_type() -> &'static str {
67        "bool"
68    }
69
70    fn proto_primitive_default() -> primitive_data::PrimitiveData {
71        primitive_data::PrimitiveData::Bool(false)
72    }
73
74    fn proto_primitive_data(&self) -> primitive_data::PrimitiveData {
75        primitive_data::PrimitiveData::Bool(*self)
76    }
77
78    fn proto_primitive_is_default(&self) -> bool {
79        !*self
80    }
81}
82
83impl traits::ProtoPrimitive for u32 {
84    fn proto_primitive_type() -> &'static str {
85        "uint32"
86    }
87
88    fn proto_primitive_default() -> primitive_data::PrimitiveData {
89        primitive_data::PrimitiveData::Unsigned(0)
90    }
91
92    fn proto_primitive_data(&self) -> primitive_data::PrimitiveData {
93        primitive_data::PrimitiveData::Unsigned((*self).into())
94    }
95
96    fn proto_primitive_is_default(&self) -> bool {
97        *self == 0
98    }
99}
100
101impl traits::ProtoPrimitive for u64 {
102    fn proto_primitive_type() -> &'static str {
103        "uint64"
104    }
105
106    fn proto_primitive_default() -> primitive_data::PrimitiveData {
107        primitive_data::PrimitiveData::Unsigned(0)
108    }
109
110    fn proto_primitive_data(&self) -> primitive_data::PrimitiveData {
111        primitive_data::PrimitiveData::Unsigned(*self)
112    }
113
114    fn proto_primitive_is_default(&self) -> bool {
115        *self == 0
116    }
117}
118
119impl traits::ProtoPrimitive for i32 {
120    fn proto_primitive_type() -> &'static str {
121        "int32"
122    }
123
124    fn proto_primitive_default() -> primitive_data::PrimitiveData {
125        primitive_data::PrimitiveData::Signed(0)
126    }
127
128    fn proto_primitive_data(&self) -> primitive_data::PrimitiveData {
129        primitive_data::PrimitiveData::Signed((*self).into())
130    }
131
132    fn proto_primitive_is_default(&self) -> bool {
133        *self == 0
134    }
135}
136
137impl traits::ProtoPrimitive for i64 {
138    fn proto_primitive_type() -> &'static str {
139        "int64"
140    }
141
142    fn proto_primitive_default() -> primitive_data::PrimitiveData {
143        primitive_data::PrimitiveData::Signed(0)
144    }
145
146    fn proto_primitive_data(&self) -> primitive_data::PrimitiveData {
147        primitive_data::PrimitiveData::Signed(*self)
148    }
149
150    fn proto_primitive_is_default(&self) -> bool {
151        *self == 0
152    }
153}
154
155impl traits::ProtoPrimitive for f32 {
156    fn proto_primitive_type() -> &'static str {
157        "float"
158    }
159
160    fn proto_primitive_default() -> primitive_data::PrimitiveData {
161        primitive_data::PrimitiveData::Float(0.0)
162    }
163
164    fn proto_primitive_data(&self) -> primitive_data::PrimitiveData {
165        primitive_data::PrimitiveData::Float((*self).into())
166    }
167
168    fn proto_primitive_is_default(&self) -> bool {
169        *self == 0.0
170    }
171}
172
173impl traits::ProtoPrimitive for f64 {
174    fn proto_primitive_type() -> &'static str {
175        "double"
176    }
177
178    fn proto_primitive_default() -> primitive_data::PrimitiveData {
179        primitive_data::PrimitiveData::Float(0.0)
180    }
181
182    fn proto_primitive_data(&self) -> primitive_data::PrimitiveData {
183        primitive_data::PrimitiveData::Float(*self)
184    }
185
186    fn proto_primitive_is_default(&self) -> bool {
187        *self == 0.0
188    }
189}
190
191impl traits::ProtoPrimitive for String {
192    fn proto_primitive_type() -> &'static str {
193        "string"
194    }
195
196    fn proto_primitive_default() -> primitive_data::PrimitiveData {
197        primitive_data::PrimitiveData::String(String::new())
198    }
199
200    fn proto_primitive_data(&self) -> primitive_data::PrimitiveData {
201        primitive_data::PrimitiveData::String(self.clone())
202    }
203
204    fn proto_primitive_is_default(&self) -> bool {
205        self.is_empty()
206    }
207}
208
209impl traits::ProtoPrimitive for Vec<u8> {
210    fn proto_primitive_type() -> &'static str {
211        "bytes"
212    }
213
214    fn proto_primitive_default() -> primitive_data::PrimitiveData {
215        primitive_data::PrimitiveData::Bytes(vec![])
216    }
217
218    fn proto_primitive_data(&self) -> primitive_data::PrimitiveData {
219        primitive_data::PrimitiveData::Bytes(self.clone())
220    }
221
222    fn proto_primitive_is_default(&self) -> bool {
223        self.is_empty()
224    }
225}
226
227impl traits::ProtoPrimitive for prost_types::Any {
228    fn proto_primitive_type() -> &'static str {
229        "any"
230    }
231
232    fn proto_primitive_default() -> primitive_data::PrimitiveData {
233        primitive_data::PrimitiveData::Any(prost_types::Any::default())
234    }
235
236    fn proto_primitive_data(&self) -> primitive_data::PrimitiveData {
237        primitive_data::PrimitiveData::Any(self.clone())
238    }
239
240    fn proto_primitive_is_default(&self) -> bool {
241        self.type_url.is_empty()
242    }
243}