pilota_thrift_reflect/
lib.rs

1use std::collections::BTreeMap;
2
3use ahash::AHashMap;
4use descriptor::thrift_reflection::ConstValueType;
5use pilota::{FastStr, OrderedFloat};
6
7include!("descriptor.rs");
8pub use descriptor::*;
9
10pub mod error;
11pub mod service;
12
13pub enum ThriftType {
14    String,
15    Byte,
16    Bool,
17    Binary,
18    I8,
19    I16,
20    I32,
21    I64,
22    Double,
23    Uuid,
24    List,
25    Set,
26    Map,
27    Void,
28    Path(FastStr),
29}
30
31impl std::fmt::Display for ThriftType {
32    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33        match self {
34            ThriftType::String => write!(f, "string"),
35            ThriftType::Byte => write!(f, "byte"),
36            ThriftType::Bool => write!(f, "bool"),
37            ThriftType::Binary => write!(f, "binary"),
38            ThriftType::I8 => write!(f, "i8"),
39            ThriftType::I16 => write!(f, "i16"),
40            ThriftType::I32 => write!(f, "i32"),
41            ThriftType::I64 => write!(f, "i64"),
42            ThriftType::Double => write!(f, "double"),
43            ThriftType::Uuid => write!(f, "uuid"),
44            ThriftType::List => write!(f, "list"),
45            ThriftType::Set => write!(f, "set"),
46            ThriftType::Map => write!(f, "map"),
47            ThriftType::Void => write!(f, "void"),
48            ThriftType::Path(path) => write!(f, "{}", path),
49        }
50    }
51}
52
53impl From<&str> for ThriftType {
54    fn from(s: &str) -> Self {
55        match s {
56            "string" => ThriftType::String,
57            "byte" => ThriftType::Byte,
58            "bool" => ThriftType::Bool,
59            "binary" => ThriftType::Binary,
60            "i8" => ThriftType::I8,
61            "i16" => ThriftType::I16,
62            "i32" => ThriftType::I32,
63            "i64" => ThriftType::I64,
64            "double" => ThriftType::Double,
65            "uuid" => ThriftType::Uuid,
66            "list" => ThriftType::List,
67            "set" => ThriftType::Set,
68            "map" => ThriftType::Map,
69            "void" => ThriftType::Void,
70            _ => ThriftType::Path(FastStr::new(s)),
71        }
72    }
73}
74
75impl From<&pilota_thrift_parser::File> for thrift_reflection::FileDescriptor {
76    fn from(file: &pilota_thrift_parser::File) -> Self {
77        let filepath = FastStr::new(file.path.display().to_string());
78        let mut services = Vec::new();
79        let mut structs = Vec::new();
80        let mut enums = Vec::new();
81        let mut typedefs = Vec::new();
82        let mut consts = Vec::new();
83        let mut includes = AHashMap::new();
84        let mut namespaces = AHashMap::new();
85        let mut exceptions = Vec::new();
86        let mut unions = Vec::new();
87
88        for item in file.items.iter() {
89            match item {
90                pilota_thrift_parser::Item::Include(include) => {
91                    let include_path = file
92                        .path
93                        .parent()
94                        .unwrap_or_else(|| std::path::Path::new(""))
95                        .join(include.path.0.as_str()); // relative path -> absolute path
96
97                    includes.insert(
98                        FastStr::new(
99                            include
100                                .path
101                                .0
102                                .as_str()
103                                .split('/')
104                                .next_back()
105                                .unwrap()
106                                .trim_end_matches(".thrift"),
107                        ),
108                        FastStr::new(include_path.to_string_lossy()),
109                    );
110                }
111                pilota_thrift_parser::Item::Namespace(namespace) => {
112                    namespaces.insert(
113                        FastStr::new(namespace.scope.0.as_str()),
114                        FastStr::new(
115                            namespace
116                                .name
117                                .segments
118                                .iter()
119                                .map(|segment| segment.0.as_ref())
120                                .collect::<Vec<_>>()
121                                .join("."),
122                        ),
123                    );
124                }
125                pilota_thrift_parser::Item::Typedef(typedef) => {
126                    typedefs.push((filepath.clone(), typedef).into());
127                }
128                pilota_thrift_parser::Item::Constant(constant) => {
129                    consts.push((filepath.clone(), constant).into());
130                }
131                pilota_thrift_parser::Item::Enum(enum_) => {
132                    enums.push((filepath.clone(), enum_).into());
133                }
134                pilota_thrift_parser::Item::Struct(struct_) => {
135                    structs.push((filepath.clone(), struct_).into());
136                }
137                pilota_thrift_parser::Item::Union(union) => {
138                    unions.push((filepath.clone(), union).into());
139                }
140                pilota_thrift_parser::Item::Exception(exception) => {
141                    exceptions.push((filepath.clone(), exception).into());
142                }
143                pilota_thrift_parser::Item::Service(service) => {
144                    services.push((filepath.clone(), service).into());
145                }
146                _ => {}
147            }
148        }
149        thrift_reflection::FileDescriptor {
150            filepath,
151            includes,
152            namespaces,
153            services,
154            structs,
155            enums,
156            typedefs,
157            consts,
158            exceptions,
159            unions,
160            ..Default::default()
161        }
162    }
163}
164
165impl From<(FastStr, &pilota_thrift_parser::Service)> for thrift_reflection::ServiceDescriptor {
166    fn from((filepath, service): (FastStr, &pilota_thrift_parser::Service)) -> Self {
167        thrift_reflection::ServiceDescriptor {
168            name: FastStr::new(service.name.0.clone()),
169            filepath: filepath.clone(),
170            methods: service
171                .functions
172                .iter()
173                .map(|function| (filepath.clone(), function).into())
174                .collect(),
175            annotations: Annotations::from(&service.annotations).0,
176            ..Default::default()
177        }
178    }
179}
180
181impl From<(FastStr, &pilota_thrift_parser::Function)> for thrift_reflection::MethodDescriptor {
182    fn from((filepath, function): (FastStr, &pilota_thrift_parser::Function)) -> Self {
183        thrift_reflection::MethodDescriptor {
184            name: FastStr::new(function.name.0.clone()),
185            filepath: filepath.clone(),
186            response: Some((filepath.clone(), &function.result_type).into()),
187            args: function
188                .arguments
189                .iter()
190                .map(|arg| (filepath.clone(), arg).into())
191                .collect(),
192            annotations: Annotations::from(&function.annotations).0,
193            throw_exceptions: function
194                .throws
195                .iter()
196                .map(|exception| (filepath.clone(), exception).into())
197                .collect(),
198            is_oneway: function.oneway,
199            ..Default::default()
200        }
201    }
202}
203
204impl From<(FastStr, &pilota_thrift_parser::Type)> for thrift_reflection::TypeDescriptor {
205    fn from((filepath, r#type): (FastStr, &pilota_thrift_parser::Type)) -> Self {
206        match &r#type.0 {
207            pilota_thrift_parser::Ty::String => thrift_reflection::TypeDescriptor {
208                filepath,
209                name: FastStr::new(ThriftType::String.to_string()),
210                key_type: None,
211                value_type: None,
212                extra: None,
213            },
214            pilota_thrift_parser::Ty::Void => thrift_reflection::TypeDescriptor {
215                filepath,
216                name: FastStr::new(ThriftType::Void.to_string()),
217                key_type: None,
218                value_type: None,
219                extra: None,
220            },
221            pilota_thrift_parser::Ty::Byte => thrift_reflection::TypeDescriptor {
222                filepath,
223                name: FastStr::new(ThriftType::Byte.to_string()),
224                key_type: None,
225                value_type: None,
226                extra: None,
227            },
228            pilota_thrift_parser::Ty::Bool => thrift_reflection::TypeDescriptor {
229                filepath,
230                name: FastStr::new(ThriftType::Bool.to_string()),
231                key_type: None,
232                value_type: None,
233                extra: None,
234            },
235            pilota_thrift_parser::Ty::Binary => thrift_reflection::TypeDescriptor {
236                filepath,
237                name: FastStr::new(ThriftType::Binary.to_string()),
238                key_type: None,
239                value_type: None,
240                extra: None,
241            },
242            pilota_thrift_parser::Ty::I8 => thrift_reflection::TypeDescriptor {
243                filepath,
244                name: FastStr::new(ThriftType::I8.to_string()),
245                key_type: None,
246                value_type: None,
247                extra: None,
248            },
249            pilota_thrift_parser::Ty::I16 => thrift_reflection::TypeDescriptor {
250                filepath,
251                name: FastStr::new(ThriftType::I16.to_string()),
252                key_type: None,
253                value_type: None,
254                extra: None,
255            },
256            pilota_thrift_parser::Ty::I32 => thrift_reflection::TypeDescriptor {
257                filepath,
258                name: FastStr::new(ThriftType::I32.to_string()),
259                key_type: None,
260                value_type: None,
261                extra: None,
262            },
263            pilota_thrift_parser::Ty::I64 => thrift_reflection::TypeDescriptor {
264                filepath,
265                name: FastStr::new(ThriftType::I64.to_string()),
266                key_type: None,
267                value_type: None,
268                extra: None,
269            },
270            pilota_thrift_parser::Ty::Double => thrift_reflection::TypeDescriptor {
271                filepath,
272                name: FastStr::new(ThriftType::Double.to_string()),
273                key_type: None,
274                value_type: None,
275                extra: None,
276            },
277            pilota_thrift_parser::Ty::Uuid => thrift_reflection::TypeDescriptor {
278                filepath,
279                name: FastStr::new(ThriftType::Uuid.to_string()),
280                key_type: None,
281                value_type: None,
282                extra: None,
283            },
284            pilota_thrift_parser::Ty::List { value, .. } => thrift_reflection::TypeDescriptor {
285                filepath: filepath.clone(),
286                name: FastStr::new(ThriftType::List.to_string()),
287                key_type: None,
288                value_type: Some(Box::new((filepath, value.as_ref()).into())),
289                extra: None,
290            },
291            pilota_thrift_parser::Ty::Set { value, .. } => thrift_reflection::TypeDescriptor {
292                filepath: filepath.clone(),
293                name: FastStr::new(ThriftType::Set.to_string()),
294                key_type: None,
295                value_type: Some(Box::new((filepath, value.as_ref()).into())),
296                extra: None,
297            },
298            pilota_thrift_parser::Ty::Map { key, value, .. } => thrift_reflection::TypeDescriptor {
299                filepath: filepath.clone(),
300                name: FastStr::new(ThriftType::Map.to_string()),
301                key_type: Some(Box::new((filepath.clone(), key.as_ref()).into())),
302                value_type: Some(Box::new((filepath, value.as_ref()).into())),
303                extra: None,
304            },
305            pilota_thrift_parser::Ty::Path(path) => thrift_reflection::TypeDescriptor {
306                filepath: filepath.clone(),
307                name: FastStr::new(
308                    path.segments
309                        .iter()
310                        .map(|segment| segment.0.clone())
311                        .collect::<Vec<_>>()
312                        .join("."),
313                ),
314                key_type: None,
315                value_type: None,
316                extra: None,
317            },
318        }
319    }
320}
321
322impl From<(FastStr, &pilota_thrift_parser::Field)> for thrift_reflection::FieldDescriptor {
323    fn from((filepath, field): (FastStr, &pilota_thrift_parser::Field)) -> Self {
324        thrift_reflection::FieldDescriptor {
325            name: FastStr::new(field.name.0.clone()),
326            filepath: filepath.clone(),
327            r#type: (filepath.clone(), &field.ty).into(),
328            requiredness: match field.attribute {
329                pilota_thrift_parser::Attribute::Optional => "optional",
330                pilota_thrift_parser::Attribute::Required => "required",
331                pilota_thrift_parser::Attribute::Default => "default",
332            }
333            .into(),
334            id: field.id,
335            default_value: field.default.as_ref().map(|default| default.into()),
336            annotations: Annotations::from(&field.annotations).0,
337            ..Default::default()
338        }
339    }
340}
341
342impl From<&pilota_thrift_parser::ConstValue> for thrift_reflection::ConstValueDescriptor {
343    fn from(const_value: &pilota_thrift_parser::ConstValue) -> Self {
344        match const_value {
345            pilota_thrift_parser::ConstValue::Bool(bool) => {
346                thrift_reflection::ConstValueDescriptor {
347                    r#type: ConstValueType::BOOL,
348                    value_bool: *bool,
349                    ..Default::default()
350                }
351            }
352            pilota_thrift_parser::ConstValue::Path(path) => {
353                thrift_reflection::ConstValueDescriptor {
354                    r#type: ConstValueType::IDENTIFIER,
355                    value_identifier: FastStr::new(
356                        path.segments
357                            .iter()
358                            .map(|segment| segment.0.as_ref())
359                            .collect::<Vec<_>>()
360                            .join("."),
361                    ),
362                    ..Default::default()
363                }
364            }
365            pilota_thrift_parser::ConstValue::String(string) => {
366                thrift_reflection::ConstValueDescriptor {
367                    r#type: ConstValueType::STRING,
368                    value_string: FastStr::new(string.0.clone()),
369                    ..Default::default()
370                }
371            }
372            pilota_thrift_parser::ConstValue::Int(int) => thrift_reflection::ConstValueDescriptor {
373                r#type: ConstValueType::INT,
374                value_int: int.0,
375                ..Default::default()
376            },
377            pilota_thrift_parser::ConstValue::Double(double) => {
378                thrift_reflection::ConstValueDescriptor {
379                    r#type: ConstValueType::DOUBLE,
380                    value_double: OrderedFloat::from(double.0.clone().parse::<f64>().unwrap()),
381                    ..Default::default()
382                }
383            }
384            pilota_thrift_parser::ConstValue::List(list) => {
385                thrift_reflection::ConstValueDescriptor {
386                    r#type: ConstValueType::LIST,
387                    value_list: Some(list.iter().map(|item| item.into()).collect()),
388                    ..Default::default()
389                }
390            }
391            pilota_thrift_parser::ConstValue::Map(map) => {
392                let mut bmap = BTreeMap::new();
393                for (key, value) in map {
394                    bmap.insert(key.into(), value.into());
395                }
396                thrift_reflection::ConstValueDescriptor {
397                    r#type: ConstValueType::MAP,
398                    value_map: Some(bmap),
399                    ..Default::default()
400                }
401            }
402        }
403    }
404}
405
406pub struct Annotations(pub AHashMap<FastStr, Vec<FastStr>>);
407
408impl From<&pilota_thrift_parser::Annotations> for Annotations {
409    fn from(annos: &pilota_thrift_parser::Annotations) -> Self {
410        let mut map = AHashMap::new();
411        for anno in annos.iter() {
412            map.insert(
413                FastStr::new(anno.key.clone()),
414                vec![FastStr::new(anno.value.to_string())],
415            );
416        }
417        Annotations(map)
418    }
419}
420
421impl From<(FastStr, &pilota_thrift_parser::Struct)> for thrift_reflection::StructDescriptor {
422    fn from((filepath, struct_): (FastStr, &pilota_thrift_parser::Struct)) -> Self {
423        thrift_reflection::StructDescriptor {
424            name: FastStr::new(struct_.name.0.clone()),
425            filepath: filepath.clone(),
426            fields: struct_
427                .fields
428                .iter()
429                .map(|field| (filepath.clone(), field).into())
430                .collect(),
431            annotations: Annotations::from(&struct_.annotations).0,
432            ..Default::default()
433        }
434    }
435}
436
437impl From<(FastStr, &pilota_thrift_parser::Typedef)> for thrift_reflection::TypedefDescriptor {
438    fn from((filepath, typedef): (FastStr, &pilota_thrift_parser::Typedef)) -> Self {
439        thrift_reflection::TypedefDescriptor {
440            filepath: filepath.clone(),
441            r#type: (filepath, &typedef.r#type).into(),
442            alias: FastStr::new(typedef.alias.0.as_ref()),
443            annotations: Annotations::from(&typedef.annotations).0,
444            ..Default::default()
445        }
446    }
447}
448
449impl From<(FastStr, &pilota_thrift_parser::Constant)> for thrift_reflection::ConstDescriptor {
450    fn from((filepath, constant): (FastStr, &pilota_thrift_parser::Constant)) -> Self {
451        thrift_reflection::ConstDescriptor {
452            filepath: filepath.clone(),
453            name: FastStr::new(constant.name.0.clone()),
454            r#type: (filepath, &constant.r#type).into(),
455            value: (&constant.value).into(),
456            annotations: Annotations::from(&constant.annotations).0,
457            ..Default::default()
458        }
459    }
460}
461
462impl From<&pilota_thrift_parser::Type> for thrift_reflection::ConstValueType {
463    fn from(ty: &pilota_thrift_parser::Type) -> Self {
464        match ty.0 {
465            pilota_thrift_parser::Ty::String => Self::STRING,
466            pilota_thrift_parser::Ty::Byte => Self::INT,
467            pilota_thrift_parser::Ty::Binary => Self::STRING,
468            pilota_thrift_parser::Ty::Bool => Self::BOOL,
469            pilota_thrift_parser::Ty::I8 => Self::INT,
470            pilota_thrift_parser::Ty::I16 => Self::INT,
471            pilota_thrift_parser::Ty::I32 => Self::INT,
472            pilota_thrift_parser::Ty::I64 => Self::INT,
473            pilota_thrift_parser::Ty::Double => Self::DOUBLE,
474            pilota_thrift_parser::Ty::Uuid => Self::STRING,
475            pilota_thrift_parser::Ty::List { .. } => Self::LIST,
476            pilota_thrift_parser::Ty::Set { .. } => Self::LIST,
477            pilota_thrift_parser::Ty::Map { .. } => Self::MAP,
478            pilota_thrift_parser::Ty::Path(_) => Self::IDENTIFIER,
479            pilota_thrift_parser::Ty::Void => unreachable!(),
480        }
481    }
482}
483
484impl From<(FastStr, &pilota_thrift_parser::Enum)> for thrift_reflection::EnumDescriptor {
485    fn from((filepath, enum_): (FastStr, &pilota_thrift_parser::Enum)) -> Self {
486        thrift_reflection::EnumDescriptor {
487            name: FastStr::new(enum_.name.0.clone()),
488            filepath: filepath.clone(),
489            values: enum_
490                .values
491                .iter()
492                .map(|value| (filepath.clone(), value).into())
493                .collect(),
494            annotations: Annotations::from(&enum_.annotations).0,
495            ..Default::default()
496        }
497    }
498}
499
500impl From<(FastStr, &pilota_thrift_parser::EnumValue)> for thrift_reflection::EnumValueDescriptor {
501    fn from((filepath, value): (FastStr, &pilota_thrift_parser::EnumValue)) -> Self {
502        thrift_reflection::EnumValueDescriptor {
503            filepath: filepath.clone(),
504            name: FastStr::new(value.name.0.clone()),
505            value: value.value.as_ref().map(|value| value.0).unwrap_or(-1),
506            annotations: Annotations::from(&value.annotations).0,
507            ..Default::default()
508        }
509    }
510}
511
512impl From<(FastStr, &pilota_thrift_parser::Union)> for thrift_reflection::StructDescriptor {
513    fn from((filepath, union): (FastStr, &pilota_thrift_parser::Union)) -> Self {
514        thrift_reflection::StructDescriptor {
515            name: FastStr::new(union.name.0.clone()),
516            filepath: filepath.clone(),
517            fields: union
518                .fields
519                .iter()
520                .map(|field| (filepath.clone(), field).into())
521                .collect(),
522            annotations: Annotations::from(&union.annotations).0,
523            ..Default::default()
524        }
525    }
526}
527
528impl From<(FastStr, &pilota_thrift_parser::Exception)> for thrift_reflection::StructDescriptor {
529    fn from((filepath, exception): (FastStr, &pilota_thrift_parser::Exception)) -> Self {
530        thrift_reflection::StructDescriptor {
531            filepath: filepath.clone(),
532            name: FastStr::new(exception.name.0.clone()),
533            fields: exception
534                .fields
535                .iter()
536                .map(|field| (filepath.clone(), field).into())
537                .collect(),
538            annotations: Annotations::from(&exception.annotations).0,
539            ..Default::default()
540        }
541    }
542}