1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
use regex::Regex;

#[derive(Clone, Debug)]
pub enum IceType {
    VoidType,
    BoolType,
    ByteType,
    ShortType,
    IntType,
    LongType,
    FloatType,
    DoubleType,
    StringType,    
    SequenceType(Box<IceType>),
    DictType(Box<IceType>, Box<IceType>),
    Optional(Box<IceType>, u8),
    CustomType(String)
}

impl IceType {
    pub fn from(text: &str) -> Result<IceType, Box<dyn std::error::Error>> {
        let type_re = Regex::new(
            r#"(?x)
            (void) |
            (bool) |
            (byte) |
            (short) |
            (int) |
            (long) |
            (float) |
            (double) |
            (string) |
            (sequence)<(.+)> |
            (dictionary)<(.+),\s*(.+)> |
            "#
        )?; 

        let captures = type_re.captures(text.trim()).map(|captures| {
            captures
                .iter() // All the captured groups
                .skip(1) // Skipping the complete match
                .flat_map(|c| c) // Ignoring all empty optional matches
                .map(|c| c.as_str()) // Grab the original strings
                .collect::<Vec<_>>() // Create a vector
        });

        match captures.as_ref().map(|c| c.as_slice()) {
            Some(["void"]) => Ok(IceType::VoidType),
            Some(["bool"]) => Ok(IceType::BoolType),
            Some(["byte"]) => Ok(IceType::ByteType),
            Some(["short"]) => Ok(IceType::ShortType),
            Some(["int"]) => Ok(IceType::IntType),
            Some(["long"]) => Ok(IceType::LongType),
            Some(["float"]) => Ok(IceType::FloatType),
            Some(["double"]) => Ok(IceType::DoubleType),
            Some(["string"]) => Ok(IceType::StringType),
            Some(["sequence", x]) => {
                Ok(IceType::SequenceType(Box::new(IceType::from(x)?)))
            },
            Some(["dictionary", x, y]) => {
                Ok(IceType::DictType(Box::new(IceType::from(x)?), Box::new(IceType::from(y)?)))
            },
            _ => Ok(IceType::CustomType(text.trim().to_string()))
        }
    }

    pub fn rust_type(&self) -> String {
        match self {
            IceType::VoidType => String::from("()"),
            IceType::BoolType => String::from("bool"),
            IceType::ByteType => String::from("u8"),
            IceType::ShortType => String::from("i16"),
            IceType::IntType => String::from("i32"),
            IceType::LongType => String::from("i64"),
            IceType::FloatType => String::from("f32"),
            IceType::DoubleType => String::from("f64"),
            IceType::StringType => String::from("String"),
            IceType::SequenceType(type_name) => format!("Vec<{}>", type_name.rust_type()),
            IceType::DictType(key_type, value_type) => format!("HashMap<{}, {}>", key_type.rust_type(), value_type.rust_type()),
            IceType::Optional(type_name, _) => format!("Option<{}>", type_name.rust_type()),
            IceType::CustomType(type_name) => format!("{}", type_name),
        }
    }

    pub fn rust_from(&self) -> String {
        match self {
            IceType::Optional(type_name, _) => format!("Option::<{}>", type_name.rust_type()),
            _ => self.rust_type(),
        }
    }

    pub fn as_ref(&self) -> bool {
        match self {
            IceType::StringType |
            IceType::SequenceType(_) |
            IceType::DictType(_, _) |
            IceType::CustomType(_) => true,
            _ => false
        }
    }
}