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()); 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}