rib/parser/
type_name.rs

1// Copyright 2024-2025 Golem Cloud
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::fmt::Display;
16use std::ops::Deref;
17
18use bincode::{Decode, Encode};
19use combine::parser::char;
20use combine::parser::char::{char, spaces, string};
21use combine::{attempt, between, choice, optional, sep_by, Parser};
22use combine::{parser, ParseError};
23use golem_wasm_ast::analysis::{AnalysedType, TypeResult};
24
25use crate::parser::errors::RibParseError;
26use crate::rib_source_span::GetSourcePosition;
27use crate::{InferredNumber, InferredType};
28
29// Rib grammar uses it's own `TypeName` instead of relying from any other crates to annotate types (Example: 1: u32, let x: u32 = 1;),
30// and sticks on to the  Display instance that aligns with what we see in WIT.
31// Usage of TypeName, InferredType and AnalysedType:
32// The Rib compiler uses `InferredType` - the output of type inference. The `TypeName` used in type annotations may help with this type inference.
33// The Rib-IR which is close to running Rib code uses `AnalysedType`, that there won't be either `TypeName` or `InferredType` in the Rib-IR.
34// Any compilation or interpreter error messages will also be using `TypeName` to show the type of the expression
35// for which we convert AnalysedType or InferredType back to TypeName. If `InferredType` cannot be converted to `TypeName`, we explain the error displaying
36// the original expression, and there is no point displaying `InferredType` to the user.
37#[derive(Debug, Hash, Clone, Eq, PartialEq, Encode, Decode, Ord, PartialOrd)]
38pub enum TypeName {
39    Bool,
40    S8,
41    U8,
42    S16,
43    U16,
44    S32,
45    U32,
46    S64,
47    U64,
48    F32,
49    F64,
50    Chr,
51    Str,
52    List(Box<TypeName>),
53    Tuple(Vec<TypeName>),
54    Option(Box<TypeName>),
55    Result {
56        ok: Option<Box<TypeName>>,
57        error: Option<Box<TypeName>>,
58    },
59    Record(Vec<(String, Box<TypeName>)>),
60    Flags(Vec<String>),
61    Enum(Vec<String>),
62    Variant {
63        cases: Vec<(String, Option<Box<TypeName>>)>,
64    },
65}
66
67impl Display for TypeName {
68    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69        match self {
70            TypeName::Bool => write!(f, "bool"),
71            TypeName::S8 => write!(f, "s8"),
72            TypeName::U8 => write!(f, "u8"),
73            TypeName::S16 => write!(f, "s16"),
74            TypeName::U16 => write!(f, "u16"),
75            TypeName::S32 => write!(f, "s32"),
76            TypeName::U32 => write!(f, "u32"),
77            TypeName::S64 => write!(f, "s64"),
78            TypeName::U64 => write!(f, "u64"),
79            TypeName::F32 => write!(f, "f32"),
80            TypeName::F64 => write!(f, "f64"),
81            TypeName::Chr => write!(f, "char"),
82            TypeName::Str => write!(f, "string"),
83            TypeName::List(inner_type) => write!(f, "list<{}>", inner_type),
84            TypeName::Tuple(inner_types) => {
85                write!(f, "tuple<")?;
86                for (i, inner_type) in inner_types.iter().enumerate() {
87                    if i > 0 {
88                        write!(f, ", ")?;
89                    }
90                    write!(f, "{}", inner_type)?;
91                }
92                write!(f, ">")
93            }
94            TypeName::Option(inner_type) => write!(f, "option<{}>", inner_type),
95            // https://component-model.bytecodealliance.org/design/wit.html#results
96            TypeName::Result { ok, error } => match (ok, error) {
97                (Some(ok), Some(error)) => {
98                    write!(f, "result<{}, {}>", ok, error)
99                }
100                (Some(ok), None) => {
101                    write!(f, "result<{}>", ok)
102                }
103                (None, Some(error)) => {
104                    write!(f, "result<_, {}>", error)
105                }
106                (None, None) => {
107                    write!(f, "result")
108                }
109            },
110            TypeName::Record(fields) => {
111                write!(f, "record {{ ")?;
112                for (i, (field, typ)) in fields.iter().enumerate() {
113                    if i > 0 {
114                        write!(f, ", ")?;
115                    }
116                    write!(f, "{}: {}", field, typ)?;
117                }
118                write!(f, " }}")
119            }
120            TypeName::Flags(flags) => {
121                write!(f, "flags<")?;
122                for (i, flag) in flags.iter().enumerate() {
123                    if i > 0 {
124                        write!(f, ", ")?;
125                    }
126                    write!(f, "{}", flag)?;
127                }
128                write!(f, ">")
129            }
130            TypeName::Enum(cases) => {
131                write!(f, "enum {{ ")?;
132                for (i, case) in cases.iter().enumerate() {
133                    if i > 0 {
134                        write!(f, ", ")?;
135                    }
136                    write!(f, "{}", case)?;
137                }
138                write!(f, " }}")
139            }
140            TypeName::Variant { cases } => {
141                write!(f, "variant {{")?;
142                for (i, (case, typ)) in cases.iter().enumerate() {
143                    if i > 0 {
144                        write!(f, ", ")?;
145                    }
146                    write!(f, "{}", case)?;
147                    if let Some(typ) = typ {
148                        write!(f, "({})", typ)?;
149                    }
150                }
151                write!(f, " }}")
152            }
153        }
154    }
155}
156
157impl From<&InferredNumber> for TypeName {
158    fn from(value: &InferredNumber) -> Self {
159        match value {
160            InferredNumber::S8 => TypeName::S8,
161            InferredNumber::U8 => TypeName::U8,
162            InferredNumber::S16 => TypeName::S16,
163            InferredNumber::U16 => TypeName::U16,
164            InferredNumber::S32 => TypeName::S32,
165            InferredNumber::U32 => TypeName::U32,
166            InferredNumber::S64 => TypeName::S64,
167            InferredNumber::U64 => TypeName::U64,
168            InferredNumber::F32 => TypeName::F32,
169            InferredNumber::F64 => TypeName::F64,
170        }
171    }
172}
173
174impl TryFrom<AnalysedType> for TypeName {
175    type Error = String;
176    fn try_from(analysed_type: AnalysedType) -> Result<Self, Self::Error> {
177        match analysed_type {
178            AnalysedType::Bool(_) => Ok(TypeName::Bool),
179            AnalysedType::S8(_) => Ok(TypeName::S8),
180            AnalysedType::U8(_) => Ok(TypeName::U8),
181            AnalysedType::S16(_) => Ok(TypeName::S16),
182            AnalysedType::U16(_) => Ok(TypeName::U16),
183            AnalysedType::S32(_) => Ok(TypeName::S32),
184            AnalysedType::U32(_) => Ok(TypeName::U32),
185            AnalysedType::S64(_) => Ok(TypeName::S64),
186            AnalysedType::U64(_) => Ok(TypeName::U64),
187            AnalysedType::F32(_) => Ok(TypeName::F32),
188            AnalysedType::F64(_) => Ok(TypeName::F64),
189            AnalysedType::Chr(_) => Ok(TypeName::Chr),
190            AnalysedType::Str(_) => Ok(TypeName::Str),
191            AnalysedType::List(inner_type) => Ok(TypeName::List(Box::new(
192                inner_type.inner.deref().clone().try_into()?,
193            ))),
194            AnalysedType::Tuple(inner_type) => Ok(TypeName::Tuple(
195                inner_type
196                    .items
197                    .into_iter()
198                    .map(|x| x.try_into())
199                    .collect::<Result<_, _>>()?,
200            )),
201            AnalysedType::Option(type_option) => Ok(TypeName::Option(Box::new(
202                type_option.inner.deref().clone().try_into()?,
203            ))),
204            AnalysedType::Result(TypeResult { ok, err }) => match (ok, err) {
205                (Some(ok), Some(err)) => Ok(TypeName::Result {
206                    ok: Some(Box::new(ok.deref().clone().try_into()?)),
207                    error: Some(Box::new(err.deref().clone().try_into()?)),
208                }),
209                (Some(ok), None) => Ok(TypeName::Result {
210                    ok: Some(Box::new(ok.deref().clone().try_into()?)),
211                    error: None,
212                }),
213                (None, Some(err)) => Ok(TypeName::Result {
214                    ok: None,
215                    error: Some(Box::new(err.deref().clone().try_into()?)),
216                }),
217                (None, None) => Ok(TypeName::Result {
218                    ok: None,
219                    error: None,
220                }),
221            },
222            AnalysedType::Record(type_record) => {
223                let mut fields = vec![];
224                for field in type_record.fields {
225                    let name = field.name.clone();
226                    let typ = field.typ.clone();
227                    let type_name = typ.try_into()?;
228                    fields.push((name, Box::new(type_name)));
229                }
230
231                Ok(TypeName::Record(fields))
232            }
233            AnalysedType::Flags(flags) => Ok(TypeName::Flags(flags.names)),
234            AnalysedType::Enum(cases) => Ok(TypeName::Enum(cases.cases)),
235            AnalysedType::Variant(cases) => {
236                let mut variant_cases = vec![];
237                for case in cases.cases {
238                    let name = case.name.clone();
239                    let typ = case.typ.clone();
240                    match typ {
241                        Some(typ) => {
242                            let type_name = typ.try_into()?;
243                            variant_cases.push((name, Some(Box::new(type_name))));
244                        }
245                        None => {
246                            variant_cases.push((name, None));
247                        }
248                    }
249                }
250                Ok(TypeName::Variant {
251                    cases: variant_cases,
252                })
253            }
254            AnalysedType::Handle(type_handle) => {
255                Err(format!("Handle type not supported: {:?}", type_handle))
256            }
257        }
258    }
259}
260
261impl From<TypeName> for InferredType {
262    fn from(type_name: TypeName) -> Self {
263        match type_name {
264            TypeName::Bool => InferredType::Bool,
265            TypeName::S8 => InferredType::S8,
266            TypeName::U8 => InferredType::U8,
267            TypeName::S16 => InferredType::S16,
268            TypeName::U16 => InferredType::U16,
269            TypeName::S32 => InferredType::S32,
270            TypeName::U32 => InferredType::U32,
271            TypeName::S64 => InferredType::S64,
272            TypeName::U64 => InferredType::U64,
273            TypeName::F32 => InferredType::F32,
274            TypeName::F64 => InferredType::F64,
275            TypeName::Chr => InferredType::Chr,
276            TypeName::Str => InferredType::Str,
277            TypeName::List(inner_type) => {
278                InferredType::List(Box::new(inner_type.deref().clone().into()))
279            }
280            TypeName::Tuple(inner_types) => {
281                InferredType::Tuple(inner_types.into_iter().map(|t| t.into()).collect())
282            }
283            TypeName::Option(type_name) => {
284                InferredType::Option(Box::new(type_name.deref().clone().into()))
285            }
286            TypeName::Result { ok, error } => InferredType::Result {
287                ok: ok.map(|x| Box::new(x.deref().clone().into())),
288                error: error.map(|x| Box::new(x.deref().clone().into())),
289            },
290            TypeName::Record(fields) => InferredType::Record(
291                fields
292                    .into_iter()
293                    .map(|(field, typ)| (field, typ.deref().clone().into()))
294                    .collect(),
295            ),
296            TypeName::Flags(flags) => InferredType::Flags(flags),
297            TypeName::Enum(cases) => InferredType::Enum(cases),
298            TypeName::Variant { cases } => InferredType::Variant(
299                cases
300                    .into_iter()
301                    .map(|(case, typ)| (case, typ.map(|x| x.deref().clone().into())))
302                    .collect(),
303            ),
304        }
305    }
306}
307
308impl TryFrom<InferredType> for TypeName {
309    type Error = String;
310
311    fn try_from(value: InferredType) -> Result<Self, Self::Error> {
312        match value {
313            InferredType::Bool => Ok(TypeName::Bool),
314            InferredType::S8 => Ok(TypeName::S8),
315            InferredType::U8 => Ok(TypeName::U8),
316            InferredType::S16 => Ok(TypeName::S16),
317            InferredType::U16 => Ok(TypeName::U16),
318            InferredType::S32 => Ok(TypeName::S32),
319            InferredType::U32 => Ok(TypeName::U32),
320            InferredType::S64 => Ok(TypeName::S64),
321            InferredType::U64 => Ok(TypeName::U64),
322            InferredType::F32 => Ok(TypeName::F32),
323            InferredType::F64 => Ok(TypeName::F64),
324            InferredType::Chr => Ok(TypeName::Chr),
325            InferredType::Str => Ok(TypeName::Str),
326            InferredType::List(inferred_type) => {
327                let verified = inferred_type.deref().clone().try_into()?;
328                Ok(TypeName::List(Box::new(verified)))
329            }
330            InferredType::Tuple(inferred_types) => {
331                let mut verified_types = vec![];
332                for typ in inferred_types {
333                    let verified = typ.try_into()?;
334                    verified_types.push(verified);
335                }
336                Ok(TypeName::Tuple(verified_types))
337            }
338            InferredType::Record(name_and_types) => {
339                let mut fields = vec![];
340                for (field, typ) in name_and_types {
341                    let verified = typ.try_into()?;
342                    fields.push((field, Box::new(verified)));
343                }
344                Ok(TypeName::Record(fields))
345            }
346            InferredType::Flags(flags) => Ok(TypeName::Flags(flags)),
347            InferredType::Enum(enums) => Ok(TypeName::Enum(enums)),
348            InferredType::Option(inferred_type) => {
349                let result = inferred_type.deref().clone().try_into()?;
350                Ok(TypeName::Option(Box::new(result)))
351            }
352            InferredType::Result { ok, error } => {
353                let ok_unified = ok.map(|ok| ok.deref().clone().try_into()).transpose()?;
354                let err_unified = error
355                    .map(|err| err.deref().clone().try_into())
356                    .transpose()?;
357                Ok(TypeName::Result {
358                    ok: ok_unified.map(Box::new),
359                    error: err_unified.map(Box::new),
360                })
361            }
362            InferredType::Variant(variant) => {
363                let mut cases = vec![];
364                for (case, typ) in variant {
365                    let verified = typ.map(TypeName::try_from).transpose()?;
366                    cases.push((case, verified.map(Box::new)));
367                }
368                Ok(TypeName::Variant { cases })
369            }
370            InferredType::Resource { .. } => {
371                Err("Cannot convert a resource type to a type name".to_string())
372            }
373            InferredType::OneOf(_) => {
374                Err("Cannot convert a one of type to a type name".to_string())
375            }
376            InferredType::AllOf(_) => {
377                Err("Cannot convert a all of type to a type name".to_string())
378            }
379            InferredType::Unknown => {
380                Err("Cannot convert an unknown type to a type name".to_string())
381            }
382            InferredType::Sequence(_) => {
383                Err("Cannot convert a sequence type to a type name".to_string())
384            }
385            InferredType::Instance { .. } => {
386                Err("Cannot convert an instance type to a type name".to_string())
387            }
388            InferredType::Range { .. } => {
389                Err("Cannot convert a range type to a type name".to_string())
390            }
391        }
392    }
393}
394
395pub fn parse_basic_type<Input>() -> impl Parser<Input, Output = TypeName>
396where
397    Input: combine::Stream<Token = char>,
398    RibParseError: Into<
399        <Input::Error as ParseError<Input::Token, Input::Range, Input::Position>>::StreamError,
400    >,
401    Input::Position: GetSourcePosition,
402{
403    choice((
404        attempt(string("bool").map(|_| TypeName::Bool)),
405        attempt(string("s8").map(|_| TypeName::S8)),
406        attempt(string("u8").map(|_| TypeName::U8)),
407        attempt(string("s16").map(|_| TypeName::S16)),
408        attempt(string("u16").map(|_| TypeName::U16)),
409        attempt(string("s32").map(|_| TypeName::S32)),
410        attempt(string("u32").map(|_| TypeName::U32)),
411        attempt(string("s64").map(|_| TypeName::S64)),
412        attempt(string("u64").map(|_| TypeName::U64)),
413        attempt(string("f32").map(|_| TypeName::F32)),
414        attempt(string("f64").map(|_| TypeName::F64)),
415        attempt(string("char").map(|_| TypeName::Chr)),
416        attempt(string("string").map(|_| TypeName::Str)),
417    ))
418    .skip(spaces().silent())
419}
420
421pub fn parse_list_type<Input>() -> impl Parser<Input, Output = TypeName>
422where
423    Input: combine::Stream<Token = char>,
424    RibParseError: Into<
425        <Input::Error as ParseError<Input::Token, Input::Range, Input::Position>>::StreamError,
426    >,
427    Input::Position: GetSourcePosition,
428{
429    string("list")
430        .skip(spaces().silent())
431        .with(between(
432            char('<').skip(spaces().silent().silent()),
433            char('>').skip(spaces().silent().silent()),
434            type_name(),
435        ))
436        .map(|inner_type| TypeName::List(Box::new(inner_type)))
437}
438
439pub fn parse_option_type<Input>() -> impl Parser<Input, Output = TypeName>
440where
441    Input: combine::Stream<Token = char>,
442    RibParseError: Into<
443        <Input::Error as ParseError<Input::Token, Input::Range, Input::Position>>::StreamError,
444    >,
445    Input::Position: GetSourcePosition,
446{
447    string("option")
448        .skip(spaces().silent())
449        .with(between(
450            char('<').skip(spaces().silent().silent()),
451            char('>').skip(spaces().silent().silent()),
452            type_name(),
453        ))
454        .map(|inner_type| TypeName::Option(Box::new(inner_type)))
455}
456
457enum ResultSuccess {
458    NoType,
459    WithType(TypeName),
460}
461
462// https://component-model.bytecodealliance.org/design/wit.html#results
463pub fn parse_result_type<Input>() -> impl Parser<Input, Output = TypeName>
464where
465    Input: combine::Stream<Token = char>,
466    RibParseError: Into<
467        <Input::Error as ParseError<Input::Token, Input::Range, Input::Position>>::StreamError,
468    >,
469    Input::Position: GetSourcePosition,
470{
471    string("result")
472        .skip(spaces().silent())
473        .with(optional(between(
474            char('<').skip(spaces().silent()),
475            char('>').skip(spaces().silent()),
476            (
477                choice!(
478                    string("_")
479                        .skip(spaces().silent())
480                        .map(|_| ResultSuccess::NoType),
481                    type_name()
482                        .skip(spaces().silent())
483                        .map(ResultSuccess::WithType)
484                ),
485                optional(
486                    char(',')
487                        .skip(spaces().silent())
488                        .with(type_name().skip(spaces().silent())),
489                ),
490            ),
491        )))
492        .map(|result| match result {
493            None => TypeName::Result {
494                ok: None,
495                error: None,
496            },
497            Some((ResultSuccess::NoType, None)) => TypeName::Result {
498                ok: None,
499                error: None,
500            },
501            Some((ResultSuccess::NoType, Some(error))) => TypeName::Result {
502                ok: None,
503                error: Some(Box::new(error)),
504            },
505            Some((ResultSuccess::WithType(ok), None)) => TypeName::Result {
506                ok: Some(Box::new(ok)),
507                error: None,
508            },
509            Some((ResultSuccess::WithType(ok), Some(error))) => TypeName::Result {
510                ok: Some(Box::new(ok)),
511                error: Some(Box::new(error)),
512            },
513        })
514}
515
516pub fn parse_tuple_type<Input>() -> impl Parser<Input, Output = TypeName>
517where
518    Input: combine::Stream<Token = char>,
519    RibParseError: Into<
520        <Input::Error as ParseError<Input::Token, Input::Range, Input::Position>>::StreamError,
521    >,
522    Input::Position: GetSourcePosition,
523{
524    string("tuple")
525        .skip(spaces().silent())
526        .with(between(
527            char('<').skip(spaces().silent()),
528            char('>').skip(spaces().silent()),
529            sep_by(type_name(), char(',').skip(spaces().silent())),
530        ))
531        .map(TypeName::Tuple)
532}
533
534pub fn type_name_<Input>() -> impl Parser<Input, Output = TypeName>
535where
536    Input: combine::Stream<Token = char>,
537    RibParseError: Into<
538        <Input::Error as ParseError<Input::Token, Input::Range, Input::Position>>::StreamError,
539    >,
540    Input::Position: GetSourcePosition,
541{
542    spaces().silent().with(choice((
543        attempt(parse_basic_type()),
544        attempt(parse_list_type()),
545        attempt(parse_tuple_type()),
546        attempt(parse_option_type()),
547        attempt(parse_result_type()),
548    )))
549}
550
551parser! {
552    pub fn type_name[Input]()(Input) -> TypeName
553     where [Input: combine::Stream<Token = char>, RibParseError: Into<<Input::Error as ParseError<Input::Token, Input::Range, Input::Position>>::StreamError>, Input::Position: GetSourcePosition]
554    {
555       type_name_()
556    }
557}
558
559#[cfg(feature = "protobuf")]
560mod protobuf {
561    use golem_api_grpc::proto::golem::rib::type_name::Kind as InnerTypeName;
562    use golem_api_grpc::proto::golem::rib::{
563        BasicTypeName, EnumType, FlagType, KeyValue, ListType, OptionType, RecordType, ResultType,
564        TupleType, TypeName as ProtoTypeName, VariantCase, VariantType,
565    };
566    use std::ops::Deref;
567
568    use crate::TypeName;
569
570    impl From<TypeName> for ProtoTypeName {
571        fn from(value: TypeName) -> Self {
572            let inner = match value {
573                TypeName::Bool => InnerTypeName::BasicType(BasicTypeName::Bool as i32),
574                TypeName::S8 => InnerTypeName::BasicType(BasicTypeName::S8 as i32),
575                TypeName::U8 => InnerTypeName::BasicType(BasicTypeName::U8 as i32),
576                TypeName::S16 => InnerTypeName::BasicType(BasicTypeName::S16 as i32),
577                TypeName::U16 => InnerTypeName::BasicType(BasicTypeName::U16 as i32),
578                TypeName::S32 => InnerTypeName::BasicType(BasicTypeName::S32 as i32),
579                TypeName::U32 => InnerTypeName::BasicType(BasicTypeName::U32 as i32),
580                TypeName::S64 => InnerTypeName::BasicType(BasicTypeName::S64 as i32),
581                TypeName::U64 => InnerTypeName::BasicType(BasicTypeName::U64 as i32),
582                TypeName::F32 => InnerTypeName::BasicType(BasicTypeName::F32 as i32),
583                TypeName::F64 => InnerTypeName::BasicType(BasicTypeName::F64 as i32),
584                TypeName::Chr => InnerTypeName::BasicType(BasicTypeName::Chr as i32),
585                TypeName::Str => InnerTypeName::BasicType(BasicTypeName::Str as i32),
586                TypeName::List(inner_type) => InnerTypeName::ListType(Box::new(ListType {
587                    inner_type: Some(Box::new(inner_type.deref().clone().into())),
588                })),
589                TypeName::Tuple(inner_types) => InnerTypeName::TupleType(TupleType {
590                    types: inner_types.into_iter().map(|t| t.into()).collect(),
591                }),
592                TypeName::Option(type_name) => InnerTypeName::OptionType(Box::new(OptionType {
593                    inner_type: Some(Box::new(type_name.deref().clone().into())),
594                })),
595                TypeName::Result { ok, error } => InnerTypeName::ResultType(Box::new(ResultType {
596                    ok_type: ok.map(|ok| Box::new(ok.deref().clone().into())),
597                    err_type: error.map(|error| Box::new(error.deref().clone().into())),
598                })),
599                TypeName::Record(fields) => InnerTypeName::RecordType(RecordType {
600                    fields: fields
601                        .into_iter()
602                        .map(|(field, typ)| KeyValue {
603                            key: field,
604                            value: Some(typ.deref().clone().into()),
605                        })
606                        .collect(),
607                }),
608                TypeName::Flags(flags) => InnerTypeName::FlagType(FlagType {
609                    flags: flags.into_iter().collect(),
610                }),
611                TypeName::Enum(cases) => InnerTypeName::EnumType(EnumType {
612                    cases: cases.into_iter().collect(),
613                }),
614                TypeName::Variant { cases } => InnerTypeName::VariantType(VariantType {
615                    cases: cases
616                        .into_iter()
617                        .map(|(case, typ)| VariantCase {
618                            case_name: case,
619                            variant_arg: typ.map(|x| x.deref().clone().into()),
620                        })
621                        .collect(),
622                }),
623            };
624
625            ProtoTypeName { kind: Some(inner) }
626        }
627    }
628
629    impl TryFrom<ProtoTypeName> for TypeName {
630        type Error = String;
631
632        fn try_from(value: ProtoTypeName) -> Result<Self, Self::Error> {
633            match value.kind {
634                Some(inner) => match inner {
635                    InnerTypeName::BasicType(value) => match BasicTypeName::try_from(value) {
636                        Ok(BasicTypeName::Bool) => Ok(TypeName::Bool),
637                        Ok(BasicTypeName::S8) => Ok(TypeName::S8),
638                        Ok(BasicTypeName::U8) => Ok(TypeName::U8),
639                        Ok(BasicTypeName::S16) => Ok(TypeName::S16),
640                        Ok(BasicTypeName::U16) => Ok(TypeName::U16),
641                        Ok(BasicTypeName::S32) => Ok(TypeName::S32),
642                        Ok(BasicTypeName::U32) => Ok(TypeName::U32),
643                        Ok(BasicTypeName::S64) => Ok(TypeName::S64),
644                        Ok(BasicTypeName::U64) => Ok(TypeName::U64),
645                        Ok(BasicTypeName::F32) => Ok(TypeName::F32),
646                        Ok(BasicTypeName::F64) => Ok(TypeName::F64),
647                        Ok(BasicTypeName::Chr) => Ok(TypeName::Chr),
648                        Ok(BasicTypeName::Str) => Ok(TypeName::Str),
649                        _ => Err(format!("Unknown basic type: {:?}", value)),
650                    },
651                    InnerTypeName::ListType(inner_type) => {
652                        let proto_list_type = inner_type
653                            .inner_type
654                            .ok_or("No inner type for list provided")?;
655                        let list_type = proto_list_type.deref().clone().try_into()?;
656                        Ok(TypeName::List(Box::new(list_type)))
657                    }
658                    InnerTypeName::TupleType(inner_types) => {
659                        let tuple_type = inner_types
660                            .types
661                            .into_iter()
662                            .map(|t| t.try_into())
663                            .collect::<Result<Vec<TypeName>, String>>()?;
664                        Ok(TypeName::Tuple(tuple_type))
665                    }
666                    InnerTypeName::OptionType(type_name) => {
667                        let proto_option_type = type_name
668                            .inner_type
669                            .ok_or("No inner type for option provided")?;
670                        let option_type = proto_option_type.deref().clone().try_into()?;
671                        Ok(TypeName::Option(Box::new(option_type)))
672                    }
673                    InnerTypeName::ResultType(result_type) => {
674                        let ok = result_type
675                            .ok_type
676                            .map(|ok| ok.deref().clone().try_into())
677                            .transpose()?;
678                        let error = result_type
679                            .err_type
680                            .map(|error| error.deref().clone().try_into())
681                            .transpose()?;
682                        Ok(TypeName::Result {
683                            ok: ok.map(Box::new),
684                            error: error.map(Box::new),
685                        })
686                    }
687                    InnerTypeName::RecordType(fields) => {
688                        let record_type = fields
689                            .fields
690                            .into_iter()
691                            .map(|key_value| {
692                                key_value
693                                    .value
694                                    .ok_or("Field type missing")?
695                                    .try_into()
696                                    .map(|typ| (key_value.key, Box::new(typ)))
697                            })
698                            .collect::<Result<Vec<(String, Box<TypeName>)>, String>>()?;
699                        Ok(TypeName::Record(record_type))
700                    }
701                    InnerTypeName::FlagType(flag_type) => Ok(TypeName::Flags(flag_type.flags)),
702                    InnerTypeName::EnumType(enum_type) => Ok(TypeName::Enum(enum_type.cases)),
703                    InnerTypeName::VariantType(variant_type) => {
704                        let mut cases = vec![];
705                        for variant_case in variant_type.cases {
706                            let case = variant_case.case_name;
707                            let typ = match variant_case.variant_arg {
708                                Some(typ) => Some(Box::new(TypeName::try_from(typ)?)),
709                                None => None,
710                            };
711                            cases.push((case, typ));
712                        }
713
714                        Ok(TypeName::Variant { cases })
715                    }
716                },
717                None => Err("No type kind provided".to_string()),
718            }
719        }
720    }
721}
722
723#[cfg(test)]
724mod type_name_tests {
725    use combine::stream::position;
726    use combine::EasyParser;
727    use test_r::test;
728
729    use super::*;
730
731    fn parse_and_compare(input: &str, expected: TypeName) {
732        let written = format!("{}", expected);
733        let result1 = type_name()
734            .easy_parse(position::Stream::new(input))
735            .map(|x| x.0);
736        let result2 = type_name()
737            .easy_parse(position::Stream::new(written.as_str()))
738            .map(|x| x.0);
739        assert_eq!(result1, Ok(expected.clone()));
740        assert_eq!(result2, Ok(expected));
741    }
742
743    #[test]
744    fn test_basic_types() {
745        parse_and_compare("bool", TypeName::Bool);
746        parse_and_compare("s8", TypeName::S8);
747        parse_and_compare("u8", TypeName::U8);
748        parse_and_compare("s16", TypeName::S16);
749        parse_and_compare("u16", TypeName::U16);
750        parse_and_compare("s32", TypeName::S32);
751        parse_and_compare("u32", TypeName::U32);
752        parse_and_compare("s64", TypeName::S64);
753        parse_and_compare("u64", TypeName::U64);
754        parse_and_compare("f32", TypeName::F32);
755        parse_and_compare("f64", TypeName::F64);
756        parse_and_compare("char", TypeName::Chr);
757        parse_and_compare("string", TypeName::Str);
758    }
759
760    #[test]
761    fn test_list_type_name() {
762        parse_and_compare("list<u8>", TypeName::List(Box::new(TypeName::U8)));
763        parse_and_compare(
764            "list<list<f32>>",
765            TypeName::List(Box::new(TypeName::List(Box::new(TypeName::F32)))),
766        );
767    }
768
769    #[test]
770    fn test_tuple_type_name() {
771        parse_and_compare(
772            "tuple<u8, u16>",
773            TypeName::Tuple(vec![TypeName::U8, TypeName::U16]),
774        );
775        parse_and_compare(
776            "tuple<s32, list<u8>>",
777            TypeName::Tuple(vec![TypeName::S32, TypeName::List(Box::new(TypeName::U8))]),
778        );
779        parse_and_compare(
780            "tuple<tuple<s8, s16>, u32>",
781            TypeName::Tuple(vec![
782                TypeName::Tuple(vec![TypeName::S8, TypeName::S16]),
783                TypeName::U32,
784            ]),
785        );
786    }
787
788    #[test]
789    fn test_option_type_name() {
790        parse_and_compare("option<u8>", TypeName::Option(Box::new(TypeName::U8)));
791        parse_and_compare(
792            "option<list<f32>>",
793            TypeName::Option(Box::new(TypeName::List(Box::new(TypeName::F32)))),
794        );
795    }
796
797    #[test]
798    fn test_nested_types() {
799        parse_and_compare(
800            "list<tuple<u8, s8>>",
801            TypeName::List(Box::new(TypeName::Tuple(vec![TypeName::U8, TypeName::S8]))),
802        );
803        parse_and_compare(
804            "tuple<list<u16>, list<f64>>",
805            TypeName::Tuple(vec![
806                TypeName::List(Box::new(TypeName::U16)),
807                TypeName::List(Box::new(TypeName::F64)),
808            ]),
809        );
810    }
811
812    #[test]
813    fn test_spaces_around_types() {
814        parse_and_compare("  u8  ", TypeName::U8);
815        parse_and_compare("list< u8 >", TypeName::List(Box::new(TypeName::U8)));
816        parse_and_compare(
817            "tuple< s32 , list< u8 > >",
818            TypeName::Tuple(vec![TypeName::S32, TypeName::List(Box::new(TypeName::U8))]),
819        );
820    }
821}