1use crate::analysis::AnalysisResult;
16use std::fmt::{Display, Formatter};
17
18#[derive(Debug, Clone, PartialEq, Hash, Eq)]
19#[cfg_attr(feature = "host", derive(serde::Serialize, serde::Deserialize))]
20#[cfg_attr(feature = "host", serde(tag = "type"))]
21#[cfg_attr(feature = "host", derive(bincode::Encode, bincode::Decode))]
22#[cfg_attr(feature = "host", derive(poem_openapi::Union))]
23#[cfg_attr(feature = "host", oai(discriminator_name = "type", one_of = true))]
24pub enum AnalysedExport {
25 Function(AnalysedFunction),
26 Instance(AnalysedInstance),
27}
28
29#[derive(Debug, Clone, PartialEq, Hash, Eq)]
30#[cfg_attr(feature = "host", derive(serde::Serialize, serde::Deserialize))]
31#[cfg_attr(feature = "host", derive(bincode::Encode, bincode::Decode))]
32#[cfg_attr(feature = "host", derive(poem_openapi::Object))]
33pub struct AnalysedFunction {
34 pub name: String,
35 pub parameters: Vec<AnalysedFunctionParameter>,
36 pub result: Option<AnalysedFunctionResult>,
37}
38
39impl AnalysedFunction {
40 pub fn is_constructor(&self) -> bool {
41 self.name.starts_with("[constructor]")
42 && self.result.is_some()
43 && matches!(
44 &self.result.as_ref().unwrap().typ,
45 AnalysedType::Handle(TypeHandle {
46 mode: AnalysedResourceMode::Owned,
47 ..
48 })
49 )
50 }
51
52 pub fn is_method(&self) -> bool {
53 self.name.starts_with("[method]")
54 && !self.parameters.is_empty()
55 && matches!(
56 &self.parameters[0].typ,
57 AnalysedType::Handle(TypeHandle {
58 mode: AnalysedResourceMode::Borrowed,
59 ..
60 })
61 )
62 }
63
64 pub fn is_static_method(&self) -> bool {
65 self.name.starts_with("[static]")
66 }
67}
68
69#[derive(Debug, Clone, PartialEq, Hash, Eq)]
70#[cfg_attr(feature = "host", derive(serde::Serialize, serde::Deserialize))]
71#[cfg_attr(feature = "host", derive(bincode::Encode, bincode::Decode))]
72#[cfg_attr(feature = "host", derive(poem_openapi::Object))]
73pub struct AnalysedInstance {
74 pub name: String,
75 pub functions: Vec<AnalysedFunction>,
76}
77
78#[derive(Debug, Clone, PartialEq, Hash, Eq)]
79#[cfg_attr(feature = "host", derive(serde::Serialize, serde::Deserialize))]
80#[cfg_attr(feature = "host", derive(bincode::Encode, bincode::Decode))]
81#[cfg_attr(feature = "host", derive(poem_openapi::Object))]
82pub struct TypeResult {
83 #[cfg_attr(feature = "host", serde(skip_serializing_if = "Option::is_none"))]
84 pub name: Option<String>,
85 #[cfg_attr(feature = "host", serde(skip_serializing_if = "Option::is_none"))]
86 pub owner: Option<String>,
87 pub ok: Option<Box<AnalysedType>>,
88 pub err: Option<Box<AnalysedType>>,
89}
90
91#[derive(Debug, Clone, PartialEq, Hash, Eq)]
92#[cfg_attr(feature = "host", derive(serde::Serialize, serde::Deserialize))]
93#[cfg_attr(feature = "host", derive(bincode::Encode, bincode::Decode))]
94#[cfg_attr(feature = "host", derive(poem_openapi::Object))]
95pub struct NameTypePair {
96 pub name: String,
97 pub typ: AnalysedType,
98}
99
100#[derive(Debug, Clone, PartialEq, Hash, Eq)]
101#[cfg_attr(feature = "host", derive(serde::Serialize, serde::Deserialize))]
102#[cfg_attr(feature = "host", derive(bincode::Encode, bincode::Decode))]
103#[cfg_attr(feature = "host", derive(poem_openapi::Object))]
104pub struct NameOptionTypePair {
105 pub name: String,
106 pub typ: Option<AnalysedType>,
107}
108
109#[derive(Debug, Clone, PartialEq, Hash, Eq)]
110#[cfg_attr(feature = "host", derive(serde::Serialize, serde::Deserialize))]
111#[cfg_attr(feature = "host", derive(bincode::Encode, bincode::Decode))]
112#[cfg_attr(feature = "host", derive(poem_openapi::Object))]
113pub struct TypeVariant {
114 #[cfg_attr(feature = "host", serde(skip_serializing_if = "Option::is_none"))]
115 pub name: Option<String>,
116 #[cfg_attr(feature = "host", serde(skip_serializing_if = "Option::is_none"))]
117 pub owner: Option<String>,
118 pub cases: Vec<NameOptionTypePair>,
119}
120
121#[derive(Debug, Clone, PartialEq, Hash, Eq)]
122#[cfg_attr(feature = "host", derive(serde::Serialize, serde::Deserialize))]
123#[cfg_attr(feature = "host", derive(bincode::Encode, bincode::Decode))]
124#[cfg_attr(feature = "host", derive(poem_openapi::Object))]
125pub struct TypeOption {
126 #[cfg_attr(feature = "host", serde(skip_serializing_if = "Option::is_none"))]
127 pub name: Option<String>,
128 #[cfg_attr(feature = "host", serde(skip_serializing_if = "Option::is_none"))]
129 pub owner: Option<String>,
130 pub inner: Box<AnalysedType>,
131}
132
133#[derive(Debug, Clone, PartialEq, Hash, Eq)]
134#[cfg_attr(feature = "host", derive(serde::Serialize, serde::Deserialize))]
135#[cfg_attr(feature = "host", derive(bincode::Encode, bincode::Decode))]
136#[cfg_attr(feature = "host", derive(poem_openapi::Object))]
137pub struct TypeEnum {
138 #[cfg_attr(feature = "host", serde(skip_serializing_if = "Option::is_none"))]
139 pub name: Option<String>,
140 #[cfg_attr(feature = "host", serde(skip_serializing_if = "Option::is_none"))]
141 pub owner: Option<String>,
142 pub cases: Vec<String>,
143}
144
145#[derive(Debug, Clone, PartialEq, Hash, Eq)]
146#[cfg_attr(feature = "host", derive(serde::Serialize, serde::Deserialize))]
147#[cfg_attr(feature = "host", derive(bincode::Encode, bincode::Decode))]
148#[cfg_attr(feature = "host", derive(poem_openapi::Object))]
149pub struct TypeFlags {
150 #[cfg_attr(feature = "host", serde(skip_serializing_if = "Option::is_none"))]
151 pub name: Option<String>,
152 #[cfg_attr(feature = "host", serde(skip_serializing_if = "Option::is_none"))]
153 pub owner: Option<String>,
154 pub names: Vec<String>,
155}
156
157#[derive(Debug, Clone, PartialEq, Hash, Eq)]
158#[cfg_attr(feature = "host", derive(serde::Serialize, serde::Deserialize))]
159#[cfg_attr(feature = "host", derive(bincode::Encode, bincode::Decode))]
160#[cfg_attr(feature = "host", derive(poem_openapi::Object))]
161pub struct TypeRecord {
162 #[cfg_attr(feature = "host", serde(skip_serializing_if = "Option::is_none"))]
163 pub name: Option<String>,
164 #[cfg_attr(feature = "host", serde(skip_serializing_if = "Option::is_none"))]
165 pub owner: Option<String>,
166 pub fields: Vec<NameTypePair>,
167}
168
169#[derive(Debug, Clone, PartialEq, Hash, Eq)]
170#[cfg_attr(feature = "host", derive(serde::Serialize, serde::Deserialize))]
171#[cfg_attr(feature = "host", derive(bincode::Encode, bincode::Decode))]
172#[cfg_attr(feature = "host", derive(poem_openapi::Object))]
173pub struct TypeTuple {
174 #[cfg_attr(feature = "host", serde(skip_serializing_if = "Option::is_none"))]
175 pub name: Option<String>,
176 #[cfg_attr(feature = "host", serde(skip_serializing_if = "Option::is_none"))]
177 pub owner: Option<String>,
178 pub items: Vec<AnalysedType>,
179}
180
181#[derive(Debug, Clone, PartialEq, Hash, Eq)]
182#[cfg_attr(feature = "host", derive(serde::Serialize, serde::Deserialize))]
183#[cfg_attr(feature = "host", derive(bincode::Encode, bincode::Decode))]
184#[cfg_attr(feature = "host", derive(poem_openapi::Object))]
185pub struct TypeList {
186 #[cfg_attr(feature = "host", serde(skip_serializing_if = "Option::is_none"))]
187 pub name: Option<String>,
188 #[cfg_attr(feature = "host", serde(skip_serializing_if = "Option::is_none"))]
189 pub owner: Option<String>,
190 pub inner: Box<AnalysedType>,
191}
192
193#[derive(Debug, Clone, PartialEq, Hash, Eq)]
194#[cfg_attr(feature = "host", derive(serde::Serialize, serde::Deserialize))]
195#[cfg_attr(feature = "host", derive(bincode::Encode, bincode::Decode))]
196#[cfg_attr(feature = "host", derive(poem_openapi::Object))]
197pub struct TypeStr;
198
199#[derive(Debug, Clone, PartialEq, Hash, Eq)]
200#[cfg_attr(feature = "host", derive(serde::Serialize, serde::Deserialize))]
201#[cfg_attr(feature = "host", derive(bincode::Encode, bincode::Decode))]
202#[cfg_attr(feature = "host", derive(poem_openapi::Object))]
203pub struct TypeChr;
204
205#[derive(Debug, Clone, PartialEq, Hash, Eq)]
206#[cfg_attr(feature = "host", derive(serde::Serialize, serde::Deserialize))]
207#[cfg_attr(feature = "host", derive(bincode::Encode, bincode::Decode))]
208#[cfg_attr(feature = "host", derive(poem_openapi::Object))]
209pub struct TypeF64;
210
211#[derive(Debug, Clone, PartialEq, Hash, Eq)]
212#[cfg_attr(feature = "host", derive(serde::Serialize, serde::Deserialize))]
213#[cfg_attr(feature = "host", derive(bincode::Encode, bincode::Decode))]
214#[cfg_attr(feature = "host", derive(poem_openapi::Object))]
215pub struct TypeF32;
216
217#[derive(Debug, Clone, PartialEq, Hash, Eq)]
218#[cfg_attr(feature = "host", derive(serde::Serialize, serde::Deserialize))]
219#[cfg_attr(feature = "host", derive(bincode::Encode, bincode::Decode))]
220#[cfg_attr(feature = "host", derive(poem_openapi::Object))]
221pub struct TypeU64;
222
223#[derive(Debug, Clone, PartialEq, Hash, Eq)]
224#[cfg_attr(feature = "host", derive(serde::Serialize, serde::Deserialize))]
225#[cfg_attr(feature = "host", derive(bincode::Encode, bincode::Decode))]
226#[cfg_attr(feature = "host", derive(poem_openapi::Object))]
227pub struct TypeS64;
228
229#[derive(Debug, Clone, PartialEq, Hash, Eq)]
230#[cfg_attr(feature = "host", derive(serde::Serialize, serde::Deserialize))]
231#[cfg_attr(feature = "host", derive(bincode::Encode, bincode::Decode))]
232#[cfg_attr(feature = "host", derive(poem_openapi::Object))]
233pub struct TypeU32;
234
235#[derive(Debug, Clone, PartialEq, Hash, Eq)]
236#[cfg_attr(feature = "host", derive(serde::Serialize, serde::Deserialize))]
237#[cfg_attr(feature = "host", derive(bincode::Encode, bincode::Decode))]
238#[cfg_attr(feature = "host", derive(poem_openapi::Object))]
239pub struct TypeS32;
240
241#[derive(Debug, Clone, PartialEq, Hash, Eq)]
242#[cfg_attr(feature = "host", derive(serde::Serialize, serde::Deserialize))]
243#[cfg_attr(feature = "host", derive(bincode::Encode, bincode::Decode))]
244#[cfg_attr(feature = "host", derive(poem_openapi::Object))]
245pub struct TypeU16;
246
247#[derive(Debug, Clone, PartialEq, Hash, Eq)]
248#[cfg_attr(feature = "host", derive(serde::Serialize, serde::Deserialize))]
249#[cfg_attr(feature = "host", derive(bincode::Encode, bincode::Decode))]
250#[cfg_attr(feature = "host", derive(poem_openapi::Object))]
251pub struct TypeS16;
252
253#[derive(Debug, Clone, PartialEq, Hash, Eq)]
254#[cfg_attr(feature = "host", derive(serde::Serialize, serde::Deserialize))]
255#[cfg_attr(feature = "host", derive(bincode::Encode, bincode::Decode))]
256#[cfg_attr(feature = "host", derive(poem_openapi::Object))]
257pub struct TypeU8;
258
259#[derive(Debug, Clone, PartialEq, Hash, Eq)]
260#[cfg_attr(feature = "host", derive(serde::Serialize, serde::Deserialize))]
261#[cfg_attr(feature = "host", derive(bincode::Encode, bincode::Decode))]
262#[cfg_attr(feature = "host", derive(poem_openapi::Object))]
263pub struct TypeS8;
264
265#[derive(Debug, Clone, PartialEq, Hash, Eq)]
266#[cfg_attr(feature = "host", derive(serde::Serialize, serde::Deserialize))]
267#[cfg_attr(feature = "host", derive(bincode::Encode, bincode::Decode))]
268#[cfg_attr(feature = "host", derive(poem_openapi::Object))]
269pub struct TypeBool;
270
271#[derive(Debug, Clone, PartialEq, Hash, Eq)]
272#[cfg_attr(feature = "host", derive(serde::Serialize, serde::Deserialize))]
273#[cfg_attr(feature = "host", derive(bincode::Encode, bincode::Decode))]
274#[cfg_attr(feature = "host", derive(poem_openapi::Object))]
275pub struct TypeHandle {
276 #[cfg_attr(feature = "host", serde(skip_serializing_if = "Option::is_none"))]
277 pub name: Option<String>,
278 #[cfg_attr(feature = "host", serde(skip_serializing_if = "Option::is_none"))]
279 pub owner: Option<String>,
280 pub resource_id: AnalysedResourceId,
281 pub mode: AnalysedResourceMode,
282}
283
284#[derive(Debug, Clone, Hash, PartialEq, Eq)]
285#[cfg_attr(feature = "host", derive(serde::Serialize, serde::Deserialize))]
286#[cfg_attr(feature = "host", serde(tag = "type"))]
287#[cfg_attr(feature = "host", derive(bincode::Encode, bincode::Decode))]
288#[cfg_attr(feature = "host", derive(poem_openapi::Union))]
289#[cfg_attr(feature = "host", oai(discriminator_name = "type", one_of = true))]
290pub enum AnalysedType {
291 Variant(TypeVariant),
292 Result(TypeResult),
293 Option(TypeOption),
294 Enum(TypeEnum),
295 Flags(TypeFlags),
296 Record(TypeRecord),
297 Tuple(TypeTuple),
298 List(TypeList),
299 Str(TypeStr),
300 Chr(TypeChr),
301 F64(TypeF64),
302 F32(TypeF32),
303 U64(TypeU64),
304 S64(TypeS64),
305 U32(TypeU32),
306 S32(TypeS32),
307 U16(TypeU16),
308 S16(TypeS16),
309 U8(TypeU8),
310 S8(TypeS8),
311 Bool(TypeBool),
312 Handle(TypeHandle),
313}
314
315impl AnalysedType {
316 pub fn name(&self) -> Option<&str> {
317 match self {
318 AnalysedType::Variant(typ) => typ.name.as_deref(),
319 AnalysedType::Result(typ) => typ.name.as_deref(),
320 AnalysedType::Option(typ) => typ.name.as_deref(),
321 AnalysedType::Enum(typ) => typ.name.as_deref(),
322 AnalysedType::Flags(typ) => typ.name.as_deref(),
323 AnalysedType::Record(typ) => typ.name.as_deref(),
324 AnalysedType::Tuple(typ) => typ.name.as_deref(),
325 AnalysedType::List(typ) => typ.name.as_deref(),
326 AnalysedType::Handle(typ) => typ.name.as_deref(),
327 _ => None,
328 }
329 }
330
331 pub fn with_optional_name(self, name: Option<String>) -> Self {
332 match self {
333 AnalysedType::Variant(mut typ) => {
334 typ.name = name;
335 AnalysedType::Variant(typ)
336 }
337 AnalysedType::Result(mut typ) => {
338 typ.name = name;
339 AnalysedType::Result(typ)
340 }
341 AnalysedType::Option(mut typ) => {
342 typ.name = name;
343 AnalysedType::Option(typ)
344 }
345 AnalysedType::Enum(mut typ) => {
346 typ.name = name;
347 AnalysedType::Enum(typ)
348 }
349 AnalysedType::Flags(mut typ) => {
350 typ.name = name;
351 AnalysedType::Flags(typ)
352 }
353 AnalysedType::Record(mut typ) => {
354 typ.name = name;
355 AnalysedType::Record(typ)
356 }
357 AnalysedType::Tuple(mut typ) => {
358 typ.name = name;
359 AnalysedType::Tuple(typ)
360 }
361 AnalysedType::List(mut typ) => {
362 typ.name = name;
363 AnalysedType::List(typ)
364 }
365 AnalysedType::Handle(mut typ) => {
366 typ.name = name;
367 AnalysedType::Handle(typ)
368 }
369 _ => self,
370 }
371 }
372
373 pub fn named(self, name: impl AsRef<str>) -> Self {
374 self.with_optional_name(Some(name.as_ref().to_string()))
375 }
376
377 pub fn owner(&self) -> Option<&str> {
378 match self {
379 AnalysedType::Variant(typ) => typ.owner.as_deref(),
380 AnalysedType::Result(typ) => typ.owner.as_deref(),
381 AnalysedType::Option(typ) => typ.owner.as_deref(),
382 AnalysedType::Enum(typ) => typ.owner.as_deref(),
383 AnalysedType::Flags(typ) => typ.owner.as_deref(),
384 AnalysedType::Record(typ) => typ.owner.as_deref(),
385 AnalysedType::Tuple(typ) => typ.owner.as_deref(),
386 AnalysedType::List(typ) => typ.owner.as_deref(),
387 AnalysedType::Handle(typ) => typ.owner.as_deref(),
388 _ => None,
389 }
390 }
391
392 pub fn with_optional_owner(self, owner: Option<String>) -> Self {
393 match self {
394 AnalysedType::Variant(mut typ) => {
395 typ.owner = owner;
396 AnalysedType::Variant(typ)
397 }
398 AnalysedType::Result(mut typ) => {
399 typ.owner = owner;
400 AnalysedType::Result(typ)
401 }
402 AnalysedType::Option(mut typ) => {
403 typ.owner = owner;
404 AnalysedType::Option(typ)
405 }
406 AnalysedType::Enum(mut typ) => {
407 typ.owner = owner;
408 AnalysedType::Enum(typ)
409 }
410 AnalysedType::Flags(mut typ) => {
411 typ.owner = owner;
412 AnalysedType::Flags(typ)
413 }
414 AnalysedType::Record(mut typ) => {
415 typ.owner = owner;
416 AnalysedType::Record(typ)
417 }
418 AnalysedType::Tuple(mut typ) => {
419 typ.owner = owner;
420 AnalysedType::Tuple(typ)
421 }
422 AnalysedType::List(mut typ) => {
423 typ.owner = owner;
424 AnalysedType::List(typ)
425 }
426 AnalysedType::Handle(mut typ) => {
427 typ.owner = owner;
428 AnalysedType::Handle(typ)
429 }
430 _ => self,
431 }
432 }
433
434 pub fn owned(self, owner: impl AsRef<str>) -> Self {
435 self.with_optional_owner(Some(owner.as_ref().to_string()))
436 }
437
438 pub fn contains_handle(&self) -> bool {
439 match self {
440 AnalysedType::Handle(_) => true,
441 AnalysedType::Variant(typ) => typ
442 .cases
443 .iter()
444 .any(|case| case.typ.as_ref().is_some_and(|t| t.contains_handle())),
445 AnalysedType::Result(typ) => {
446 typ.ok.as_ref().is_some_and(|t| t.contains_handle())
447 || typ.err.as_ref().is_some_and(|t| t.contains_handle())
448 }
449 AnalysedType::Option(typ) => typ.inner.contains_handle(),
450 AnalysedType::Record(typ) => typ.fields.iter().any(|f| f.typ.contains_handle()),
451 AnalysedType::Tuple(typ) => typ.items.iter().any(|t| t.contains_handle()),
452 AnalysedType::List(typ) => typ.inner.contains_handle(),
453 _ => false,
454 }
455 }
456}
457
458pub mod analysed_type {
459 use crate::analysis::*;
460
461 pub fn field(name: &str, typ: AnalysedType) -> NameTypePair {
462 NameTypePair {
463 name: name.to_string(),
464 typ,
465 }
466 }
467
468 pub fn case(name: &str, typ: AnalysedType) -> NameOptionTypePair {
469 NameOptionTypePair {
470 name: name.to_string(),
471 typ: Some(typ),
472 }
473 }
474
475 pub fn opt_case(name: &str, typ: Option<AnalysedType>) -> NameOptionTypePair {
476 NameOptionTypePair {
477 name: name.to_string(),
478 typ,
479 }
480 }
481
482 pub fn unit_case(name: &str) -> NameOptionTypePair {
483 NameOptionTypePair {
484 name: name.to_string(),
485 typ: None,
486 }
487 }
488
489 pub fn bool() -> AnalysedType {
490 AnalysedType::Bool(TypeBool)
491 }
492
493 pub fn s8() -> AnalysedType {
494 AnalysedType::S8(TypeS8)
495 }
496
497 pub fn s16() -> AnalysedType {
498 AnalysedType::S16(TypeS16)
499 }
500
501 pub fn s32() -> AnalysedType {
502 AnalysedType::S32(TypeS32)
503 }
504
505 pub fn s64() -> AnalysedType {
506 AnalysedType::S64(TypeS64)
507 }
508
509 pub fn u8() -> AnalysedType {
510 AnalysedType::U8(TypeU8)
511 }
512
513 pub fn u16() -> AnalysedType {
514 AnalysedType::U16(TypeU16)
515 }
516
517 pub fn u32() -> AnalysedType {
518 AnalysedType::U32(TypeU32)
519 }
520
521 pub fn u64() -> AnalysedType {
522 AnalysedType::U64(TypeU64)
523 }
524
525 pub fn f32() -> AnalysedType {
526 AnalysedType::F32(TypeF32)
527 }
528
529 pub fn f64() -> AnalysedType {
530 AnalysedType::F64(TypeF64)
531 }
532
533 pub fn chr() -> AnalysedType {
534 AnalysedType::Chr(TypeChr)
535 }
536
537 pub fn str() -> AnalysedType {
538 AnalysedType::Str(TypeStr)
539 }
540
541 pub fn list(inner: AnalysedType) -> AnalysedType {
542 AnalysedType::List(TypeList {
543 name: None,
544 owner: None,
545 inner: Box::new(inner),
546 })
547 }
548
549 pub fn option(inner: AnalysedType) -> AnalysedType {
550 AnalysedType::Option(TypeOption {
551 name: None,
552 owner: None,
553 inner: Box::new(inner),
554 })
555 }
556
557 pub fn flags(names: &[&str]) -> AnalysedType {
558 AnalysedType::Flags(TypeFlags {
559 name: None,
560 owner: None,
561 names: names.iter().map(|n| n.to_string()).collect(),
562 })
563 }
564
565 pub fn r#enum(cases: &[&str]) -> AnalysedType {
566 AnalysedType::Enum(TypeEnum {
567 name: None,
568 owner: None,
569 cases: cases.iter().map(|n| n.to_string()).collect(),
570 })
571 }
572
573 pub fn tuple(items: Vec<AnalysedType>) -> AnalysedType {
574 AnalysedType::Tuple(TypeTuple {
575 name: None,
576 owner: None,
577 items,
578 })
579 }
580
581 pub fn result(ok: AnalysedType, err: AnalysedType) -> AnalysedType {
582 AnalysedType::Result(TypeResult {
583 name: None,
584 owner: None,
585 ok: Some(Box::new(ok)),
586 err: Some(Box::new(err)),
587 })
588 }
589
590 pub fn result_ok(ok: AnalysedType) -> AnalysedType {
591 AnalysedType::Result(TypeResult {
592 name: None,
593 owner: None,
594 ok: Some(Box::new(ok)),
595 err: None,
596 })
597 }
598
599 pub fn result_err(err: AnalysedType) -> AnalysedType {
600 AnalysedType::Result(TypeResult {
601 name: None,
602 owner: None,
603 ok: None,
604 err: Some(Box::new(err)),
605 })
606 }
607
608 pub fn record(fields: Vec<NameTypePair>) -> AnalysedType {
609 AnalysedType::Record(TypeRecord {
610 name: None,
611 owner: None,
612 fields,
613 })
614 }
615
616 pub fn variant(cases: Vec<NameOptionTypePair>) -> AnalysedType {
617 AnalysedType::Variant(TypeVariant {
618 name: None,
619 owner: None,
620 cases,
621 })
622 }
623
624 pub fn handle(resource_id: AnalysedResourceId, mode: AnalysedResourceMode) -> AnalysedType {
625 AnalysedType::Handle(TypeHandle {
626 name: None,
627 owner: None,
628 resource_id,
629 mode,
630 })
631 }
632}
633
634#[derive(Debug, Clone, PartialEq, Hash, Eq)]
635#[cfg_attr(feature = "host", derive(serde::Serialize, serde::Deserialize))]
636#[cfg_attr(feature = "host", derive(bincode::Encode, bincode::Decode))]
637#[cfg_attr(feature = "host", derive(poem_openapi::Enum))]
638pub enum AnalysedResourceMode {
639 Owned,
640 Borrowed,
641}
642
643#[derive(Debug, Copy, Clone, PartialEq, Hash, Eq)]
644#[cfg_attr(feature = "host", derive(serde::Serialize, serde::Deserialize))]
645#[cfg_attr(feature = "host", derive(bincode::Encode, bincode::Decode))]
646#[cfg_attr(feature = "host", derive(poem_openapi::NewType))]
647pub struct AnalysedResourceId(pub u64);
648
649#[derive(Debug, Clone, PartialEq, Hash, Eq)]
650#[cfg_attr(feature = "host", derive(serde::Serialize, serde::Deserialize))]
651#[cfg_attr(feature = "host", derive(bincode::Encode, bincode::Decode))]
652#[cfg_attr(feature = "host", derive(poem_openapi::Object))]
653pub struct AnalysedFunctionParameter {
654 pub name: String,
655 pub typ: AnalysedType,
656}
657
658#[derive(Debug, Clone, PartialEq, Hash, Eq)]
659#[cfg_attr(feature = "host", derive(serde::Serialize, serde::Deserialize))]
660#[cfg_attr(feature = "host", derive(bincode::Encode, bincode::Decode))]
661#[cfg_attr(feature = "host", derive(poem_openapi::Object))]
662pub struct AnalysedFunctionResult {
663 pub typ: AnalysedType,
664}
665
666#[derive(Debug, Clone)]
667#[cfg_attr(feature = "host", derive(serde::Serialize, serde::Deserialize))]
668#[cfg_attr(feature = "host", derive(bincode::Encode, bincode::Decode))]
669#[cfg_attr(feature = "host", derive(poem_openapi::Object))]
670pub struct InterfaceCouldNotBeAnalyzedWarning {
671 pub name: String,
672 pub failure: AnalysisFailure,
673}
674
675#[derive(Debug, Clone)]
676#[cfg_attr(feature = "host", derive(serde::Serialize, serde::Deserialize))]
677#[cfg_attr(feature = "host", serde(tag = "type"))]
678#[cfg_attr(feature = "host", derive(bincode::Encode, bincode::Decode))]
679#[cfg_attr(feature = "host", derive(poem_openapi::Union))]
680#[cfg_attr(feature = "host", oai(discriminator_name = "type", one_of = true))]
681pub enum AnalysisWarning {
682 InterfaceCouldNotBeAnalyzed(InterfaceCouldNotBeAnalyzedWarning),
683}
684
685impl Display for AnalysisWarning {
686 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
687 match self {
688 AnalysisWarning::InterfaceCouldNotBeAnalyzed(warning) => {
689 write!(
690 f,
691 "Interface could not be analyzed: {} {}",
692 warning.name, warning.failure.reason
693 )
694 }
695 }
696 }
697}
698
699#[derive(Debug, Clone)]
700#[cfg_attr(feature = "host", derive(serde::Serialize, serde::Deserialize))]
701#[cfg_attr(feature = "host", derive(bincode::Encode, bincode::Decode))]
702#[cfg_attr(feature = "host", derive(poem_openapi::Object))]
703pub struct AnalysisFailure {
704 pub reason: String,
705}
706
707impl AnalysisFailure {
708 pub fn failed(message: impl Into<String>) -> AnalysisFailure {
709 AnalysisFailure {
710 reason: message.into(),
711 }
712 }
713
714 pub fn fail_on_missing<T>(value: Option<T>, description: impl AsRef<str>) -> AnalysisResult<T> {
715 match value {
716 Some(value) => Ok(value),
717 None => Err(AnalysisFailure::failed(format!(
718 "Missing {}",
719 description.as_ref()
720 ))),
721 }
722 }
723}
724
725#[cfg(test)]
726mod tests {
727 use crate::analysis::analysed_type::{bool, list, str};
728 use crate::analysis::{
729 AnalysedExport, AnalysedFunction, AnalysedFunctionParameter, AnalysedFunctionResult,
730 AnalysedInstance,
731 };
732 use poem_openapi::types::ToJSON;
733 use test_r::test;
734
735 #[cfg(feature = "host")]
736 #[cfg(feature = "host")]
737 #[test]
738 fn analysed_export_poem_and_serde_are_compatible() {
739 let export1 = AnalysedExport::Instance(AnalysedInstance {
740 name: "inst1".to_string(),
741 functions: vec![AnalysedFunction {
742 name: "func1".to_string(),
743 parameters: vec![AnalysedFunctionParameter {
744 name: "param1".to_string(),
745 typ: bool(),
746 }],
747 result: Some(AnalysedFunctionResult { typ: list(str()) }),
748 }],
749 });
750 let poem_serialized = export1.to_json_string();
751 let serde_deserialized: AnalysedExport = serde_json::from_str(&poem_serialized).unwrap();
752
753 assert_eq!(export1, serde_deserialized);
754 }
755}