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