Skip to main content

interstice_abi/interstice_type/
mod.rs

1use crate::error::IntersticeAbiError;
2use serde::{Deserialize, Serialize};
3use std::{
4    fmt::{Display, Formatter},
5    str::FromStr,
6};
7
8#[derive(Debug, Clone, Deserialize, Serialize)]
9pub enum IntersticeType {
10    Void,
11    U32,
12    U64,
13    I32,
14    I64,
15    F32,
16    F64,
17    Bool,
18    String,
19    Vec(Box<IntersticeType>),
20    Option(Box<IntersticeType>),
21    Tuple(Vec<IntersticeType>),
22    Named(String), // reference to user-defined struct/enum
23}
24
25impl Display for IntersticeType {
26    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
27        match self {
28            IntersticeType::Void => write!(f, "()"),
29            IntersticeType::U32 => write!(f, "u32"),
30            IntersticeType::U64 => write!(f, "u64"),
31            IntersticeType::I32 => write!(f, "i32"),
32            IntersticeType::I64 => write!(f, "i64"),
33            IntersticeType::F32 => write!(f, "f32"),
34            IntersticeType::F64 => write!(f, "f64"),
35            IntersticeType::Bool => write!(f, "bool"),
36            IntersticeType::String => write!(f, "String"),
37
38            IntersticeType::Vec(inner) => write!(f, "Vec<{}>", inner),
39            IntersticeType::Option(inner) => write!(f, "Option<{}>", inner),
40
41            IntersticeType::Tuple(types) => {
42                write!(f, "(")?;
43                for (i, ty) in types.iter().enumerate() {
44                    if i > 0 {
45                        write!(f, ", ")?;
46                    }
47                    write!(f, "{ty}")?;
48                }
49                write!(f, ")")
50            }
51
52            IntersticeType::Named(s) => write!(f, "{s}"),
53        }
54    }
55}
56impl FromStr for IntersticeType {
57    type Err = IntersticeAbiError;
58
59    fn from_str(s: &str) -> Result<Self, Self::Err> {
60        let mut p = Parser::new(s);
61        let ty = p.parse_type()?;
62        p.consume_ws();
63        if !p.is_eof() {
64            return Err(IntersticeAbiError::ConversionError(format!(
65                "Unexpected trailing input: '{}'",
66                p.rest()
67            )));
68        }
69        Ok(ty)
70    }
71}
72
73struct Parser<'a> {
74    input: &'a str,
75    pos: usize,
76}
77
78impl<'a> Parser<'a> {
79    fn new(input: &'a str) -> Self {
80        Self { input, pos: 0 }
81    }
82
83    fn rest(&self) -> &str {
84        &self.input[self.pos..]
85    }
86
87    fn is_eof(&self) -> bool {
88        self.pos >= self.input.len()
89    }
90
91    fn peek(&self) -> Option<char> {
92        self.rest().chars().next()
93    }
94
95    fn bump(&mut self) {
96        if let Some(c) = self.peek() {
97            self.pos += c.len_utf8();
98        }
99    }
100
101    fn consume_ws(&mut self) {
102        while matches!(self.peek(), Some(c) if c.is_whitespace()) {
103            self.bump();
104        }
105    }
106
107    fn eat(&mut self, ch: char) -> Result<(), IntersticeAbiError> {
108        self.consume_ws();
109        match self.peek() {
110            Some(c) if c == ch => {
111                self.bump();
112                Ok(())
113            }
114            _ => Err(IntersticeAbiError::ConversionError(format!(
115                "Expected '{}' at '{}'",
116                ch,
117                self.rest()
118            ))),
119        }
120    }
121
122    fn parse_ident(&mut self) -> Result<String, IntersticeAbiError> {
123        self.consume_ws();
124        let mut len = 0;
125        for c in self.rest().chars() {
126            if c.is_alphanumeric() || c == '_' {
127                len += c.len_utf8();
128            } else {
129                break;
130            }
131        }
132        if len == 0 {
133            return Err(IntersticeAbiError::ConversionError(format!(
134                "Expected identifier at '{}'",
135                self.rest()
136            )));
137        }
138        let ident = self.rest()[..len].to_string();
139        self.pos += len;
140        Ok(ident)
141    }
142
143    fn parse_type(&mut self) -> Result<IntersticeType, IntersticeAbiError> {
144        self.consume_ws();
145
146        // ---- Tuple or unit ----
147        if self.peek() == Some('(') {
148            self.bump(); // '('
149            self.consume_ws();
150
151            if self.peek() == Some(')') {
152                self.bump();
153                return Ok(IntersticeType::Void);
154            }
155
156            let mut elems = Vec::new();
157            loop {
158                elems.push(self.parse_type()?);
159                self.consume_ws();
160                match self.peek() {
161                    Some(',') => {
162                        self.bump();
163                    }
164                    Some(')') => {
165                        self.bump();
166                        break;
167                    }
168                    _ => {
169                        return Err(IntersticeAbiError::ConversionError(format!(
170                            "Expected ',' or ')' in tuple at '{}'",
171                            self.rest()
172                        )));
173                    }
174                }
175            }
176            return Ok(IntersticeType::Tuple(elems));
177        }
178
179        // ---- Identifier ----
180        let ident = self.parse_ident()?;
181
182        // ---- Primitives ----
183        let primitive = match ident.as_str() {
184            "u32" => Some(IntersticeType::U32),
185            "u64" => Some(IntersticeType::U64),
186            "i32" => Some(IntersticeType::I32),
187            "i64" => Some(IntersticeType::I64),
188            "f32" => Some(IntersticeType::F32),
189            "f64" => Some(IntersticeType::F64),
190            "bool" => Some(IntersticeType::Bool),
191            "String" => Some(IntersticeType::String),
192            "Vec" | "Option" => None,
193            _ => None,
194        };
195
196        // ---- Generics like Vec<T> / Option<T> ----
197        self.consume_ws();
198        if self.peek() == Some('<') {
199            self.bump(); // '<'
200            let inner = self.parse_type()?;
201            self.consume_ws();
202            self.eat('>')?;
203
204            return match ident.as_str() {
205                "Vec" => Ok(IntersticeType::Vec(Box::new(inner))),
206                "Option" => Ok(IntersticeType::Option(Box::new(inner))),
207                _ => Err(IntersticeAbiError::ConversionError(format!(
208                    "Unknown generic type '{}'",
209                    ident
210                ))),
211            };
212        }
213
214        if let Some(p) = primitive {
215            return Ok(p);
216        }
217
218        // ---- Named user type ----
219        Ok(IntersticeType::Named(ident))
220    }
221}