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
}