donet_core/
dctype.rs

1/*
2    This file is part of Donet.
3
4    Copyright © 2024-2025 Max Rodriguez <[email protected]>
5
6    Donet is free software; you can redistribute it and/or modify
7    it under the terms of the GNU Affero General Public License,
8    as published by the Free Software Foundation, either version 3
9    of the License, or (at your option) any later version.
10
11    Donet is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14    GNU Affero General Public License for more details.
15
16    You should have received a copy of the GNU Affero General Public
17    License along with Donet. If not, see <https://www.gnu.org/licenses/>.
18*/
19
20//! Represents all data types supported by the DC language
21//! and developer-defined type alias definitions.
22
23use crate::globals::DgSizeTag;
24use crate::hashgen::*;
25use crate::parser::ast;
26
27/// The DCTypeEnum variants have assigned u8 values
28/// to keep compatibility with Astron's DC hash inputs.
29#[repr(u8)] // 8-bit alignment, unsigned
30#[derive(Debug, Clone, PartialEq, Eq)]
31#[rustfmt::skip]
32pub enum DCTypeEnum {
33    // Numeric Types
34    TInt8 = 0, TInt16 = 1, TInt32 = 2, TInt64 = 3,
35    TUInt8 = 4, TChar = 8, TUInt16 = 5, TUInt32 = 6, TUInt64 = 7,
36    TFloat32 = 9, TFloat64 = 10,
37
38    // Sized Data Types (Array Types)
39    TString = 11, // a string with a fixed byte length
40    TVarString = 12, // a string with a variable byte length
41    TBlob = 13, TVarBlob = 14,
42    TArray = 15, TVarArray = 16,
43
44    // Complex DC Types
45    TStruct = 17, TMethod = 18,
46
47    TInvalid = 19,
48}
49
50impl std::fmt::Display for DCTypeEnum {
51    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52        match self {
53            Self::TInt8 => write!(f, "int8"),
54            Self::TInt16 => write!(f, "int16"),
55            Self::TInt32 => write!(f, "int32"),
56            Self::TInt64 => write!(f, "int64"),
57            Self::TUInt8 => write!(f, "uint8"),
58            Self::TChar => write!(f, "char"),
59            Self::TUInt16 => write!(f, "uint16"),
60            Self::TUInt32 => write!(f, "uint32"),
61            Self::TUInt64 => write!(f, "uint64"),
62            Self::TFloat32 => write!(f, "float32"),
63            Self::TFloat64 => write!(f, "float64"),
64            Self::TString => write!(f, "string"),
65            Self::TBlob => write!(f, "blob"),
66            Self::TArray => write!(f, "array"),
67            Self::TStruct => write!(f, "struct"),
68            _ => Ok(()), // not written
69        }
70    }
71}
72
73impl From<ast::SizedTypeToken> for DCTypeEnum {
74    fn from(value: ast::SizedTypeToken) -> Self {
75        match value {
76            ast::SizedTypeToken::Blob => DCTypeEnum::TBlob,
77            ast::SizedTypeToken::String => DCTypeEnum::TString,
78        }
79    }
80}
81
82#[derive(Debug, Clone, PartialEq, Eq)]
83pub struct DCTypeDefinition {
84    alias: Option<String>,
85    pub data_type: DCTypeEnum,
86    pub size: DgSizeTag,
87}
88
89/// Creates a new DCTypeDefinition struct with a DC type set.
90impl From<DCTypeEnum> for DCTypeDefinition {
91    fn from(value: DCTypeEnum) -> Self {
92        Self {
93            alias: None,
94            data_type: value,
95            size: 0_u16,
96        }
97    }
98}
99
100impl From<ast::TypeDefinition> for DCTypeDefinition {
101    fn from(value: ast::TypeDefinition) -> Self {
102        Self {
103            alias: value.alias_identifier,
104            data_type: match value.data_type {
105                ast::NonMethodDataType::NumericType(a) => a.base_type,
106                ast::NonMethodDataType::StructType(_) => {
107                    // FIXME: Store struct identifier!!
108                    DCTypeEnum::TStruct
109                }
110                ast::NonMethodDataType::TypeWithArray(a) => {
111                    match a.data_type {
112                        ast::ArrayableType::Numeric(a) => a.base_type,
113                        ast::ArrayableType::Struct(_) => {
114                            // FIXME: Store struct identifier!!
115                            DCTypeEnum::TStruct
116                        }
117                        ast::ArrayableType::Sized(a) => a.into(),
118                    }
119                }
120            },
121            size: 0_u16, // FIXME: have no idea what this does in Astron source
122        }
123    }
124}
125
126impl std::fmt::Display for DCTypeDefinition {
127    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
128        write!(f, "typedef ")?;
129        self.data_type.fmt(f)?;
130        if self.has_alias() {
131            write!(f, " ")?;
132            self.alias.clone().unwrap().fmt(f)?;
133        }
134        write!(f, ";")
135    }
136}
137
138impl LegacyDCHash for DCTypeDefinition {
139    fn generate_hash(&self, hashgen: &mut DCHashGenerator) {
140        hashgen.add_int(i32::from(self.data_type.clone() as u8));
141
142        if self.has_alias() {
143            hashgen.add_string(self.alias.clone().unwrap())
144        }
145    }
146}
147
148impl DCTypeDefinition {
149    pub fn get_dc_type(&self) -> DCTypeEnum {
150        self.data_type.clone()
151    }
152
153    #[inline(always)]
154    pub fn is_variable_length(&self) -> bool {
155        self.size == 0_u16
156    }
157
158    #[inline(always)]
159    pub fn get_size(&self) -> DgSizeTag {
160        self.size
161    }
162
163    #[inline(always)]
164    pub fn has_alias(&self) -> bool {
165        self.alias.is_some()
166    }
167
168    pub fn get_alias(&self) -> Result<String, ()> {
169        if self.alias.is_some() {
170            Ok(self.alias.clone().unwrap())
171        } else {
172            Err(())
173        }
174    }
175
176    pub fn set_alias(&mut self, alias: String) {
177        self.alias = Some(alias);
178    }
179}
180
181#[derive(Copy, Clone, PartialEq)] // required for unwrapping when in an option type
182pub enum DCNumber {
183    Integer(i64),
184    UnsignedInteger(u64),
185    FloatingPoint(f64),
186}
187
188impl From<DCNumber> for i32 {
189    fn from(value: DCNumber) -> i32 {
190        match value {
191            DCNumber::Integer(x) => x as i32,
192            DCNumber::UnsignedInteger(x) => x as i32,
193            DCNumber::FloatingPoint(x) => x as i32,
194        }
195    }
196}
197
198/// Converts a `DCNumber` to an `i64` primitive type.
199///
200/// Panics if `DCNumber` is not of variant `Integer`.
201impl From<DCNumber> for i64 {
202    fn from(value: DCNumber) -> Self {
203        match value {
204            DCNumber::Integer(x) => x,
205            _ => panic!("DCNumber is not of variant `Integer`."),
206        }
207    }
208}
209
210/// Converts a `DCNumber` to an `u64` primitive type.
211///
212/// Panics if `DCNumber` is not of variant `UnsignedInteger`.
213impl From<DCNumber> for u64 {
214    fn from(value: DCNumber) -> Self {
215        match value {
216            DCNumber::UnsignedInteger(x) => x,
217            _ => panic!("DCNumber is not of variant `UnsignedInteger`."),
218        }
219    }
220}
221
222/// Converts a `DCNumber` to an `f64` primitive type.
223///
224/// Panics if `DCNumber` is not of variant `FloatingPoint`.
225impl From<DCNumber> for f64 {
226    fn from(value: DCNumber) -> Self {
227        match value {
228            DCNumber::FloatingPoint(x) => x,
229            _ => panic!("DCNumber is not of variant `FloatingPoint`."),
230        }
231    }
232}