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