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 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), }
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 if self.peek() == Some('(') {
150 self.bump(); 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 let ident = self.parse_ident()?;
183
184 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 self.consume_ws();
201 if self.peek() == Some('<') {
202 self.bump(); 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 Ok(IntersticeType::Named(ident))
223 }
224}