interstice_abi/interstice_type/
mod.rs1use 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), }
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 if self.peek() == Some('(') {
148 self.bump(); 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 let ident = self.parse_ident()?;
181
182 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 self.consume_ws();
198 if self.peek() == Some('<') {
199 self.bump(); 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 Ok(IntersticeType::Named(ident))
220 }
221}