donet_core/
dcfield.rs

1/*
2    This file is part of Donet.
3
4    Copyright © 2024 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//! Base data model for DC Field elements. Alone, it represents
21//! an attribute of a structure or Distributed Class.
22
23use crate::datagram::datagram::Datagram;
24use crate::dcatomic::DCAtomicField;
25use crate::dckeyword::{DCKeywordList, IdentifyKeyword};
26use crate::dclass::DClass;
27use crate::dcmolecular::DCMolecularField;
28use crate::dconfig::*;
29use crate::dcstruct::DCStruct;
30use crate::dctype::DCTypeDefinition;
31use crate::globals;
32use crate::hashgen::*;
33
34/// Enumerator representing the 3 types of fields that inherit DC Field,
35/// which can legally be declared within a Distributed Class.
36///
37/// Plain DC Fields represent a property, or member, of a structure
38/// or class. DC fields have a data type assigned to them.
39///
40/// DC Atomic Fields represent a method of a Distributed Class, which
41/// is always implemented as a remote procedure call (RPC). Unlike
42/// attribute fields, atomic fields cannot be declared within structs.
43///
44/// DC Molecular Fields represent a collection of one or more
45/// DC Atomic Fields as one field under one identifier. The parameters
46/// of a molecular field are the parameters of all the fields it
47/// represents, joined together in the order in which they were declared
48/// when the molecular field was declared.
49#[derive(Debug)]
50pub enum ClassField<'dc> {
51    Field(DCField<'dc>),
52    Atomic(DCAtomicField<'dc>),
53    Molecular(DCMolecularField<'dc>),
54}
55
56/// A different enumerator representing DC Field types used
57/// for DC Structs, since they cannot contain DC Atomic Fields.
58#[derive(Debug)]
59pub enum StructField<'dc> {
60    Field(DCField<'dc>),
61    Molecular(DCMolecularField<'dc>),
62}
63
64/// A DC field element can be declared within a dclass or a
65/// struct declaration. The DC field element must have a
66/// reference to its parent, which is stored in this enum type.
67#[derive(Debug)]
68pub enum FieldParent<'dc> {
69    DClass(&'dc DClass<'dc>),
70    Strukt(&'dc DCStruct<'dc>), // 'strukt' due to reserved keyword
71}
72
73/// Macro for Panda historical keywords inline functions.
74macro_rules! has_keyword {
75    ($self:ident, $i:literal) => {
76        $self
77            .keyword_list
78            .has_keyword(IdentifyKeyword::ByName($i.to_owned()))
79    };
80}
81
82/// A field of a Distributed Class. The DCField struct is a base for
83/// struct and dclass fields. In the DC language, there are three types
84/// of field declarations, which are: plain fields, atomic, and molecular.
85#[derive(Debug)]
86pub struct DCField<'dc> {
87    keyword_list: DCKeywordList<'dc>,
88    parent_element: FieldParent<'dc>,
89    field_name: String,
90    field_id: globals::FieldId,
91    field_type: Option<DCTypeDefinition>,
92    default_value_stale: bool,
93    has_default_value: bool,
94    default_value: Vec<u8>, // stored as byte array
95    bogus_field: bool,
96}
97
98impl std::fmt::Display for DCField<'_> {
99    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
100        writeln!(f, "TODO")
101    }
102}
103
104impl DCFileConfigAccessor for DCField<'_> {
105    fn get_dc_config(&self) -> &DCFileConfig {
106        match self.parent_element {
107            FieldParent::DClass(dc) => dc.get_dc_config(),
108            FieldParent::Strukt(s) => s.get_dc_config(),
109        }
110    }
111}
112
113impl LegacyDCHash for DCField<'_> {
114    fn generate_hash(&self, hashgen: &mut DCHashGenerator) {
115        self.keyword_list.generate_hash(hashgen);
116        self.field_type.clone().unwrap().generate_hash(hashgen);
117
118        // It shouldn't be necessary to explicitly add the field ID
119        // to the hash--this is computed based on the relative
120        // position of this field with the other fields, so adding it
121        // explicitly will be redundant. However, the field name is
122        // significant.
123        hashgen.add_string(self.field_name.clone());
124
125        // The field ID is added to the hash here, since we need to
126        // ensure the hash code comes out different in the
127        // DC_MULTIPLE_INHERITANCE case.
128        if self.get_dc_config().dc_multiple_inheritance {
129            hashgen.add_int(i32::from(self.field_id));
130        }
131    }
132}
133
134impl<'dc> DCField<'dc> {
135    #[inline(always)]
136    pub fn get_field_id(&self) -> globals::FieldId {
137        self.field_id
138    }
139
140    #[inline(always)]
141    pub fn get_field_name(&self) -> String {
142        self.field_name.clone()
143    }
144
145    /// Gets the parent DClass element reference.
146    ///
147    /// Panics if this field's parent element is not a DClass.
148    pub fn get_dclass(&self) -> &'dc DClass {
149        match self.parent_element {
150            FieldParent::DClass(dclass_ref) => dclass_ref,
151            FieldParent::Strukt(_) => panic!("Field parent is not a DClass."),
152        }
153    }
154
155    #[inline(always)]
156    pub fn set_field_id(&mut self, id: globals::FieldId) {
157        self.field_id = id
158    }
159
160    #[inline(always)]
161    pub fn set_field_name(&mut self, name: String) {
162        self.field_name = name
163    }
164
165    pub fn set_field_type(&mut self, dtype: DCTypeDefinition) {
166        self.field_type = Some(dtype);
167        self.has_default_value = false;
168        self.default_value = vec![];
169    }
170
171    pub fn set_field_keyword_list(&mut self, kw_list: DCKeywordList<'dc>) {
172        self.keyword_list = kw_list;
173    }
174
175    pub fn set_default_value(&mut self, value: Vec<u8>) {
176        self.default_value = value;
177        self.has_default_value = true;
178        self.default_value_stale = false;
179    }
180
181    #[inline(always)]
182    pub fn set_bogus_field(&mut self, is_bogus: bool) {
183        self.bogus_field = is_bogus
184    }
185
186    #[inline(always)]
187    pub fn has_default_value(&self) -> bool {
188        self.has_default_value
189    }
190
191    pub fn validate_ranges(&self, _packed_data: &Datagram) -> bool {
192        todo!()
193    }
194
195    /// Given a blob that represents the packed data for this field, returns a
196    /// string formatting it for human consumption.
197    pub fn format_packed_data(
198        &self,
199        f: &mut std::fmt::Formatter<'_>,
200        _data: &[u8],
201        _show_field_names: bool,
202    ) -> std::fmt::Result {
203        f.write_str("TODO") // TODO
204    }
205
206    #[inline(always)]
207    pub fn is_bogus_field(&self) -> bool {
208        self.bogus_field
209    }
210
211    #[inline(always)]
212    pub fn is_required(&self) -> bool {
213        has_keyword!(self, "required")
214    }
215
216    #[inline(always)]
217    pub fn is_broadcast(&self) -> bool {
218        has_keyword!(self, "broadcast")
219    }
220
221    #[inline(always)]
222    pub fn is_ram(&self) -> bool {
223        has_keyword!(self, "ram")
224    }
225
226    #[inline(always)]
227    pub fn is_db(&self) -> bool {
228        has_keyword!(self, "db")
229    }
230
231    #[inline(always)]
232    pub fn is_clsend(&self) -> bool {
233        has_keyword!(self, "clsend")
234    }
235
236    #[inline(always)]
237    pub fn is_clrecv(&self) -> bool {
238        has_keyword!(self, "clrecv")
239    }
240
241    #[inline(always)]
242    pub fn is_ownsend(&self) -> bool {
243        has_keyword!(self, "ownsend")
244    }
245
246    #[inline(always)]
247    pub fn is_ownrecv(&self) -> bool {
248        has_keyword!(self, "ownrecv")
249    }
250
251    #[inline(always)]
252    pub fn is_airecv(&self) -> bool {
253        has_keyword!(self, "airecv")
254    }
255
256    fn _refresh_default_value(&self) {
257        todo!()
258    }
259}