1use crate::wit_type::{bool, field, record, str, tuple};
16use crate::wit_type::{
17 AnalysedResourceId, AnalysedResourceMode, NameOptionTypePair, NameTypePair, TypeBool, TypeChr,
18 TypeEnum, TypeF32, TypeF64, TypeFlags, TypeHandle, TypeList, TypeOption, TypeRecord,
19 TypeResult, TypeS16, TypeS32, TypeS64, TypeS8, TypeStr, TypeTuple, TypeU16, TypeU32, TypeU64,
20 TypeU8, TypeVariant, WitType,
21};
22use crate::{GetTypeHint, InferredType, InstanceType, TypeInternal};
23use serde::{Deserialize, Serialize};
24
25#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
29pub enum WitTypeWithUnit {
30 Unit,
31 Type(WitType),
32}
33
34impl WitTypeWithUnit {
35 pub fn unit() -> Self {
36 WitTypeWithUnit::Unit
37 }
38
39 pub fn analysed_type(typ: WitType) -> Self {
40 WitTypeWithUnit::Type(typ)
41 }
42}
43
44impl TryFrom<WitTypeWithUnit> for WitType {
45 type Error = String;
46
47 fn try_from(value: WitTypeWithUnit) -> Result<Self, Self::Error> {
48 match value {
49 WitTypeWithUnit::Unit => Ok(tuple(vec![])),
50 WitTypeWithUnit::Type(typ) => Ok(typ),
51 }
52 }
53}
54
55impl TryFrom<&InferredType> for WitType {
56 type Error = String;
57
58 fn try_from(value: &InferredType) -> Result<Self, Self::Error> {
59 let with_unit = WitTypeWithUnit::try_from(value)?;
60 WitType::try_from(with_unit)
61 }
62}
63
64impl TryFrom<&InferredType> for WitTypeWithUnit {
65 type Error = String;
66
67 fn try_from(inferred_type: &InferredType) -> Result<Self, Self::Error> {
68 match inferred_type.internal_type() {
69 TypeInternal::Instance { instance_type } => match instance_type.as_ref() {
70 InstanceType::Resource {
71 analysed_resource_id,
72 analysed_resource_mode,
73 ..
74 } => {
75 let analysed_resource_id = AnalysedResourceId(*analysed_resource_id);
76
77 let analysed_resource_mode = if *analysed_resource_mode == 0 {
78 AnalysedResourceMode::Owned
79 } else {
80 AnalysedResourceMode::Borrowed
81 };
82
83 Ok(WitTypeWithUnit::analysed_type(WitType::Handle(
84 TypeHandle {
85 resource_id: analysed_resource_id,
86 mode: analysed_resource_mode,
87 name: None,
88 owner: None,
89 },
90 )))
91 }
92
93 _ => Ok(WitTypeWithUnit::analysed_type(str())),
94 },
95 TypeInternal::Range { from, to } => {
96 let from: WitType = WitType::try_from(from)?;
97 let to: Option<WitType> = to.as_ref().map(WitType::try_from).transpose()?;
98 let analysed_type = match (from, to) {
99 (from_type, Some(to_type)) => record(vec![
100 field("from", from_type),
101 field("to", to_type),
102 field("inclusive", bool()),
103 ]),
104
105 (from_type, None) => {
106 record(vec![field("from", from_type), field("inclusive", bool())])
107 }
108 };
109 Ok(WitTypeWithUnit::analysed_type(analysed_type))
110 }
111 TypeInternal::Bool => Ok(WitTypeWithUnit::analysed_type(WitType::Bool(TypeBool))),
112 TypeInternal::S8 => Ok(WitTypeWithUnit::analysed_type(WitType::S8(TypeS8))),
113 TypeInternal::U8 => Ok(WitTypeWithUnit::analysed_type(WitType::U8(TypeU8))),
114 TypeInternal::S16 => Ok(WitTypeWithUnit::analysed_type(WitType::S16(TypeS16))),
115 TypeInternal::U16 => Ok(WitTypeWithUnit::analysed_type(WitType::U16(TypeU16))),
116 TypeInternal::S32 => Ok(WitTypeWithUnit::analysed_type(WitType::S32(TypeS32))),
117 TypeInternal::U32 => Ok(WitTypeWithUnit::analysed_type(WitType::U32(TypeU32))),
118 TypeInternal::S64 => Ok(WitTypeWithUnit::analysed_type(WitType::S64(TypeS64))),
119 TypeInternal::U64 => Ok(WitTypeWithUnit::analysed_type(WitType::U64(TypeU64))),
120 TypeInternal::F32 => Ok(WitTypeWithUnit::analysed_type(WitType::F32(TypeF32))),
121 TypeInternal::F64 => Ok(WitTypeWithUnit::analysed_type(WitType::F64(TypeF64))),
122 TypeInternal::Chr => Ok(WitTypeWithUnit::analysed_type(WitType::Chr(TypeChr))),
123 TypeInternal::Str => Ok(WitTypeWithUnit::analysed_type(WitType::Str(TypeStr))),
124 TypeInternal::List(inferred_type) => {
125 Ok(WitTypeWithUnit::analysed_type(WitType::List(TypeList {
126 inner: Box::new(inferred_type.try_into()?),
127 name: None,
128 owner: None,
129 })))
130 }
131 TypeInternal::Tuple(tuple) => {
132 Ok(WitTypeWithUnit::analysed_type(WitType::Tuple(TypeTuple {
133 items: tuple
134 .iter()
135 .map(|t| t.try_into())
136 .collect::<Result<Vec<WitType>, String>>()?,
137 name: None,
138 owner: None,
139 })))
140 }
141 TypeInternal::Record(record) => Ok(WitTypeWithUnit::analysed_type(WitType::Record(
142 TypeRecord {
143 fields: record
144 .iter()
145 .map(|(name, typ)| {
146 Ok(NameTypePair {
147 name: name.to_string(),
148 typ: typ.try_into()?,
149 })
150 })
151 .collect::<Result<Vec<NameTypePair>, String>>()?,
152 name: None,
153 owner: None,
154 },
155 ))),
156 TypeInternal::Flags(flags) => {
157 Ok(WitTypeWithUnit::analysed_type(WitType::Flags(TypeFlags {
158 names: flags.clone(),
159 name: None,
160 owner: None,
161 })))
162 }
163 TypeInternal::Enum(enums) => {
164 Ok(WitTypeWithUnit::analysed_type(WitType::Enum(TypeEnum {
165 cases: enums.clone(),
166 name: None,
167 owner: None,
168 })))
169 }
170 TypeInternal::Option(option) => Ok(WitTypeWithUnit::analysed_type(WitType::Option(
171 TypeOption {
172 inner: Box::new(option.try_into()?),
173 name: None,
174 owner: None,
175 },
176 ))),
177 TypeInternal::Result { ok, error } => Ok(WitTypeWithUnit::analysed_type(
178 WitType::Result(TypeResult {
180 ok: ok.as_ref().and_then(|t| t.try_into().ok().map(Box::new)),
181 err: error.as_ref().and_then(|t| t.try_into().ok().map(Box::new)),
182 name: None,
183 owner: None,
184 }),
185 )),
186 TypeInternal::Variant(variant) => Ok(WitTypeWithUnit::analysed_type(WitType::Variant(
187 TypeVariant {
188 cases: variant
189 .iter()
190 .map(|(name, typ)| {
191 Ok(NameOptionTypePair {
192 name: name.clone(),
193 typ: typ.as_ref().map(|t| t.try_into()).transpose()?,
194 })
195 })
196 .collect::<Result<Vec<NameOptionTypePair>, String>>()?,
197 name: None,
198 owner: None,
199 },
200 ))),
201 TypeInternal::Resource {
202 resource_id,
203 resource_mode,
204 name: _,
205 owner: _,
206 } => Ok(WitTypeWithUnit::analysed_type(WitType::Handle(
207 TypeHandle {
208 resource_id: AnalysedResourceId(*resource_id),
209 mode: if resource_mode == &0 {
210 AnalysedResourceMode::Owned
211 } else {
212 AnalysedResourceMode::Borrowed
213 },
214 name: None,
215 owner: None,
216 },
217 ))),
218
219 TypeInternal::AllOf(types) => Err(format!(
220 "ambiguous types {}",
221 types
222 .iter()
223 .map(|x| x.get_type_hint().to_string())
224 .collect::<Vec<_>>()
225 .join(", ")
226 )),
227 TypeInternal::Unknown => Err("failed to infer type".to_string()),
228 TypeInternal::Sequence(vec) => {
231 if vec.is_empty() {
232 Ok(WitTypeWithUnit::unit())
233 } else if vec.len() == 1 {
234 let first = &vec[0];
235 Ok(first.try_into()?)
236 } else {
237 Err("function with multiple return types not supported".to_string())
238 }
239 }
240 }
241 }
242}