## Coverage Report

#### Created: 2025-09-08 21:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)

    /home/noah/src/ruchy/src/wasm/wit.rs

    Line
    Count
    Source
    1
    //! WIT (WebAssembly Interface Type) generation for Ruchy (RUCHY-0819)
    2
    //!
    3
    //! Generates WIT interface definitions from Ruchy code for component interoperability.
    4
    5
    use anyhow::{Context, Result};
    6
    use serde::{Deserialize, Serialize};
    7
    use std::collections::{HashMap, HashSet};
    8
    use std::path::Path;
    9
    use std::fs;
    10
    use std::fmt;
    11
    12
    /// WIT interface definition
    13
    #[derive(Debug, Clone)]
    14
    pub struct WitInterface {
    15
        /// Interface name
    16
        pub name: String,
    17
    18
        /// Interface version
    19
        pub version: String,
    20
    21
        /// Package information
    22
        pub package: PackageInfo,
    23
    24
        /// Type definitions
    25
        pub types: Vec<TypeDefinition>,
    26
    27
        /// Function definitions
    28
        pub functions: Vec<FunctionDefinition>,
    29
    30
        /// Resource definitions
    31
        pub resources: Vec<ResourceDefinition>,
    32
    33
        /// World definition
    34
        pub world: Option<WorldDefinition>,
    35
    }
    36
    37
    /// WIT interface generator
    38
    pub struct WitGenerator {
    39
        /// Generation configuration
    40
        config: WitConfig,
    41
    42
        /// Type registry
    43
        _type_registry: TypeRegistry,
    44
    45
        /// Import tracking
    46
        _imports: HashSet<String>,
    47
    }
    48
    49
    /// Configuration for WIT generation
    50
    #[derive(Debug, Clone, Serialize, Deserialize)]
    51
    pub struct WitConfig {
    52
        /// Generate documentation comments
    53
        pub include_docs: bool,
    54
    55
        /// Generate type aliases
    56
        pub use_type_aliases: bool,
    57
    58
        /// Generate resource types
    59
        pub generate_resources: bool,
    60
    61
        /// Component model version
    62
        pub component_model_version: String,
    63
    64
        /// Custom type mappings
    65
        pub type_mappings: HashMap<String, String>,
    66
    67
        /// World name
    68
        pub world_name: Option<String>,
    69
    }
    70
    71
    /// Interface definition structure
    72
    #[derive(Debug, Clone, Serialize, Deserialize)]
    73
    pub struct InterfaceDefinition {
    74
        /// Interface name
    75
        pub name: String,
    76
    77
        /// Interface functions
    78
        pub functions: Vec<InterfaceFunction>,
    79
    80
        /// Interface types
    81
        pub types: Vec<InterfaceType>,
    82
    83
        /// Documentation
    84
        pub documentation: Option<String>,
    85
    }
    86
    87
    /// Package information
    88
    #[derive(Debug, Clone, Serialize, Deserialize)]
    89
    pub struct PackageInfo {
    90
        /// Package namespace
    91
        pub namespace: String,
    92
    93
        /// Package name
    94
        pub name: String,
    95
    96
        /// Package version
    97
        pub version: String,
    98
    }
    99
    100
    /// Type definition in WIT
    101
    #[derive(Debug, Clone, Serialize, Deserialize)]
    102
    pub struct TypeDefinition {
    103
        /// Type name
    104
        pub name: String,
    105
    106
        /// Type kind
    107
        pub kind: TypeKind,
    108
    109
        /// Documentation
    110
        pub documentation: Option<String>,
    111
    }
    112
    113
    /// Function definition in WIT
    114
    #[derive(Debug, Clone, Serialize, Deserialize)]
    115
    pub struct FunctionDefinition {
    116
        /// Function name
    117
        pub name: String,
    118
    119
        /// Parameters
    120
        pub params: Vec<Parameter>,
    121
    122
        /// Return type
    123
        pub return_type: Option<WitType>,
    124
    125
        /// Whether function is async
    126
        pub is_async: bool,
    127
    128
        /// Documentation
    129
        pub documentation: Option<String>,
    130
    }
    131
    132
    /// Resource definition in WIT
    133
    #[derive(Debug, Clone, Serialize, Deserialize)]
    134
    pub struct ResourceDefinition {
    135
        /// Resource name
    136
        pub name: String,
    137
    138
        /// Resource methods
    139
        pub methods: Vec<ResourceMethod>,
    140
    141
        /// Constructor
    142
        pub constructor: Option<FunctionDefinition>,
    143
    144
        /// Documentation
    145
        pub documentation: Option<String>,
    146
    }
    147
    148
    /// World definition for component composition
    149
    #[derive(Debug, Clone, Serialize, Deserialize)]
    150
    pub struct WorldDefinition {
    151
        /// World name
    152
        pub name: String,
    153
    154
        /// Imports
    155
        pub imports: Vec<WorldImport>,
    156
    157
        /// Exports
    158
        pub exports: Vec<WorldExport>,
    159
    160
        /// Documentation
    161
        pub documentation: Option<String>,
    162
    }
    163
    164
    /// Type kinds in WIT
    165
    #[derive(Debug, Clone, Serialize, Deserialize)]
    166
    pub enum TypeKind {
    167
        /// Record type (struct)
    168
        Record(Vec<Field>),
    169
        /// Variant type (enum)
    170
        Variant(Vec<VariantCase>),
    171
        /// Flags type (bitflags)
    172
        Flags(Vec<String>),
    173
        /// Tuple type
    174
        Tuple(Vec<WitType>),
    175
        /// List type
    176
        List(Box<WitType>),
    177
        /// Option type
    178
        Option(Box<WitType>),
    179
        /// Result type
    180
        Result {
    181
            ok: Option<Box<WitType>>,
    182
            err: Option<Box<WitType>>,
    183
        },
    184
        /// Type alias
    185
        Alias(Box<WitType>),
    186
    }
    187
    188
    /// WIT type representation
    189
    #[derive(Debug, Clone, Serialize, Deserialize)]
    190
    pub enum WitType {
    191
        /// Boolean
    192
        Bool,
    193
        /// Unsigned 8-bit integer
    194
        U8,
    195
        /// Unsigned 16-bit integer
    196
        U16,
    197
        /// Unsigned 32-bit integer
    198
        U32,
    199
        /// Unsigned 64-bit integer
    200
        U64,
    201
        /// Signed 8-bit integer
    202
        S8,
    203
        /// Signed 16-bit integer
    204
        S16,
    205
        /// Signed 32-bit integer
    206
        S32,
    207
        /// Signed 64-bit integer
    208
        S64,
    209
        /// 32-bit float
    210
        F32,
    211
        /// 64-bit float
    212
        F64,
    213
        /// Character
    214
        Char,
    215
        /// String
    216
        String,
    217
        /// Named type reference
    218
        Named(String),
    219
        /// List type
    220
        List(Box<WitType>),
    221
        /// Option type
    222
        Option(Box<WitType>),
    223
        /// Result type
    224
        Result {
    225
            ok: Option<Box<WitType>>,
    226
            err: Option<Box<WitType>>,
    227
        },
    228
        /// Tuple type
    229
        Tuple(Vec<WitType>),
    230
    }
    231
    232
    /// Record field
    233
    #[derive(Debug, Clone, Serialize, Deserialize)]
    234
    pub struct Field {
    235
        /// Field name
    236
        pub name: String,
    237
    238
        /// Field type
    239
        pub field_type: WitType,
    240
    241
        /// Documentation
    242
        pub documentation: Option<String>,
    243
    }
    244
    245
    /// Variant case
    246
    #[derive(Debug, Clone, Serialize, Deserialize)]
    247
    pub struct VariantCase {
    248
        /// Case name
    249
        pub name: String,
    250
    251
        /// Associated data
    252
        pub payload: Option<WitType>,
    253
    254
        /// Documentation
    255
        pub documentation: Option<String>,
    256
    }
    257
    258
    /// Function parameter
    259
    #[derive(Debug, Clone, Serialize, Deserialize)]
    260
    pub struct Parameter {
    261
        /// Parameter name
    262
        pub name: String,
    263
    264
        /// Parameter type
    265
        pub param_type: WitType,
    266
    }
    267
    268
    /// Resource method
    269
    #[derive(Debug, Clone, Serialize, Deserialize)]
    270
    pub struct ResourceMethod {
    271
        /// Method name
    272
        pub name: String,
    273
    274
        /// Method kind
    275
        pub kind: MethodKind,
    276
    277
        /// Method definition
    278
        pub function: FunctionDefinition,
    279
    }
    280
    281
    /// Method kinds for resources
    282
    #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
    283
    pub enum MethodKind {
    284
        /// Constructor method
    285
        Constructor,
    286
        /// Static method
    287
        Static,
    288
        /// Instance method
    289
        Instance,
    290
    }
    291
    292
    /// Interface function
    293
    #[derive(Debug, Clone, Serialize, Deserialize)]
    294
    pub struct InterfaceFunction {
    295
        /// Function name
    296
        pub name: String,
    297
    298
        /// Parameters
    299
        pub params: Vec<(String, String)>,
    300
    301
        /// Return type
    302
        pub return_type: Option<String>,
    303
    }
    304
    305
    /// Interface type
    306
    #[derive(Debug, Clone, Serialize, Deserialize)]
    307
    pub struct InterfaceType {
    308
        /// Type name
    309
        pub name: String,
    310
    311
        /// Type definition
    312
        pub definition: String,
    313
    }
    314
    315
    /// World import
    316
    #[derive(Debug, Clone, Serialize, Deserialize)]
    317
    pub struct WorldImport {
    318
        /// Import name
    319
        pub name: String,
    320
    321
        /// Import interface
    322
        pub interface: String,
    323
    }
    324
    325
    /// World export
    326
    #[derive(Debug, Clone, Serialize, Deserialize)]
    327
    pub struct WorldExport {
    328
        /// Export name
    329
        pub name: String,
    330
    331
        /// Export interface
    332
        pub interface: String,
    333
    }
    334
    335
    /// Type registry for managing type definitions
    336
    struct TypeRegistry {
    337
        /// Registered types
    338
        _types: HashMap<String, TypeDefinition>,
    339
    340
        /// Type dependencies
    341
        _dependencies: HashMap<String, HashSet<String>>,
    342
    }
    343
    344
    impl Default for WitConfig {
    345
    0
        fn default() -> Self {
    346
    0
            Self {
    347
    0
                include_docs: true,
    348
    0
                use_type_aliases: true,
    349
    0
                generate_resources: true,
    350
    0
                component_model_version: "0.2.0".to_string(),
    351
    0
                type_mappings: HashMap::new(),
    352
    0
                world_name: None,
    353
    0
            }
    354
    0
        }
    355
    }
    356
    357
    impl Default for WitGenerator {
    358
    0
        fn default() -> Self {
    359
    0
            Self::new()
    360
    0
        }
    361
    }
    362
    363
    impl WitGenerator {
    364
        /// Create a new WIT generator with default config
    365
    0
        pub fn new() -> Self {
    366
    0
            Self {
    367
    0
                config: WitConfig::default(),
    368
    0
                _type_registry: TypeRegistry::new(),
    369
    0
                _imports: HashSet::new(),
    370
    0
            }
    371
    0
        }
    372
    373
        /// Create a new WIT generator with specific config
    374
    0
        pub fn new_with_config(config: WitConfig) -> Self {
    375
    0
            Self {
    376
    0
                config,
    377
    0
                _type_registry: TypeRegistry::new(),
    378
    0
                _imports: HashSet::new(),
    379
    0
            }
    380
    0
        }
    381
    382
        /// Set the world name
    383
    0
        pub fn with_world(&mut self, world: &str) -> &mut Self {
    384
    0
            self.config.world_name = Some(world.to_string());
    385
    0
            self
    386
    0
        }
    387
    388
        /// Generate WIT interface from component
    389
    0
        pub fn generate(&mut self, component: &super::component::WasmComponent) -> Result<WitInterface> {
    390
    0
            self.generate_from_component(component)
    391
    0
        }
    392
    393
        /// Generate WIT interface from component
    394
    0
        pub fn generate_from_component(&mut self, _component: &super::component::WasmComponent) -> Result<WitInterface> {
    395
            // In a real implementation, analyze the component's exports and imports
    396
    0
            self.generate_default()
    397
    0
        }
    398
    399
        /// Generate WIT interface from Ruchy source
    400
    0
        pub fn generate_from_source(&mut self, _source: &str) -> Result<WitInterface> {
    401
            // In a real implementation, this would:
    402
            // 1. Parse Ruchy source code
    403
            // 2. Extract type definitions
    404
            // 3. Extract function signatures
    405
            // 4. Generate corresponding WIT definitions
    406
    407
            // For now, create a sample interface
    408
    0
            let interface = WitInterface {
    409
    0
                name: "ruchy-component".to_string(),
    410
    0
                version: "0.1.0".to_string(),
    411
    0
                package: PackageInfo {
    412
    0
                    namespace: "ruchy".to_string(),
    413
    0
                    name: "component".to_string(),
    414
    0
                    version: "0.1.0".to_string(),
    415
    0
                },
    416
    0
                types: vec![
    417
    0
                    TypeDefinition {
    418
    0
                        name: "request".to_string(),
    419
    0
                        kind: TypeKind::Record(vec![
    420
    0
                            Field {
    421
    0
                                name: "method".to_string(),
    422
    0
                                field_type: WitType::String,
    423
    0
                                documentation: Some("HTTP method".to_string()),
    424
    0
                            },
    425
    0
                            Field {
    426
    0
                                name: "path".to_string(),
    427
    0
                                field_type: WitType::String,
    428
    0
                                documentation: Some("Request path".to_string()),
    429
    0
                            },
    430
    0
                        ]),
    431
    0
                        documentation: Some("HTTP request type".to_string()),
    432
    0
                    },
    433
    0
                ],
    434
    0
                functions: vec![
    435
    0
                    FunctionDefinition {
    436
    0
                        name: "handle-request".to_string(),
    437
    0
                        params: vec![
    438
    0
                            Parameter {
    439
    0
                                name: "req".to_string(),
    440
    0
                                param_type: WitType::Named("request".to_string()),
    441
    0
                            },
    442
    0
                        ],
    443
    0
                        return_type: Some(WitType::String),
    444
    0
                        is_async: false,
    445
    0
                        documentation: Some("Handle an HTTP request".to_string()),
    446
    0
                    },
    447
    0
                ],
    448
    0
                resources: vec![],
    449
    0
                world: Some(WorldDefinition {
    450
    0
                    name: "http-handler".to_string(),
    451
    0
                    imports: vec![],
    452
    0
                    exports: vec![
    453
    0
                        WorldExport {
    454
    0
                            name: "handler".to_string(),
    455
    0
                            interface: "ruchy:component/handler".to_string(),
    456
    0
                        },
    457
    0
                    ],
    458
    0
                    documentation: Some("HTTP handler world".to_string()),
    459
    0
                }),
    460
    0
            };
    461
    462
    0
            Ok(interface)
    463
    0
        }
    464
    465
        /// Generate a default WIT interface
    466
    0
        fn generate_default(&mut self) -> Result<WitInterface> {
    467
    0
            self.generate_from_source("")
    468
    0
        }
    469
    470
        /// Add a custom type mapping
    471
    0
        pub fn add_type_mapping(&mut self, ruchy_type: String, wit_type: String) {
    472
    0
            self.config.type_mappings.insert(ruchy_type, wit_type);
    473
    0
        }
    474
    475
        /// Generate WIT file content
    476
    0
        pub fn generate_wit_file(&self, interface: &WitInterface) -> String {
    477
    0
            let mut wit = String::new();
    478
    479
            // Package declaration
    480
    0
            wit.push_str(&format!(
    481
    0
                "package {}:{}/{}@{};\n\n",
    482
    0
                interface.package.namespace,
    483
    0
                interface.package.name,
    484
    0
                interface.name,
    485
    0
                interface.version
    486
    0
            ));
    487
    488
            // Interface declaration
    489
    0
            wit.push_str(&format!("interface {} {{\n", interface.name));
    490
    491
            // Type definitions
    492
    0
            for type_def in &interface.types {
    493
    0
                if let Some(doc) = &type_def.documentation {
    494
    0
                    wit.push_str(&format!("  /// {doc}\n"));
    495
    0
                }
    496
    0
                wit.push_str(&format!("  {}\n\n", self.format_type_definition(type_def)));
    497
            }
    498
    499
            // Function definitions
    500
    0
            for func in &interface.functions {
    501
    0
                if let Some(doc) = &func.documentation {
    502
    0
                    wit.push_str(&format!("  /// {doc}\n"));
    503
    0
                }
    504
    0
                wit.push_str(&format!("  {}\n", self.format_function(func)));
    505
            }
    506
    507
    0
            wit.push_str("}\n\n");
    508
    509
            // World definition
    510
    0
            if let Some(world) = &interface.world {
    511
    0
                wit.push_str(&self.format_world(world));
    512
    0
            }
    513
    514
    0
            wit
    515
    0
        }
    516
    517
    0
        fn format_type_definition(&self, type_def: &TypeDefinition) -> String {
    518
    0
            match &type_def.kind {
    519
    0
                TypeKind::Record(fields) => {
    520
    0
                    let mut s = format!("record {} {{\n", type_def.name);
    521
    0
                    for field in fields {
    522
    0
                        if let Some(doc) = &field.documentation {
    523
    0
                            s.push_str(&format!("    /// {doc}\n"));
    524
    0
                        }
    525
    0
                        s.push_str(&format!("    {}: {},\n", field.name, self.format_wit_type(&field.field_type)));
    526
                    }
    527
    0
                    s.push_str("  }");
    528
    0
                    s
    529
                }
    530
    0
                TypeKind::Variant(cases) => {
    531
    0
                    let mut s = format!("variant {} {{\n", type_def.name);
    532
    0
                    for case in cases {
    533
    0
                        if let Some(doc) = &case.documentation {
    534
    0
                            s.push_str(&format!("    /// {doc}\n"));
    535
    0
                        }
    536
    0
                        if let Some(payload) = &case.payload {
    537
    0
                            s.push_str(&format!("    {}({}),\n", case.name, self.format_wit_type(payload)));
    538
    0
                        } else {
    539
    0
                            s.push_str(&format!("    {},\n", case.name));
    540
    0
                        }
    541
                    }
    542
    0
                    s.push_str("  }");
    543
    0
                    s
    544
                }
    545
    0
                TypeKind::Flags(flags) => {
    546
    0
                    let mut s = format!("flags {} {{\n", type_def.name);
    547
    0
                    for flag in flags {
    548
    0
                        s.push_str(&format!("    {flag},\n"));
    549
    0
                    }
    550
    0
                    s.push_str("  }");
    551
    0
                    s
    552
                }
    553
    0
                TypeKind::Alias(wit_type) => {
    554
    0
                    format!("type {} = {}", type_def.name, self.format_wit_type(wit_type))
    555
                }
    556
    0
                _ => format!("type {}", type_def.name),
    557
            }
    558
    0
        }
    559
    560
    0
        fn format_function(&self, func: &FunctionDefinition) -> String {
    561
    0
            let params = func.params.iter()
    562
    0
                .map(|p| format!("{}: {}", p.name, self.format_wit_type(&p.param_type)))
    563
    0
                .collect::<Vec<_>>()
    564
    0
                .join(", ");
    565
    566
    0
            let return_part = if let Some(ret) = &func.return_type {
    567
    0
                format!(" -> {}", self.format_wit_type(ret))
    568
            } else {
    569
    0
                String::new()
    570
            };
    571
    572
    0
            format!("{}: func({}){};", func.name, params, return_part)
    573
    0
        }
    574
    575
    0
        fn format_wit_type(&self, wit_type: &WitType) -> String {
    576
    0
            match wit_type {
    577
    0
                WitType::Bool => "bool".to_string(),
    578
    0
                WitType::U8 => "u8".to_string(),
    579
    0
                WitType::U16 => "u16".to_string(),
    580
    0
                WitType::U32 => "u32".to_string(),
    581
    0
                WitType::U64 => "u64".to_string(),
    582
    0
                WitType::S8 => "s8".to_string(),
    583
    0
                WitType::S16 => "s16".to_string(),
    584
    0
                WitType::S32 => "s32".to_string(),
    585
    0
                WitType::S64 => "s64".to_string(),
    586
    0
                WitType::F32 => "f32".to_string(),
    587
    0
                WitType::F64 => "f64".to_string(),
    588
    0
                WitType::Char => "char".to_string(),
    589
    0
                WitType::String => "string".to_string(),
    590
    0
                WitType::Named(name) => name.clone(),
    591
    0
                WitType::List(inner) => format!("list<{}>", self.format_wit_type(inner)),
    592
    0
                WitType::Option(inner) => format!("option<{}>", self.format_wit_type(inner)),
    593
    0
                WitType::Result { ok, err } => {
    594
    0
                    let ok_str = ok.as_ref().map_or_else(|| "_".to_string(), |t| self.format_wit_type(t));
    595
    0
                    let err_str = err.as_ref().map_or_else(|| "_".to_string(), |t| self.format_wit_type(t));
    596
    0
                    format!("result<{ok_str}, {err_str}>")
    597
                }
    598
    0
                WitType::Tuple(types) => {
    599
    0
                    let types_str = types.iter()
    600
    0
                        .map(|t| self.format_wit_type(t))
    601
    0
                        .collect::<Vec<_>>()
    602
    0
                        .join(", ");
    603
    0
                    format!("tuple<{types_str}>")
    604
                }
    605
            }
    606
    0
        }
    607
    608
    0
        fn format_world(&self, world: &WorldDefinition) -> String {
    609
    0
            let mut s = String::new();
    610
    611
    0
            if let Some(doc) = &world.documentation {
    612
    0
                s.push_str(&format!("/// {doc}\n"));
    613
    0
            }
    614
    615
    0
            s.push_str(&format!("world {} {{\n", world.name));
    616
    617
            // Imports
    618
    0
            for import in &world.imports {
    619
    0
                s.push_str(&format!("  import {}: {};\n", import.name, import.interface));
    620
    0
            }
    621
    622
            // Exports
    623
    0
            for export in &world.exports {
    624
    0
                s.push_str(&format!("  export {}: {};\n", export.name, export.interface));
    625
    0
            }
    626
    627
    0
            s.push_str("}\n");
    628
    0
            s
    629
    0
        }
    630
    }
    631
    632
    impl fmt::Display for WitInterface {
    633
    0
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    634
    0
            let generator = WitGenerator::new();
    635
    0
            write!(f, "{}", generator.generate_wit_file(self))
    636
    0
        }
    637
    }
    638
    639
    impl WitInterface {
    640
        /// Save the WIT interface to a file
    641
    0
        pub fn save(&self, path: impl AsRef<Path>) -> Result<()> {
    642
    0
            let generator = WitGenerator::new();
    643
    0
            let wit_content = generator.generate_wit_file(self);
    644
    645
    0
            fs::write(path.as_ref(), wit_content)
    646
    0
                .with_context(|| format!("Failed to write WIT file to {}", path.as_ref().display()))?;
    647
    648
    0
            Ok(())
    649
    0
        }
    650
    }
    651
    652
    impl TypeRegistry {
    653
    0
        fn new() -> Self {
    654
    0
            Self {
    655
    0
                _types: HashMap::new(),
    656
    0
                _dependencies: HashMap::new(),
    657
    0
            }
    658
    0
        }
    659
    }