autozig_engine/
type_mapper.rs

1//! Type mapping between Zig and Rust types
2
3use std::collections::HashMap;
4
5/// Maps Zig types to Rust types for FFI
6pub struct TypeMapper {
7    mappings: HashMap<&'static str, &'static str>,
8}
9
10impl TypeMapper {
11    pub fn new() -> Self {
12        let mut mappings = HashMap::new();
13
14        // Integer types
15        mappings.insert("i8", "i8");
16        mappings.insert("i16", "i16");
17        mappings.insert("i32", "i32");
18        mappings.insert("i64", "i64");
19        mappings.insert("i128", "i128");
20        mappings.insert("isize", "isize");
21
22        mappings.insert("u8", "u8");
23        mappings.insert("u16", "u16");
24        mappings.insert("u32", "u32");
25        mappings.insert("u64", "u64");
26        mappings.insert("u128", "u128");
27        mappings.insert("usize", "usize");
28
29        // Floating point
30        mappings.insert("f32", "f32");
31        mappings.insert("f64", "f64");
32
33        // Boolean (Zig bool is u8 in C ABI)
34        mappings.insert("bool", "u8");
35
36        // Void
37        mappings.insert("void", "()");
38
39        // Pointer types
40        mappings.insert("[*]const u8", "*const u8");
41        mappings.insert("[*]u8", "*mut u8");
42
43        Self { mappings }
44    }
45
46    /// Map a Zig type to its Rust equivalent
47    pub fn map_type(&self, zig_type: &str) -> Option<&str> {
48        self.mappings.get(zig_type).copied()
49    }
50
51    /// Check if a type is a pointer that needs special handling
52    pub fn is_slice_type(&self, zig_type: &str) -> bool {
53        zig_type.starts_with("[*]")
54    }
55}
56
57impl Default for TypeMapper {
58    fn default() -> Self {
59        Self::new()
60    }
61}
62
63/// Conversion strategy for function parameters
64#[derive(Debug, Clone, PartialEq)]
65pub enum ParamConversion {
66    /// Direct pass-through (primitive types)
67    Direct,
68    /// Convert &[T] to (ptr, len)
69    SliceToPtrLen,
70    /// Convert &str to (ptr, len)
71    StrToPtrLen,
72}
73
74/// Analyze a Rust type and determine conversion strategy
75pub fn analyze_param_type(ty: &syn::Type) -> ParamConversion {
76    match ty {
77        syn::Type::Reference(type_ref) => {
78            // Check if it's &[T] or &str
79            match &*type_ref.elem {
80                syn::Type::Slice(_) => ParamConversion::SliceToPtrLen,
81                syn::Type::Path(type_path) => {
82                    if let Some(segment) = type_path.path.segments.last() {
83                        if segment.ident == "str" {
84                            return ParamConversion::StrToPtrLen;
85                        }
86                    }
87                    ParamConversion::Direct
88                },
89                _ => ParamConversion::Direct,
90            }
91        },
92        _ => ParamConversion::Direct,
93    }
94}
95
96#[cfg(test)]
97mod tests {
98    use super::*;
99
100    #[test]
101    fn test_type_mapper() {
102        let mapper = TypeMapper::new();
103
104        assert_eq!(mapper.map_type("i32"), Some("i32"));
105        assert_eq!(mapper.map_type("u64"), Some("u64"));
106        assert_eq!(mapper.map_type("f32"), Some("f32"));
107        assert_eq!(mapper.map_type("bool"), Some("u8"));
108        assert_eq!(mapper.map_type("void"), Some("()"));
109    }
110
111    #[test]
112    fn test_slice_detection() {
113        let mapper = TypeMapper::new();
114
115        assert!(mapper.is_slice_type("[*]const u8"));
116        assert!(mapper.is_slice_type("[*]u8"));
117        assert!(!mapper.is_slice_type("i32"));
118    }
119}