cainome_parser/tokens/
array.rs

1use super::constants::CAIRO_CORE_SPAN_ARRAY;
2use super::genericity;
3
4use crate::tokens::Token;
5use crate::{CainomeResult, Error};
6
7pub const CAIRO_0_ARRAY: &str = "*";
8
9#[derive(Debug, Clone, PartialEq)]
10pub struct Array {
11    pub type_path: String,
12    pub inner: Box<Token>,
13    pub is_legacy: bool,
14}
15
16impl Array {
17    pub fn parse(type_path: &str) -> CainomeResult<Self> {
18        for a in CAIRO_CORE_SPAN_ARRAY {
19            if type_path.starts_with(a) {
20                let generic_args = genericity::extract_generics_args(type_path)?;
21
22                if generic_args.len() != 1 {
23                    return Err(Error::TokenInitFailed(format!(
24                        "Array/Span are expected exactly one generic argument, found {} in `{}`.",
25                        generic_args.len(),
26                        type_path,
27                    )));
28                }
29
30                let (_, generic_arg_token) = &generic_args[0];
31
32                return Ok(Self {
33                    type_path: type_path.to_string(),
34                    inner: Box::new(generic_arg_token.clone()),
35                    is_legacy: false,
36                });
37            }
38        }
39
40        if let Some(inner_type) = type_path.strip_suffix(CAIRO_0_ARRAY) {
41            return Ok(Self {
42                type_path: type_path.to_string(),
43                inner: Box::new(Token::parse(inner_type)?),
44                is_legacy: true,
45            });
46        }
47
48        Err(Error::TokenInitFailed(format!(
49            "Array/Span couldn't be initialized from `{}`.",
50            type_path,
51        )))
52    }
53
54    pub fn resolve_generic(&self, generic_name: &str, generic_type_path: &str) -> Token {
55        if self.type_path == generic_type_path {
56            Token::GenericArg(generic_name.to_string())
57        } else {
58            Token::Array(Self {
59                type_path: self.type_path.clone(),
60                inner: Box::new(self.inner.resolve_generic(generic_name, generic_type_path)),
61                is_legacy: self.is_legacy,
62            })
63        }
64    }
65
66    pub fn apply_alias(&mut self, type_path: &str, alias: &str) {
67        self.inner.apply_alias(type_path, alias);
68    }
69}
70
71#[cfg(test)]
72mod tests {
73    use super::*;
74    use crate::tokens::*;
75
76    #[test]
77    fn test_parse() {
78        assert_eq!(
79            Array::parse("core::array::Array::<core::felt252>").unwrap(),
80            Array {
81                type_path: "core::array::Array::<core::felt252>".to_string(),
82                inner: Box::new(Token::CoreBasic(CoreBasic {
83                    type_path: "core::felt252".to_string()
84                })),
85                is_legacy: false,
86            }
87        );
88    }
89
90    #[test]
91    fn test_parse_no_inner_invalid() {
92        assert!(Array::parse("core::array::Array").is_err());
93        assert!(Array::parse("core::array::Array<>").is_err());
94    }
95
96    #[test]
97    fn test_parse_wrong_path_invalid() {
98        assert!(Array::parse("array::Array::<core::felt252>").is_err());
99    }
100
101    #[test]
102    fn test_parse_invalid_path_invalid() {
103        assert!(Array::parse("module::module2::array::Array::<core::felt252>").is_err());
104        assert!(Array::parse("module::module2::MyStruct::<core::felt252>").is_err());
105    }
106}