rib/parser/
type_name.rs

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