shm_rs/static_scheme/
scheme.rs

1/*-
2 * shm-rs - a scheme serialization lib
3 * Copyright (C) 2021  Aleksandr Morozov
4 * 
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 *  file, You can obtain one at https://mozilla.org/MPL/2.0/.
8 */
9
10use std::borrow::Borrow;
11use std::sync::Arc;
12use std::fmt;
13use std::path::PathBuf;
14use indexmap::IndexSet;
15use linked_hash_map::LinkedHashMap;
16use std::collections::{HashSet, HashMap};
17use std::collections::hash_map;
18use std::cell::Cell;
19use std::hash::{Hash, Hasher};
20
21use serde::{Serialize, Deserialize};
22
23use crate::common::{self, some_kind_of_lowercase_first_letter, prepare_enum_variant};
24use crate::lexer::lexer_node::{NodeInteger, NodeLongInteger};
25use crate::serializator::serializator::*;
26use crate::static_scheme::generator::RustCodeEnumType;
27use crate::LexerInfo;
28
29use super::error::{self, StaticSchemeRes};
30use super::generator::{RustCode, RustCodeDefineType, RustCodeFields, RustCodeItem, RustCodeItemDataType, RustCodeItemStruct};
31
32bitflags! {
33    /// Flags  which  control  the  operation  of openlog() and 
34    /// subsequent calls to syslog.
35    #[derive(Copy, Clone, Debug, Serialize, Deserialize)]
36    pub struct ProcFlags: u64
37    {
38        /// Allow the Procedure to be optional (args can not be optional)
39        const FLAG_OPTIONAL = 1;
40
41        /// Allow the procedure to be repeated (args can not be repeated)
42        const FLAG_COLLECTION = 2;
43    }
44}
45
46
47
48/// Defines a type of the (f/vector) field. Used by the `generator.rs`
49/// in order to generate Rust structs and enums fields.
50#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
51pub enum VectorSerializType
52{
53    /// Generate field type as [Vec]
54    Array, 
55    /// Generate field type as [HashSet]
56    Hashset,
57    /// Generate field type as [IndexSet]
58    Indexset
59}
60
61/// An argument data type.
62#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
63pub enum ArgDataType
64{
65    None,
66    Symbol,
67    String,
68    Int,
69    UInt,
70    LongInt,
71    LongUint,
72    Boolean,
73    Vector,
74    Range,
75    RangeInc,
76    Variable,
77    Entity,
78    Enumerator,
79    AutoType
80}
81
82impl Default for ArgDataType
83{
84    fn default() -> Self 
85    {
86        return Self::None;
87    }
88}
89
90impl ArgDataType
91{
92    /// Returns true if the datatype requires an inner type (type of collected args)
93    pub fn has_subtype(&self) -> bool
94    {
95        return 
96            *self == Self::Vector || *self == Self::Range || 
97            *self == Self::RangeInc || *self == Self::Symbol;
98    }
99}
100
101impl fmt::Display for ArgDataType 
102{
103    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result 
104    {
105        match *self 
106        {
107            Self::None => write!(f, "Not Defined"),
108            Self::Symbol => write!(f, "Symbol"),
109            Self::String => write!(f, "String"),
110            Self::Int => write!(f, "Int"),
111            Self::UInt => write!(f, "Uint"),
112            Self::LongInt => write!(f, "LongInt"),
113            Self::LongUint => write!(f, "LongUint"),
114            Self::Boolean => write!(f, "Boolean"),
115            Self::Vector => write!(f, "Vector"),
116            Self::Range => write!(f, "Range"),
117            Self::RangeInc => write!(f, "RangeInc"),
118            Self::Variable => write!(f, "Variable"),
119            Self::Entity => write!(f, "Entity"),
120            Self::Enumerator => write!(f, "Enumerator"),
121            Self::AutoType => write!(f, "Auto-type"),
122        }
123    }
124}
125
126/// A generic data type for dynamic scheme.
127#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
128pub enum GenericDataTypes
129{
130    None,
131    Symbol(Box<GenericDataTypes>, LexerInfo),
132    String(String, LexerInfo),
133    Int(NodeInteger, LexerInfo),
134    LongInt(NodeLongInteger, LexerInfo),
135    Boolean(bool, LexerInfo),
136    Variable(String, LexerInfo), // ext
137    Entity(String, LexerInfo), // ext
138    Enumerator(String, String, LexerInfo),
139    Vector(Vec<GenericDataTypes>, LexerInfo),
140    Range(Box<GenericDataTypes>, Box<GenericDataTypes>, LexerInfo),
141    RangeIncl(Box<GenericDataTypes>, Box<GenericDataTypes>, LexerInfo),
142    AnyValWrap(Box<GenericDataTypes>, LexerInfo)
143}
144
145impl Default for GenericDataTypes
146{
147    fn default() -> Self 
148    {
149        return Self::None;
150    }
151}
152
153impl fmt::Display for GenericDataTypes 
154{
155    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result 
156    {
157        match *self 
158        {
159            Self::None => 
160                write!(f, "None"),
161            Self::Symbol(ref r, ref li) => 
162                write!(f, "Symbol({}: {})", r, li),
163            Self::String(ref r, ref li) => 
164                write!(f, "String({}: {})", r, li),
165            Self::Int(ref r, ref li) => 
166                write!(f, "Int({}: {})", r, li),
167            Self::LongInt(ref r, ref li) => 
168                write!(f, "LongInt({}: {})", r, li),
169            Self::Boolean(ref r, ref li) => 
170                write!(f, "Boolean({}: {})", r, li),
171            Self::Vector(ref r, ref _li) => 
172            {
173                write!(f, "Vector(")?;
174                for i in r.iter()
175                {
176                    write!(f, "{}", i)?;
177                }
178                write!(f, ")")
179            },
180            Self::Range(ref l, ref r, ref li) =>
181                write!(f, "Range({}..{}): {}", l, r, li),
182            Self::RangeIncl(ref l, ref r, ref li) =>
183                write!(f, "RangeIncl({}..={}): {}", l, r, li),
184            Self::Variable(ref var, ref li) => 
185                write!(f, "Variable(${}): '{}'", var, li),
186            Self::Entity(ref ent, ref li) => 
187                write!(f, "Entity(@{}): '{}'", ent, li),
188            Self::Enumerator(ref enum_name, ref enum_item, ref li) => 
189                write!(f, "Enumerator({}::{}): '{}'", enum_name, enum_item, li),
190            Self::AnyValWrap(ref anyval, ref li) =>
191                write!(f, "AnyValue({}): '{}'", anyval, li),
192        }
193    }
194}
195
196#[derive(Clone, Copy, Debug, PartialEq, Eq)]
197pub enum PathResolve
198{
199    Proc, 
200    Struct,
201}
202
203/// This struct contains information about the [Serializator] instance
204/// which is defined in scheme and starting with (serialization "name" ...).
205#[derive(Debug, Serialize, Deserialize)]
206pub struct Serializator
207{
208    /// Title of the serializator
209    name: Arc<String>, 
210
211    /// The document root
212    root_proc: Option<Arc<Procedure>>,
213
214    /// All declared procedures
215    procedures: HashMap<Arc<String>, Arc<Procedure>>,
216
217    /// All declared Defines
218    defines: HashMap<Arc<String>, Arc<Define>>,
219
220    /// All declared enums
221    enum_defines: HashMap<Arc<String>, Arc<DefineEnum>>,
222
223    /// A root structure of serializer
224    root_ser_structure: Option<Arc<Structure>>,
225
226    /// All enumerators serialization data
227    enumeratos: Vec<Arc<Enumerator>>,
228
229    /// All structures serialization data
230    structs: Vec<Arc<Structure>>,
231
232    /// A path to file which was used to generate this instance
233    file_path: Option<PathBuf>,
234}
235
236impl fmt::Display for Serializator
237{
238    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
239    {
240        write!(f, "{}", self.name)
241    }
242}
243
244/// A dummy clone. This instance must never be clonned.
245impl Clone for Serializator 
246{
247    fn clone(&self) -> Self 
248    {
249        panic!("Asserion trap: Serializator must never be cloned! \
250                Implementation Clone for Serializator is used to comply \
251                with compilter requirments.");
252        /*return Self 
253            {
254                name: self.name.clone(), 
255                root_proc: None, 
256                procedures: HashMap::new(), 
257                defines: HashMap::new(),
258                root_ser_structure: None,    
259                enumeratos: Vec::new(),
260                structs: Vec::new(),
261            };*/
262    }
263}
264
265impl Serializator
266{
267    /// Returned instead of path when path is None
268    pub const SERIALIZATOR_FROM_MEMORY_PATH: &'static str = "from memory";
269
270    /// Creates new instance of serializator and sets the `name` 
271    /// provided in the scheme.
272    pub 
273    fn new(name: String) -> Self
274    {
275        return 
276            Self 
277            {
278                name: Arc::new(name), 
279                root_proc: None, 
280                procedures: HashMap::new(), 
281                defines: HashMap::new(),
282                enum_defines: HashMap::new(),
283                root_ser_structure: None,
284                enumeratos: Vec::new(),
285                structs: Vec::new(),
286                file_path: None,
287            };
288    }
289
290    /// Sets to the created instance a path to the file which was used to 
291    /// generate current instance.
292    pub 
293    fn set_file_path(&mut self, file_path: Option<PathBuf>)
294    {
295        self.file_path = file_path;
296    }
297
298    /// Returns a reference to [PathBuf] inside [Option]. It contains the path to the
299    /// file which was used to build the instance.
300    pub 
301    fn get_file_path(&self) -> Option<&PathBuf>
302    {
303        return self.file_path.as_ref();
304    }
305
306    /// Returns a path or constant SERIALIZATOR_FROM_MEMORY_PATH if
307    /// it was generated from memory.
308    pub 
309    fn get_file_path_string_safe(&self) -> String
310    {
311        return 
312            self
313                .file_path
314                .as_ref()
315                .map_or(
316                    Self::SERIALIZATOR_FROM_MEMORY_PATH.to_string(), 
317                    |s| s.display().to_string()
318                );
319    }
320
321    /// Returns a list of references to the [Define] instance by the defined parameters.
322    /// 
323    /// The [Define] instance is defined to be used in `proc_name` procedure and contain
324    /// data with the exact `arg_dt` data type.
325    /// 
326    /// # Arguments
327    /// 
328    /// * `proc_name` - a name of the procedure.
329    /// 
330    /// * `arg_dt` - a [ArgDataType] data type.
331    /// 
332    /// # Return
333    /// 
334    /// A [Vec] of [Rc][Define] items is returned.
335    pub 
336    fn get_defines_by_proc_dt(&self, proc_name: &String, arg_dt: ArgDataType) -> Vec<Arc<Define>>
337    {
338        let mut defs: Vec<Arc<Define>> = Vec::new();
339
340        for (_defn, defk) in self.defines.iter()
341        {
342            if defk.is_in_proc_scope(proc_name) == true && defk.get_datatype() == arg_dt
343            {
344                defs.push(defk.clone());
345            }
346        }
347
348        return defs;
349    }
350
351    pub 
352    fn resolve_path_to(&self, source: Arc<Procedure>, path_to_label: &[String], 
353        full_path_to_lbl: &[String], is_enum: bool, path_last_len: usize) -> Result<(Arc<Procedure>, Arc<ForegnProc>), String>
354    {
355        // current path item
356        let p = &path_to_label[0];
357
358        // get the [ForegnProc] by the path item
359        match source.procs.get(p)
360        {
361            Some(r) => 
362            {
363                // if this is last item, then search for the serialization description
364                if is_enum == true && path_to_label.len() == 1
365                {
366                    return Ok((source.clone(), r.clone()));
367                }
368
369                // structs must not have more than one `procedure` defined
370                // in (proc) of `procedure`
371                if r.foregn_names.len() > 1
372                {
373                    return Err(
374                        format!("found item at: '{}', full path: '{}' is not a structure because allows \
375                            more than one variant: '{}'", p, error::convert_list(full_path_to_lbl), 
376                            error::convert_hashset(&r.foregn_names, " "))
377                    );
378                }
379
380                // convert to list (to extract) item
381                let foregn_names: Vec<String> = 
382                    r.foregn_names.iter().map(|f| f.clone()).collect();
383
384                // get [Procedure] from list by foreign_name
385                // (resolving ForegnProc)
386                let proc = 
387                    self
388                        .procedures
389                        .get(&foregn_names[0])
390                        .ok_or_else(|| 
391                            format!("procedure named: '{}', label path: '{}' does not exist in list of \
392                                procedures", &foregn_names[0], error::convert_list(full_path_to_lbl))
393                        )?
394                        .clone();
395
396                // if not last item in the path then repeat operation
397                if path_to_label.len() > path_last_len || is_enum == true
398                {
399                    return self.resolve_path_to(proc, &path_to_label[1..], full_path_to_lbl, is_enum, path_last_len);
400                }
401                else
402                {
403                    return Ok((proc, r.clone()));
404                }  
405            }
406            None => 
407            {
408                // procedure was not found in current `source`.
409                return Err(
410                    format!("path label not found: '{}', on chain: '{}', procedure \
411                        endpoint: '{}' for structure", p, error::convert_list(full_path_to_lbl), source.get_name())
412                );
413            },
414        }
415    }
416
417
418    /// Searches for a [Structure] (and [Procedure]) from the point specified by
419    /// argument `source` which is [Procedure]. 
420    /// 
421    /// This function is recursive!
422    /// 
423    /// # Arguments
424    /// 
425    /// * `source` - a point from where the item from argument `path_to_label`
426    ///     is resolved.
427    /// 
428    /// * `path_to_label` - a path (by labels) to the target.
429    /// 
430    /// # Returns
431    /// 
432    /// Returns a [SchemeResult] where:
433    /// * On success returns [Result::Ok] with reference to [Structure] and [Rc]
434    ///  to [Procedure]
435    /// 
436    /// * On error, returns [Result::Err] with error description. 
437    pub 
438    fn resolve_path_to_struct(
439        &self, 
440        source: Arc<Procedure>, 
441        path_to_label: &[String],
442        full_path_to_lbl: &[String],
443    ) -> Result<(Arc<Structure>,Arc<Procedure>), String>
444    {
445        let (proc, _) = self.resolve_path_to(source, path_to_label, full_path_to_lbl, false, 1)?;
446
447        // return the tuple with struct info and Procedure
448        return Ok(
449            (self.get_serialization_struct_by_procname(proc.get_name())?, proc)
450        );
451    }
452
453    /// Searches for the [Procedure] instance. A starting point is
454    ///  `source`. A path is `full_path_to_lbl`. `path_to_label` is 
455    ///  a recursivly modified list from where on each recursion
456    ///  an item is removed.
457    /// 
458    /// # Returns
459    /// 
460    /// An optional reference to [Structure] is returned in case if
461    ///  procedure is defined with structure.
462    pub 
463    fn resolve_path_to_proc(
464        &self, 
465        source:Arc<Procedure>, 
466        path_to_label: &[String],
467        full_path_to_lbl: &[String],
468    ) -> Result<(Option<Arc<Structure>>,Arc<Procedure>), String>
469    {
470        let (proc, _) = self.resolve_path_to(source, path_to_label, full_path_to_lbl, false, 1)?;
471                   
472        // return the tuple with struct info and Procedure
473        return Ok(
474            (self.get_serialization_struct_by_procname_opt(proc.get_name()), proc)
475        );
476    }
477
478    /// Searches for a [Enumerator] (and [Procedure]) from the point specified by
479    /// argument `source` which is [Procedure]. 
480    /// 
481    /// This function is recursive!
482    /// 
483    /// # Arguments
484    /// 
485    /// * `source` - a point from where the item from argument `path_to_label`
486    ///     is resolved.
487    /// 
488    /// * `path_to_label` - a path (by labels) to the target.
489    /// 
490    /// # Returns
491    /// 
492    /// Returns a [SchemeResult] where:
493    /// * On success returns [Result::Ok] with reference to [Enumerator] and [Rc]
494    ///  to [Procedure]
495    /// 
496    /// * On error, returns [Result::Err] with error description. 
497    pub 
498    fn resolve_path_to_enum(
499        &self, 
500        source:Arc<Procedure>, 
501        path_to_label: &[String],
502        full_path_to_lbl: &[String],
503    ) -> Result<(Arc<Enumerator>,Arc<Procedure>), String>
504    {
505        let (proc, forn_proc) = self.resolve_path_to(source, path_to_label, full_path_to_lbl, true, 1)?;
506
507        let enumer = self.find_enum_by_procs(&forn_proc)?;
508
509        return Ok((enumer, proc));
510    }
511
512    /// Searches for the enumerator serialization description by the 
513    /// [ForegnProc] `foreign_proc` names. Each serialization description
514    /// of enums serializes only specified procedures. Also those procedures
515    /// are specified in `(proc)` of the `(procedure)` which is a [ForegnProc].
516    /// So, the procedures specified in `(proc)` must match what is serialized
517    /// by the enum serialization description.
518    /// 
519    /// # Arguments
520    /// 
521    /// * `foreign_proc` - a reference to the [ForegnProc] which is paired to 
522    ///     enum serialization description [Enumerator]
523    /// 
524    /// # Returns
525    /// 
526    /// A function returns [SchemeResult] with the following inner types:
527    /// 
528    /// * [Result::Ok] - with the reference to [Enumerator] if found
529    /// 
530    /// * [Result::Err] - with error description. 
531    fn find_enum_by_procs(&self, foreign_proc: &ForegnProc) -> Result<Arc<Enumerator>, String>
532    {
533        let mut cnt: usize = 0;
534        let mut last_found: Option<Arc<Enumerator>> = None;
535
536        'ext: for enm_itm in self.enumeratos.iter()
537        {
538            let map: HashSet<String> = 
539                enm_itm
540                    .get_enum_procs_list()
541                    .iter()
542                    .map(|p| p.clone())
543                    .collect();
544
545            for for_proc_name in foreign_proc.foregn_names.iter()
546            {
547                if map.contains(for_proc_name) == false
548                {
549                    cnt = 0;
550                    continue 'ext;
551                }
552
553                cnt += 1;
554            }
555
556            if cnt == map.len()
557            {
558                return Ok(enm_itm.clone());
559            }
560            else
561            {
562                cnt = 0;
563
564                match last_found
565                {
566                    Some(ref r) => 
567                    {
568                        if r.get_enum_procs_list().len() > map.len()
569                        {
570                            last_found = Some(enm_itm.clone());
571                        }
572                    },
573                    None => 
574                    {
575                        last_found = Some(enm_itm.clone());
576                    }
577                }
578            }
579        }
580
581        if let Some(r) = last_found
582        {
583            return Ok(r);
584        }
585        else
586        {
587            return Err(
588                format!("can not find enum which serializes: '{}'", 
589                    error::convert_hashset(&foreign_proc.foregn_names, " "))
590            );
591        }  
592    }
593
594    
595
596    /// Searches for a [Argument] from the point specified by
597    /// argument `source` which is [Procedure]. 
598    /// 
599    /// This function is recursive!
600    /// 
601    /// # Arguments
602    /// 
603    /// * `source` - a point from where the item from argument `path_to_label`
604    ///     is resolved.
605    /// 
606    /// * `path_to_label` - a path (by labels) to the target.
607    /// 
608    /// # Returns
609    /// 
610    /// Returns a [SchemeResult] where:
611    /// * On success returns [Result::Ok] with reference to [Rc] [Argument] 
612    /// 
613    /// * On error, returns [Result::Err] with error description. 
614    pub 
615    fn resolve_path_to_arg(
616        &self, 
617        source:Arc<Procedure>, 
618        path_to_label: &[String],
619        full_path_to_lbl: &[String]
620    ) -> Result<Arc<Argument>, String>
621    {
622        // current path item
623        let p = &path_to_label[0];
624
625        let (proc, _) = 
626            self.resolve_path_to(source, path_to_label, full_path_to_lbl, false, 2)?;
627
628        let p = path_to_label.last().unwrap();
629        
630        let arg = 
631            proc
632                .args
633                .get(p)
634                .ok_or_else(|| 
635                    format!("argument labeled as: '{}' was not found on path: '{}'", 
636                        p, error::convert_list(full_path_to_lbl))
637                )?
638                .clone();
639
640
641        return Ok(arg);
642    }
643
644    /// Generates a Rust code (structures and enums) from the root of the document.
645    /// 
646    /// # Arguments
647    /// 
648    /// * `rust_code` - a mutable reference to [RustCode] instance which is used to 
649    ///     collect result.
650    /// 
651    /// # Returns 
652    /// 
653    /// A [SchemeResult] is returned.
654    /// 
655    /// * [Result::Ok] - if operation is successful.
656    /// 
657    /// * [Result::Err] - if operation has failed and error is returned.
658    pub 
659    fn generate_rust_code(&self, rust_code: &mut RustCode) -> Result<(), String>
660    {
661        // generate all enums for arguments first
662        for (_, de) in self.enum_defines.iter()
663        {
664            let items: Vec<RustCodeEnumType> = 
665                de
666                    .enum_defs
667                    .iter()
668                    .map(|itm| {
669                            RustCodeEnumType::Empty(prepare_enum_variant(itm.as_str()), None)
670                        }
671                    )
672                    .collect();
673        
674            rust_code
675                .add_item(
676                    RustCodeItem
677                        ::new_enum_arg(de.get_enum_name().as_str(), de.get_rust_code_gen(), items)
678                );
679        }
680
681        // generate all symbols as static definitions
682        for (_, de) in self.defines.iter()
683        {
684            let def = 
685                RustCodeDefineType::make_from(de.get_datatype(), de.get_data())?;
686            
687            rust_code.add_item(RustCodeItem::new_define(de.get_name().as_str(), def, de.comment.clone()));
688        }
689
690        // current (root) serialization structure
691        let cur_set_int = 
692            self
693                .get_root_ser()
694                .ok_or_else(|| 
695                    format!( 
696                        "in file: '{}', root serialization is empty, nothing to do in '{}'", 
697                            self.get_file_path_string_safe(),self.get_name()
698                    )
699                )?;
700
701                // current (root) procedure
702        let cur_proc_int = 
703            self
704                .get_root_proc()
705                .ok_or_else(|| 
706                    format!( 
707                        "in file: '{}', root procedure is empty, nothing to do in '{}'", 
708                            self.get_file_path_string_safe(),self.get_name()
709                    )
710                )?;
711
712        // calling generator
713        self
714            .generate_rust_struct(rust_code, cur_set_int.clone(), cur_proc_int, true)
715            .map_err(|e| 
716                format!("generating Rust formatted structs failed: {}", e)
717            )?;
718
719        return Ok(());
720    }
721
722    /// Builds a structure from provided arguments. 
723    /// 
724    /// This function is recursive.
725    /// 
726    /// # Arguments
727    /// 
728    /// * `rust_code` - a mutable reference to [RustCode] instance which
729    ///     is used to build code.
730    /// 
731    /// * `cur_set_int` - a reference to [Structure] which describes the 
732    ///     serialization of the [Procedure] provided in arg `cur_proc_int`.
733    /// 
734    /// * `cur_proc_int` - a [Rc] to [Procedure] which describes how to 
735    ///     read the config and which has a [Structure] description which
736    ///     is passed in arg `cur_set_int`.
737    /// 
738    /// # Returns
739    /// 
740    /// A [SchemeResult] is returned.
741    /// 
742    /// * [Result::Ok] - if operation is successful.
743    /// 
744    /// * [Result::Err] - if operation has failed and error is returned.
745    fn generate_rust_struct(
746        &self, 
747        rust_code: &mut RustCode,
748        cur_set_int: Arc<Structure>, 
749        cur_proc_int: Arc<Procedure>,
750        is_root: bool,
751    ) -> Result<(), String>
752    {
753        let mut fields: Vec<RustCodeItemStruct> = Vec::with_capacity(cur_set_int.get_fields_len());
754
755        let field_first = 
756            match cur_set_int.get_first_field()
757            {
758                Some(fdecl) => 
759                {
760                    fdecl.get_data_type() == &FieldTypes::Enum && fdecl.get_field_name().is_none() == true
761                },
762                None => false
763            };
764
765        if is_root == true && 
766            cur_set_int.get_fields_len() == 1 && 
767            field_first == true
768        {
769            let field = cur_set_int.get_first_field().unwrap();
770
771            // assertion check
772            if field.is_optional() == true
773            {
774                return Err(
775                    format!("(root) procedure: '{}', field path: '{}' is 'optional', but anonymous \
776                        field can not be optional in this case", cur_proc_int.get_name(), 
777                        error::convert_list(field.get_path_to_label()))
778                );
779            }
780
781            // don't create root structure, create an enum with the title
782
783            let _ = 
784                self
785                    .generate_field(rust_code, field, cur_proc_int.clone(), None)
786                    .map_err(|e| 
787                        format!("{} procedure: '{}', path to label: '{}'", e, cur_proc_int.get_name(), 
788                            error::convert_list(field.get_path_to_label()))
789                    )?;
790            
791        }
792        else
793        {
794            // list all fields
795            for root_field in cur_set_int.get_fields_iter()
796            {
797                let field = 
798                    self
799                        .generate_field(rust_code, root_field, cur_proc_int.clone(), None)
800                        .map_err(|e| 
801                            format!("{} procedure: '{}', path to label: '{}'", e, cur_proc_int.get_name(), 
802                                error::convert_list(root_field.get_path_to_label()))
803                        )?;
804
805                fields.push(field);
806            }
807
808            let rci = 
809                RustCodeItem::new_struct(
810                    cur_set_int.as_ref(),
811                    fields, 
812                    is_root,
813                );
814            
815            rust_code.add_item(rci);
816        }
817
818        return Ok(());
819    }
820
821    /// Generates a field's (Rust) datatype.
822    /// 
823    /// # Arguments
824    /// 
825    /// * `rust_code` - a mutable reference to [RustCode] instance which
826    ///     is used to build code.
827    /// 
828    /// * `field` - a reference to [FieldDecl] with the field description
829    ///     from serialization information.
830    /// 
831    /// * `cur_proc_int` - a related [Procedure] to the serialized data.
832    /// 
833    /// # Returns
834    /// 
835    /// A [SchemeResult] is returned.
836    /// 
837    /// * [Result::Ok] with the [RustCodeItemDataType] as inner type which 
838    ///     contains a field data type information.
839    /// 
840    /// * [Result::Err] with error description.
841    pub 
842    fn generate_field_data_type(
843        &self, 
844        rust_code: &mut RustCode, 
845        field: &FieldDecl, 
846        cur_proc_int:Arc<Procedure>,
847        cur_enumer: Option<Arc<Enumerator>>
848    ) -> Result<RustCodeItemDataType, String>
849    {
850        let field_datatype = 
851            match field.get_data_type()
852            {
853                FieldTypes::String => 
854                    RustCodeItemDataType::String,
855                FieldTypes::Boolean => 
856                    RustCodeItemDataType::Bool,
857                FieldTypes::Int => 
858                    RustCodeItemDataType::Int(field.get_int_width()),
859                FieldTypes::UInt => 
860                    RustCodeItemDataType::Uint(field.get_int_width()),
861                FieldTypes::LongInt =>
862                    RustCodeItemDataType::Int(field.get_int_width()),
863                FieldTypes::LongUInt =>
864                    RustCodeItemDataType::Uint(field.get_int_width()),
865                FieldTypes::AnyType => 
866                {
867                    /*let foreign_arg = 
868                        self.resolve_path_to_arg(cur_proc_int.clone(), field.get_path_to_label(), 
869                            field.get_path_to_label())?;
870
871                    let int_width = 
872                        match foreign_arg.get_collection_type()
873                        {
874                            ArgDataType::UInt => field.get_int_width(),
875                            ArgDataType::Int => field.get_int_width(),
876                            _ => 
877                                static_throw_text!("unexpected inner type for <anytype>, type: '{}'", 
878                                    foreign_arg.get_collection_type())
879                        };*/
880
881                    rust_code.set_field_any(8);
882
883                    RustCodeItemDataType::AnyType
884                }, 
885                FieldTypes::Range => 
886                {
887                    let foreign_arg = 
888                        self.resolve_path_to_arg(cur_proc_int.clone(), field.get_path_to_label(), 
889                            field.get_path_to_label())?;
890
891                        
892                    let sd_type = 
893                        match foreign_arg.get_collection_type()
894                        {
895                            ArgDataType::UInt => 
896                                RustCodeItemDataType::Uint(field.get_int_width()),
897                            ArgDataType::Int => 
898                                RustCodeItemDataType::Int(field.get_int_width()),
899                            _ => 
900                                return Err(
901                                    format!("unexpected inner type for <range>, type: '{}'", 
902                                        foreign_arg.get_collection_type())
903                                )
904                        };
905
906                    RustCodeItemDataType::Range(Box::new(sd_type))
907                },
908                FieldTypes::RangeInc =>
909                {
910                    let foreign_arg = 
911                        self.resolve_path_to_arg(cur_proc_int.clone(), field.get_path_to_label(), 
912                            field.get_path_to_label())?;
913
914                    let sd_type = 
915                        match foreign_arg.get_collection_type()
916                        {
917                            ArgDataType::UInt => 
918                                RustCodeItemDataType::Uint(field.get_int_width()),
919                            ArgDataType::Int => 
920                                RustCodeItemDataType::Int(field.get_int_width()),
921                            _ => 
922                                return Err(
923                                    format!("unexpected inner type for <rangeinc>, type: '{}'", 
924                                        foreign_arg.get_collection_type())
925                                )
926                        };
927
928                    RustCodeItemDataType::RangeInclusive(Box::new(sd_type))
929                },
930                FieldTypes::Struct =>
931                {
932                    let (foregn_struct, foregn_proc) = 
933                        self.resolve_path_to_struct(cur_proc_int.clone(), field.get_path_to_label(), 
934                            field.get_path_to_label())?;
935                    
936                    self.generate_rust_struct(
937                        rust_code, 
938                        foregn_struct.clone(), 
939                        foregn_proc, 
940                        false
941                    )?;
942
943                    RustCodeItemDataType::Struct(foregn_struct.get_struct_name().get_name_1().to_string())
944                },
945                FieldTypes::Vector =>
946                {
947                    let inner_type = 
948                        match field.get_data_inner_type(1)
949                        {
950                            FieldTypes::AnyType =>
951                            {
952                                rust_code.set_field_any(8);
953
954                                RustCodeItemDataType::AnyType
955                            },
956                            FieldTypes::Struct =>
957                            {
958                                let (foregn_struct, foregn_proc) = 
959                                    self.resolve_path_to_struct(cur_proc_int.clone(), field.get_path_to_label(), 
960                                        field.get_path_to_label())?;
961
962                                self.generate_rust_struct(rust_code, foregn_struct.clone(), 
963                                    foregn_proc, false)?;
964
965                                RustCodeItemDataType::Struct(foregn_struct.get_struct_name().get_name_1().to_string())
966                            },
967                            FieldTypes::ArgEnum =>
968                            {
969                                let foreign_arg = 
970                                    self.resolve_path_to_arg(cur_proc_int.clone(), field.get_path_to_label(), 
971                                        field.get_path_to_label())?;
972
973                                    
974                                if *foreign_arg.get_data_type() == ArgDataType::Enumerator
975                                {
976                                    return Err(
977                                        format!("argument on the path: '{}' is not defined as `enumerator`", 
978                                            field.get_path_to_label().join("/"))
979                                    );
980                                }
981                    
982                                match field.get_arg_enum_title()
983                                {
984                                    Some(r) => 
985                                    {   
986                                        let _ = 
987                                        self.enum_defines
988                                            .get(r)
989                                            .ok_or_else(|| 
990                                                format!("can not find argument enum name: '{}'", r)
991                                            );
992
993                                        RustCodeItemDataType::Enum(r.clone())
994                                    },
995                                    None => 
996                                    {
997                                        return Err(
998                                            format!("enum name was not set, field: '{}'", field.get_field_name_safe())
999                                        );
1000                                    }
1001                                }
1002                            },
1003                            FieldTypes::Enum =>
1004                            {
1005                                let (enumer, proced) = 
1006                                    self.resolve_path_to_enum(cur_proc_int.clone(), field.get_path_to_label(), 
1007                                        field.get_path_to_label())?;
1008
1009                                if cur_enumer.is_some() == true && enumer.as_ref() == cur_enumer.as_ref().unwrap().as_ref()
1010                                {
1011                                    RustCodeItemDataType::Enum(enumer.get_enum_label().clone())
1012                                }
1013                                else
1014                                {
1015                                // todo. do not resolve duplicates
1016                                    self.generate_rust_enum(rust_code, enumer.clone(), proced)?;
1017
1018                                    RustCodeItemDataType::Enum(enumer.get_enum_label().clone())
1019                                }
1020                            },
1021                            FieldTypes::Range =>
1022                            {
1023                                let foreign_arg = 
1024                                    self.resolve_path_to_arg(cur_proc_int.clone(), field.get_path_to_label(), 
1025                                        field.get_path_to_label())?;
1026
1027                                let sd_type = 
1028                                    match foreign_arg.get_collection_type()
1029                                    {
1030                                        ArgDataType::UInt => 
1031                                            RustCodeItemDataType::Uint(field.get_int_width()),
1032                                        ArgDataType::Int => 
1033                                            RustCodeItemDataType::Int(field.get_int_width()),
1034                                        _ => 
1035                                            return Err(
1036                                                format!("unexpected inner type for <range>, type: '{}'", 
1037                                                    foreign_arg.get_collection_type())
1038                                            )
1039                                    };
1040
1041                                RustCodeItemDataType::Range(Box::new(sd_type))
1042                            },
1043                            FieldTypes::RangeInc =>
1044                            {
1045                                let foreign_arg = 
1046                                    self.resolve_path_to_arg(cur_proc_int.clone(), field.get_path_to_label(), 
1047                                        field.get_path_to_label())?;
1048
1049                                let sd_type = 
1050                                    match foreign_arg.get_collection_type()
1051                                    {
1052                                        ArgDataType::UInt => 
1053                                            RustCodeItemDataType::Uint(field.get_int_width()),
1054                                        ArgDataType::Int => 
1055                                            RustCodeItemDataType::Int(field.get_int_width()),
1056                                        _ => 
1057                                            return Err(
1058                                                format!("unexpected inner type for <rangeinc>, type: '{}'", 
1059                                                    foreign_arg.get_collection_type())
1060                                            )
1061                                    };
1062
1063                                RustCodeItemDataType::RangeInclusive(Box::new(sd_type))
1064                            },
1065                            FieldTypes::String => 
1066                                RustCodeItemDataType::String,
1067                            FieldTypes::Boolean => 
1068                                RustCodeItemDataType::Bool,
1069                            FieldTypes::Int => 
1070                                RustCodeItemDataType::Int(field.get_int_width()),
1071                            FieldTypes::UInt => 
1072                                RustCodeItemDataType::Uint(field.get_int_width()),
1073                            FieldTypes::LongInt => 
1074                                RustCodeItemDataType::Int(field.get_int_width()),
1075                            FieldTypes::LongUInt => 
1076                                RustCodeItemDataType::Uint(field.get_int_width()),
1077                            FieldTypes::None => 
1078                                return Err(format!("can not serialize field with type None")),
1079                            FieldTypes::Optional => 
1080                                return Err(format!("can not serialize field with type Optional")),
1081                            FieldTypes::Vector => 
1082                                return Err(format!("field with vector in vector is not allowed")),
1083                        };
1084
1085                    RustCodeItemDataType::Vector(Box::new(inner_type), field.get_vector_serial_type())
1086                },
1087                FieldTypes::Enum =>
1088                {
1089                    // search the enumerator searilization infromation
1090                    let (enumer, proced) = 
1091                        self.resolve_path_to_enum(cur_proc_int.clone(), field.get_path_to_label(), 
1092                            field.get_path_to_label())?;
1093
1094                    self.generate_rust_enum(rust_code, enumer.clone(), proced)?;
1095
1096                    RustCodeItemDataType::Enum(enumer.get_enum_label().clone())
1097                },
1098                FieldTypes::ArgEnum =>
1099                {
1100                    let foreign_arg = 
1101                        self.resolve_path_to_arg(cur_proc_int.clone(), field.get_path_to_label(), 
1102                            field.get_path_to_label())?;
1103                    
1104                    if *foreign_arg.get_data_type() != ArgDataType::Enumerator
1105                    {
1106                        return Err(
1107                            format!("argument on the path: '{}' is not defined as `enumerator`", 
1108                                field.get_path_to_label().join("/"))
1109                        );
1110                    }
1111
1112                    match field.get_arg_enum_title()
1113                    {
1114                        Some(r) => 
1115                        {   
1116                            let _ = 
1117                            self.enum_defines
1118                                .get(r)
1119                                .ok_or_else(|| 
1120                                    format!("can not find argument enum name: '{}'", r)
1121                                );
1122
1123                            RustCodeItemDataType::Enum(r.clone())
1124                        },
1125                        None => 
1126                        {
1127                            return Err(
1128                                format!("enum name was not set, field: '{}'", field.get_field_name_safe())
1129                            );
1130                        }
1131                    }
1132                },
1133                FieldTypes::None => 
1134                    return Err(format!("can not serialize field with type None")),
1135                FieldTypes::Optional => 
1136                    return Err(format!("can not serialize field with type Optional")),
1137            };
1138
1139        
1140        return Ok(field_datatype);
1141    }
1142
1143    /// Forms a field of the structure with field name and datatype.
1144    /// 
1145    /// Calls `generate_field_data_type()` to generate the field type.
1146    /// 
1147    /// # Arguments
1148    /// 
1149    /// * `rust_code` - a mutable reference to [RustCode] instance which
1150    ///     is used to build code.
1151    /// 
1152    /// * `field` - a reference to [FieldDecl] with the field description
1153    ///     from serialization information.
1154    /// 
1155    /// * `cur_proc_int` - a related [Procedure] to the serialized data.
1156    /// 
1157    /// * `cur_enumer` - 
1158    /// 
1159    /// # Returns
1160    /// 
1161    /// A [SchemeResult] is returned.
1162    /// 
1163    /// * [Result::Ok] with the [RustCodeItemStruct] as inner type which 
1164    ///     contains a field data type information.
1165    /// 
1166    /// * [Result::Err] with error description.
1167    fn generate_field(
1168        &self, 
1169        rust_code: &mut RustCode, 
1170        field: &FieldDecl, 
1171        cur_proc_int: Arc<Procedure>,
1172        cur_enumer: Option<Arc<Enumerator>>
1173    ) -> Result<RustCodeItemStruct, String>
1174    {
1175        let is_enum = cur_enumer.is_some();
1176        let field_datatype = self.generate_field_data_type(rust_code, field, cur_proc_int, cur_enumer)?;
1177
1178        return Ok(
1179            RustCodeItemStruct
1180                ::new(field.get_field_name(), field.is_optional(), field.get_field_comment(),
1181                    field_datatype, is_enum
1182                )
1183        );
1184    }
1185
1186    /// Builds an enumertator from provided arguments. 
1187    /// 
1188    /// This function is recursive.
1189    /// 
1190    /// # Arguments
1191    /// 
1192    /// * `rust_code` - a mutable reference to [RustCode] instance which
1193    ///     is used to build code.
1194    /// 
1195    /// * `enumer` - a reference to [Enumerator] which describes the 
1196    ///     serialization of the [Procedure] provided in arg `proced`
1197    ///     as an enum.
1198    /// 
1199    /// * `proced` - a [Rc] to [Procedure] which describes how to 
1200    ///     read the config and which has a [Structure] description which
1201    ///     is passed in arg `cur_set_int`.
1202    /// 
1203    /// # Returns
1204    /// 
1205    /// A [SchemeResult] is returned.
1206    /// 
1207    /// * [Result::Ok] - if operation is successful.
1208    /// 
1209    /// * [Result::Err] - if operation has failed and error is returned.
1210    fn generate_rust_enum(
1211        &self, 
1212        rust_code: &mut RustCode, 
1213        enumer:Arc<Enumerator>, 
1214        _proced:Arc<Procedure>
1215    ) -> Result<(), String>
1216    {
1217        // reserve memory for the fields
1218        let mut enums: Vec<RustCodeEnumType> = Vec::with_capacity(enumer.get_enum_opts_len());
1219
1220        // each enumerator options
1221        for enm in enumer.get_enum_opts_iter()
1222        {
1223            match enm
1224            {
1225                // An enum option without inner data.
1226                EnumOpt::Anonymous{ proc_rename, comment, .. } => 
1227                {
1228                    let rcet = RustCodeEnumType::new_anon(proc_rename, comment.clone());
1229
1230                    enums.push(rcet);
1231                },
1232                // An enum option with tuple data.
1233                EnumOpt::Vector{ proc_name, proc_rename, fields, comment } => 
1234                {
1235                    // reserve memory for the tuple items
1236                    let mut items: Vec<RustCodeItemDataType> = Vec::with_capacity(fields.len());
1237
1238                    // get the [Procedure] by `proc_name` from the all known procedures
1239                    let proc_loc = 
1240                        self
1241                            .procedures
1242                            .get(proc_name)
1243                            .ok_or_else(|| 
1244                                format!("procedure named: '{}', does not exist in list of \
1245                                    procedures while serializing enum {} -> {}", proc_name, proc_name, proc_rename)
1246                            )?
1247                            .clone();
1248
1249                    for field in fields.iter()
1250                    {
1251                        let field = 
1252                            self.generate_field_data_type(rust_code, field, proc_loc.clone(), Some(enumer.clone()))?;
1253
1254                        items.push(field);
1255                    }
1256
1257                    let rcet = RustCodeEnumType::new_vec(proc_rename, items, comment.clone());
1258
1259                    enums.push(rcet);
1260                },
1261                // An enum option with structure data.
1262                EnumOpt::Structure { proc_name, proc_rename, structure, comment } => 
1263                {
1264                    // reserve memory for the fields
1265                    let mut items: Vec<RustCodeItemStruct> = Vec::with_capacity(structure.get_fields_len());
1266
1267                    // get the [Procedure] by `proc_name` from the all known procedures
1268                    let proc_loc = 
1269                        self
1270                            .procedures
1271                            .get(proc_name)
1272                            .ok_or_else(|| 
1273                                format!("procedure named: '{}', does not exist in list of \
1274                                    procedures while serializing enum {} -> {}", proc_name, proc_name, proc_rename)
1275                            )?
1276                            .clone();
1277
1278                    for root_field in structure.get_fields_iter()
1279                    {
1280                        let field = 
1281                            self
1282                                .generate_field(rust_code, root_field, proc_loc.clone(), Some(enumer.clone()))
1283                                .map_err(|e| 
1284                                    format!("{} procedure: '{}', path to label: '{}'", e, proc_name, 
1285                                        error::convert_list(root_field.get_path_to_label()))
1286                                )?;
1287
1288                        items.push(field);
1289                    }
1290                    
1291                    let rcet = RustCodeEnumType::new_fields(proc_rename, items, comment.clone());
1292                    //self.generate_rust_struct_anon(str_buffers, &mut str_buffer, structure, proc_loc.clone())?;
1293
1294                    enums.push(rcet);
1295                }
1296            }
1297        }
1298
1299        rust_code.add_item(
1300            RustCodeItem::new_enum(enumer.as_ref(),enums)
1301        );
1302
1303        return Ok(());
1304    }
1305
1306    /// Returns a title of the serializer.
1307    pub 
1308    fn get_name(&self) -> &String
1309    {
1310        return &self.name;
1311    }
1312
1313    /// Clones a title of the serializer.
1314    pub 
1315    fn clone_name(&self) ->Arc<String>
1316    {
1317        return self.name.clone();
1318    }
1319
1320    /// Declares new procedure
1321    pub 
1322    fn new_root_proc(&mut self, proc: Procedure) -> Result<(), String>
1323    {
1324        if self.root_proc.is_none() == false
1325        {
1326            return Err(
1327                format!("procedure: '{}' already exists in root of serializer: '{}'", 
1328                    proc.get_name(), self.name)
1329            );
1330        }
1331
1332        self.root_proc = Some(Arc::new(proc));
1333
1334        return Ok(());
1335    }
1336
1337    /// Declares new procedure.
1338    pub 
1339    fn new_proc(&mut self, proc: Procedure) -> Result<(), String>
1340    { 
1341        if self.procedures.contains_key(proc.get_name()) == true
1342        {
1343            return Err(
1344                format!("procedure: '{}' already exists in serializer: '{}'", 
1345                    proc.get_name(), self.name)
1346            );
1347        }
1348
1349        self.procedures.insert(proc.clone_name(), Arc::new(proc));
1350
1351        return Ok(());
1352    }
1353
1354    /// Declares symbol.
1355    pub 
1356    fn symbol_define(&mut self, def: Define) -> Result<(), String>
1357    {
1358        if self.defines.contains_key(def.get_name()) == true
1359        {
1360            return Err(
1361                format!("redefinition of the define label: '{}' in serializer: '{}'", 
1362                    def.get_name(), self.name)
1363            );
1364        }
1365
1366        self.defines.insert(def.clone_name(), Arc::new(def));
1367
1368        return Ok(());
1369    }
1370
1371    pub 
1372    fn symbol_enum_define(&mut self, def: DefineEnum) -> Result<(), String>
1373    {
1374        if self.enum_defines.contains_key(def.get_enum_name()) == true
1375        {
1376            return Err(
1377                format!("redefinition of the enum-define label: '{}' in serializer: '{}'", 
1378                    def.get_enum_name(), self.name)
1379            );
1380        }
1381
1382        self.enum_defines.insert(def.clone_enum_name(), Arc::new(def));
1383
1384        return Ok(());
1385    }
1386
1387    /// Sets the root serialization descriptor.
1388    pub 
1389    fn set_root_serialization_struct(&mut self, ser: Structure) -> Result<(), String>
1390    {
1391        if self.root_ser_structure.is_some() == true
1392        {
1393            return Err(
1394                format!("redefinition of the root struct: '{}' in serializer: '{}'", 
1395                    ser.get_struct_name(), self.name)
1396            );
1397        }
1398        let rc_ser = Arc::new(ser);
1399
1400        self.root_ser_structure = Some(rc_ser.clone());
1401        self.structs.push(rc_ser);
1402
1403        return Ok(());
1404    }
1405    
1406    /// Declares serialization information for structure.
1407    pub 
1408    fn add_serialization_struct(&mut self, ser: Structure)
1409    {
1410        self.structs.push(Arc::new(ser));
1411    }
1412
1413    /// Declares a serialization information for enum.
1414    pub 
1415    fn add_serialization_enum(&mut self, enm: Enumerator)
1416    {
1417        self.enumeratos.push(Arc::new(enm));
1418    }
1419
1420    /// Searches for the [Structure] by the `proc_name` which is a procedure 
1421    /// name.
1422    /// 
1423    /// # Arguments
1424    /// 
1425    /// * `proc_name` - a reference to [String] which contains title of the
1426    ///     procedure.
1427    /// 
1428    /// # Returns
1429    /// 
1430    /// A [SchemeResult] with result is returned.
1431    /// 
1432    /// - [Result::Ok] with reference to [Structure] is returned on success.
1433    /// 
1434    /// - [Result::Err] with error description is returned.
1435    pub 
1436    fn get_serialization_struct_by_procname(&self, proc_name: &String) -> Result<Arc<Structure>, String>
1437    {
1438        for i in self.structs.iter()
1439        {
1440            if i.contain_proc_name(proc_name) == true
1441            {
1442                return Ok(i.clone());
1443            }
1444        }
1445
1446        return Err(
1447            format!("no struct serializes procedure: '{}' was found in serializer: '{}'", 
1448                proc_name, self.get_name())
1449        );
1450    }
1451
1452    pub 
1453    fn get_serialization_struct_by_procname_opt(&self, proc_name: &String) -> Option<Arc<Structure>>
1454    {
1455        for i in self.structs.iter()
1456        {
1457            if i.contain_proc_name(proc_name) == true
1458            {
1459                return Some(i.clone());
1460            }
1461        }
1462
1463        return None;
1464    }
1465
1466    pub 
1467    fn get_serialization_struct_by_name(&self, struct_name: &str) -> Result<Arc<Structure>, String>
1468    {
1469        for i in self.structs.iter()
1470        {
1471            if i.get_struct_name() == struct_name
1472            {
1473                return Ok(i.clone());
1474            }
1475        }
1476
1477        return Err(
1478            format!("no struct with name: '{}' was found in serializer: '{}'", 
1479                struct_name, self.get_name())
1480        );
1481    }
1482
1483    /// Searches for the [Enumerator] serialization information for enum
1484    /// by the `procedure name` which `enumerator` instance is serializing.
1485    /// 
1486    /// # Arguments
1487    /// 
1488    /// * `proc_name` - a reference to [String] which points to procedure name.
1489    /// 
1490    /// # Returns
1491    /// 
1492    /// A [SchemeResult] is returned with:
1493    /// 
1494    /// * [Result::Ok] on success with the reference to [Enumerator]
1495    /// 
1496    /// * [Result::Err] on error with the error description
1497    pub 
1498    fn get_serialization_enum_by_procname(&self, proc_name: &String) -> Result<&Enumerator, String>
1499    {
1500        for i in self.enumeratos.iter()
1501        {
1502            if i.is_proc_name_presents(proc_name) == true
1503            {
1504                return Ok(i);
1505            }
1506        }
1507
1508        return Err(format!("no enum serializes procedure: '{}' was found in serializer: '{}'", proc_name, self.get_name()));
1509    }
1510
1511    pub 
1512    fn get_procedure_by_name(&self, proc_name: &String) -> Option<&Arc<Procedure>>
1513    {
1514        return self.procedures.get(proc_name);
1515    }
1516
1517   /* pub 
1518    fn get_serialization_enum_by_rename_procname(&self, proc_rename: &String) -> SerializationPartialRes<&Enumerator>
1519    {
1520        for i in self.enumeratos.iter()
1521        {
1522            if i.
1523            if i.get_enum_opt_by_rename_procname(proc_rename).is_some() == true
1524            {
1525                return Ok(i);
1526            }
1527        }
1528
1529        ser_partial_throw!("no enum serializes procedure: '{}' was found in serializer: '{}'", proc_name, self.get_name());
1530    }*/
1531
1532    /// Returns root serialization structure if was defined
1533    pub 
1534    fn get_root_ser(&self) -> Option<Arc<Structure>>
1535    {
1536        return self.root_ser_structure.clone();
1537    }
1538
1539    /// Returns root procedure.
1540    /// 
1541    /// The [Rc] inside Option is cloned.
1542    pub 
1543    fn get_root_proc(&self) -> Option<Arc<Procedure>>
1544    {
1545        return self.root_proc.clone();
1546    }
1547
1548    /// Returns iterator to defined symbols.
1549    pub 
1550    fn get_define_list_iter(&self) -> hash_map::Iter<'_, Arc<String>, Arc<Define>>
1551    {
1552        return self.defines.iter();
1553    }
1554
1555    /// Returns iterator to defined enum symbols.
1556    pub 
1557    fn get_enum_define_list_iter(&self) -> hash_map::Iter<'_, Arc<String>, Arc<DefineEnum>>
1558    {
1559        return self.enum_defines.iter();
1560    }
1561
1562    pub 
1563    fn get_enum_define_value_by_key(&self, key: &String) -> Option<&Arc<DefineEnum>>
1564    {
1565        return self.enum_defines.get(key);
1566    }
1567
1568    /// Returns iterator to all defined procedures.
1569    pub 
1570    fn get_procedure_list_iter(&self) -> hash_map::Iter<'_,Arc<String>, Arc<Procedure>>
1571    {
1572        return self.procedures.iter();
1573    }
1574}
1575
1576/// A struct which holds information about definitions.
1577#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
1578pub struct DefineEnum
1579{
1580    /// An symbol name
1581    enum_name:Arc<String>,  
1582
1583    /// Enum fields
1584    enum_defs: IndexSet<String>,
1585
1586    /// An items related to code generation
1587    rust_code_gen: RustCodeFields,
1588}
1589
1590impl Hash for DefineEnum
1591{
1592    fn hash<H: Hasher>(&self, state: &mut H) 
1593    {
1594        self.enum_name.hash(state);
1595    }
1596}
1597
1598impl PartialEq<str> for DefineEnum
1599{
1600    fn eq(&self, other: &str) -> bool 
1601    {
1602        return self.enum_name.as_str() == other;
1603    }
1604}
1605
1606impl PartialEq<String> for DefineEnum
1607{
1608    fn eq(&self, other: &String) -> bool 
1609    {
1610        return self.enum_name.as_str() == other.as_str();
1611    }
1612}
1613
1614impl Borrow<str> for DefineEnum
1615{
1616    fn borrow(&self) -> &str 
1617    {
1618        return &self.enum_name;
1619    }
1620}
1621
1622impl Borrow<String> for DefineEnum
1623{
1624    fn borrow(&self) -> &String 
1625    {
1626        return &self.enum_name;
1627    }
1628}
1629
1630impl fmt::Display for DefineEnum
1631{
1632    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
1633    {
1634        write!(f, "enum_name: '{}', enum_defs: '{}'", 
1635            self.enum_name, 
1636            self.enum_defs.iter().map(|f| f.as_str()).collect::<Vec<&str>>().join(","), 
1637        )
1638    }
1639}
1640
1641impl Clone for DefineEnum 
1642{
1643    fn clone(&self) -> Self 
1644    {
1645        panic!("Asserion trap: Define must never be cloned! \
1646                Implementation Clone for Define is used to comply \
1647                with compilter requirments.");
1648    }
1649}
1650
1651impl DefineEnum
1652{
1653    pub 
1654    fn new(enum_name: String, enum_defs: IndexSet<String>) -> Result<Self, String>
1655    {
1656        if enum_defs.len() == 0
1657        {
1658            return Err(format!("(define-enum \"{}\") is empty!", enum_name));
1659        }
1660
1661        return Ok( 
1662            Self
1663            { 
1664                enum_name: 
1665                    Arc::new(enum_name), 
1666                enum_defs: 
1667                    enum_defs,
1668                rust_code_gen: 
1669                    RustCodeFields::default(),
1670            } 
1671        );
1672    }
1673
1674    
1675    pub 
1676    fn get_enum_name(&self) -> &String
1677    {
1678        return self.enum_name.as_ref();
1679    }
1680
1681    pub 
1682    fn get_rust_code_gen(&self) -> &RustCodeFields
1683    {
1684        return &self.rust_code_gen;
1685    }
1686
1687    pub 
1688    fn get_rust_code_gen_mut(&mut self) -> &mut RustCodeFields
1689    {
1690        return &mut self.rust_code_gen;
1691    }
1692    
1693
1694    pub 
1695    fn clone_enum_name(&self) ->Arc<String>
1696    {
1697        return self.enum_name.clone();
1698    }
1699
1700    pub 
1701    fn generate_enum_pairs(&self) -> (Vec<Arc<String>>, Vec<Arc<String>>)
1702    {
1703        let mut enum_symbol_pair: Vec<Arc<String>> = Vec::with_capacity(self.enum_defs.len());
1704        let mut enum_symbol: Vec<Arc<String>> = Vec::with_capacity(self.enum_defs.len());
1705
1706        for ed in self.enum_defs.iter()
1707        {
1708            let upper_c = prepare_enum_variant(ed);
1709            let lower_c = some_kind_of_lowercase_first_letter(ed);
1710
1711            enum_symbol_pair.push(Arc::new([self.enum_name.as_ref(), "::", upper_c.as_str()].concat()));
1712            enum_symbol_pair.push(Arc::new([self.enum_name.as_ref(), "::", lower_c.as_str()].concat()));
1713            enum_symbol.push(Arc::new(upper_c.to_string()));
1714            enum_symbol.push(Arc::new(lower_c.to_string()));
1715        }
1716
1717        return (enum_symbol_pair, enum_symbol);
1718    }
1719
1720    pub 
1721    fn present(&self, itm: &str) -> bool
1722    {
1723        return self.enum_defs.contains(itm);
1724    }
1725
1726    pub 
1727    fn convert_to_dyn_scheme_def(&self, itm: &str) -> Option<&str>
1728    {
1729        for d in self.enum_defs.iter()
1730        {
1731            if prepare_enum_variant(d.as_str()) == itm
1732            {
1733                return Some(d.as_str());
1734            }
1735        }
1736
1737        return None;
1738    }
1739}
1740
1741/// A struct which holds information about definitions.
1742#[derive(Debug, Default, Serialize, Deserialize)]
1743pub struct Define
1744{
1745    /// An symbol name
1746    name: Arc<String>, 
1747
1748    /// Data it defines
1749    data: GenericDataTypes, 
1750
1751    /// A data type
1752    data_type: ArgDataType,
1753
1754    /// In which procedures can be used
1755    proc_binds: Option<HashSet<String>>,
1756
1757    /// A comment for the const value in Rust code
1758    comment: Option<String>,
1759}
1760
1761impl fmt::Display for Define
1762{
1763    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
1764    {
1765        write!(f, "symbol: '{}', data: '{}', binds: '{}'", 
1766            self.name, self.data, 
1767            self.proc_binds
1768                .as_ref()
1769                .map_or(
1770                    "UNBIND".to_string(), 
1771                    |f| f.iter().map(|v| v.as_str()).collect::<Vec<&str>>().join(", ")
1772                )
1773        )
1774    }
1775}
1776
1777impl Hash for Define
1778{
1779    fn hash<H: Hasher>(&self, state: &mut H) 
1780    {
1781        self.name.as_ref().hash(state);
1782    }
1783}
1784
1785impl Eq for Define {}
1786
1787impl PartialEq for Define 
1788{
1789    fn eq(&self, other: &Self) -> bool 
1790    {
1791        return 
1792            self.name.as_ref() == other.name.as_ref();
1793    }
1794}
1795
1796impl Borrow<String> for Define
1797{
1798    fn borrow(&self) -> &String
1799    {
1800        return &self.name;
1801    }
1802}
1803
1804impl Borrow<str> for Define
1805{
1806    fn borrow(&self) -> &str
1807    {
1808        return &self.name;
1809    }
1810}
1811
1812impl Clone for Define 
1813{
1814    fn clone(&self) -> Self 
1815    {
1816        panic!("Asserion trap: Define must never be cloned! \
1817                Implementation Clone for Define is used to comply \
1818                with compilter requirments.");
1819    }
1820}
1821
1822impl Define
1823{
1824    pub 
1825    fn new(name: String, dt_type: ArgDataType, data: GenericDataTypes, proc_binds_set: HashSet<String>) -> Self
1826    {
1827        let proc_binds = 
1828            if proc_binds_set.len() > 0
1829            {
1830                Some(proc_binds_set)
1831            }
1832            else
1833            {
1834                None
1835            };
1836    
1837        return Self{ name: Arc::new(name), data_type: dt_type, data, proc_binds, comment: None };
1838    }
1839
1840    pub 
1841    fn clone_name(&self) -> Arc<String>
1842    {
1843        return self.name.clone();
1844    }
1845
1846    pub 
1847    fn clone_data(&self) -> GenericDataTypes
1848    {
1849        return self.data.clone();
1850    }
1851    pub 
1852    fn set_comment(&mut self, comment: String)
1853    {
1854        self.comment.replace(comment);
1855    }
1856
1857    pub 
1858    fn get_name(&self) -> &String
1859    {
1860        return &self.name;
1861    }
1862
1863    pub 
1864    fn get_data(&self) -> &GenericDataTypes
1865    {
1866        return &self.data;
1867    }
1868
1869    pub 
1870    fn get_binds(&self) -> Option<&HashSet<String>>
1871    {
1872        return self.proc_binds.as_ref();
1873    }
1874
1875    pub 
1876    fn get_datatype(&self) -> ArgDataType
1877    {
1878        return self.data_type;
1879    }
1880
1881    /// Returns `true` if `proc_name` is defined in the list
1882    /// of binded procedures or if instance is not limited to any
1883    /// procedure.
1884    pub 
1885    fn is_in_proc_scope(&self, proc_name: &String) -> bool
1886    {
1887        if let Some(ref p) = self.proc_binds
1888        {
1889            return p.contains(proc_name);
1890        }
1891        else
1892        {
1893            return true;
1894        }
1895    }
1896}
1897
1898/// A strucure which holds information about `procedure` 
1899/// read from init (static scheme) scheme files.
1900#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
1901pub struct Procedure
1902{
1903    /// A title of the procedure
1904    name: Arc<String>,
1905
1906    /// Arguments of the procedure (in strict order)
1907    args: LinkedHashMap<Arc<String>, Arc<Argument>>,
1908
1909    /// A procedures which may appear in current instance
1910    procs: LinkedHashMap<Arc<String>, Arc<ForegnProc>>,
1911
1912    /// Explicitly define procedure as empty
1913    is_empty: bool,
1914}
1915
1916impl PartialEq<str> for Procedure
1917{
1918    fn eq(&self, other: &str) -> bool 
1919    {
1920        return self.name.as_str() == other;
1921    }
1922}
1923
1924impl Hash for Procedure
1925{
1926    fn hash<H: Hasher>(&self, state: &mut H) 
1927    {
1928        self.name.hash(state);
1929    }
1930}
1931
1932impl Borrow<str> for Procedure
1933{
1934    fn borrow(&self) -> &str 
1935    {
1936        return &self.name;
1937    }
1938}
1939
1940impl Borrow<String> for Procedure
1941{
1942    fn borrow(&self) -> &String 
1943    {
1944        return &self.name;
1945    }
1946}
1947
1948impl fmt::Display for Procedure
1949{
1950    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
1951    {
1952        write!(f, "name: {}, is_empty: {}, porcs: {}", self.name, self.is_empty, 
1953            self.procs.keys().map(|k| k.as_ref().clone()).collect::<Vec<String>>().join(", "))
1954    }
1955}
1956
1957impl Clone for Procedure 
1958{
1959    fn clone(&self) -> Self 
1960    {
1961        panic!("Asserion trap: Procedure must never be cloned! \
1962            Implementation Clone for Procedure is used to comply \
1963            with compilter requirments.");
1964    }
1965}
1966
1967impl Procedure
1968{
1969    pub const ROOT_PROC_NAME: &'static str = "root_procedure_0000";
1970
1971    pub 
1972    fn new(name: String, li: LexerInfo) -> Result<Self, String>
1973    {
1974        if common::contains_printable_all(&name) == false
1975        {
1976            return Err(
1977                format!("in procedure: 'N?A', near: '{}' the procedure name contains non-printable character!", li)
1978            );
1979        }
1980
1981        return Ok(
1982            Self
1983            {
1984                name: Arc::new(name), 
1985                args: LinkedHashMap::new(), 
1986                procs: LinkedHashMap::new(), 
1987                is_empty: false,
1988            }
1989        );
1990    }
1991
1992    pub 
1993    fn new_root() -> Self
1994    {
1995        return 
1996            Self
1997            {
1998                name: Arc::new(Self::ROOT_PROC_NAME.to_string()), 
1999                args: LinkedHashMap::new(), 
2000                procs: LinkedHashMap::new(), 
2001                is_empty: false,
2002            };
2003    }
2004
2005    pub
2006    fn is_root(&self) -> bool
2007    {
2008        return self.name.as_str() == Self::ROOT_PROC_NAME;
2009    }
2010
2011    pub 
2012    fn clone_name(&self) ->Arc<String>
2013    {
2014        return self.name.clone();
2015    }
2016
2017    pub 
2018    fn get_arg_by_label(&self, arg_level: &String) -> Option<&Arc<Argument>>
2019    {
2020        return self.args.get(arg_level);
2021    }
2022    
2023    pub 
2024    fn get_proc_by_label(&self, proc_name: &String) -> Option<&Arc<ForegnProc>>
2025    {
2026        return self.procs.get(proc_name);
2027    }
2028
2029    pub 
2030    fn get_name(&self) -> &String
2031    {
2032        return &self.name;
2033    }
2034
2035    pub 
2036    fn get_args_iter(&self) -> linked_hash_map::Iter<'_,Arc<String>,Arc<Argument>>
2037    {
2038        return self.args.iter();
2039    }
2040
2041    pub 
2042    fn get_args_len(&self) -> usize
2043    {
2044        return self.args.len();
2045    }
2046
2047    pub 
2048    fn get_procs_iter(&self) -> linked_hash_map::Iter<'_,Arc<String>,Arc<ForegnProc>>
2049    {
2050        return self.procs.iter();
2051    }
2052
2053    pub 
2054    fn get_procs_len(&self) -> usize
2055    {
2056        return self.procs.len();
2057    }
2058
2059    pub 
2060    fn get_proc(&self) -> &LinkedHashMap<Arc<String>,Arc<ForegnProc>>
2061    {
2062        return &self.procs;
2063    }
2064
2065    /// Adds a procedure's argument.
2066    /// (arg ...)
2067    pub 
2068    fn add_arg(&mut self, arg: Argument) -> Result<(), String>
2069    {
2070        if self.is_empty == true
2071        {
2072            return Err(
2073                format!("(procedure \"{}\") was explicitly set to empty but expects \
2074                    (arg \"{}\") to appear", self.get_name(), arg.get_label())
2075            );
2076        }
2077
2078        let res = 
2079            self.args.insert(arg.clone_label(), Arc::new(arg));
2080
2081        if let Some(r) = res
2082        {
2083            return Err(
2084                format!("redefinition of the (arg \"{}\" {:?}) in \
2085                    (procedure \"{}\")", r.get_label(), r.arg_data_types, self.get_name())
2086            );
2087        }
2088
2089        return Ok(());
2090    }
2091
2092    /// Adds a foreign procedure to current procedure instance.
2093    /// 
2094    /// # Arguments
2095    /// 
2096    /// * `proc_label` - [String] a label to the foreign procedure/s
2097    /// 
2098    /// * `proc_names` - [HashSet] [String] an allowed foreign procedures to appear in 
2099    ///     current procedure instance.
2100    /// 
2101    /// * `proc_allowed_flags` - [ProcFlags] a control flags like collection, optional
2102    pub 
2103    fn add_proc(
2104        &mut self, 
2105        proc_label: String, 
2106        proc_names: HashSet<String>, 
2107        proc_allowed_flags: ProcFlags
2108    ) -> Result<(), String>
2109    {
2110        if self.is_empty == true
2111        {
2112            return Err(
2113                format!("procedure: '{}' was explicitly set to be empty, but a \
2114                    foreign procedure is added: '{}", self.get_name(), proc_label)
2115            );
2116        }
2117
2118        let label = Arc::new(proc_label);
2119        let fp = ForegnProc::new(label.clone(), proc_names, proc_allowed_flags);
2120
2121        let res = self.procs.insert(label, Arc::new(fp));
2122
2123        if let Some(r) = res
2124        {
2125            return Err(
2126                format!("redefinition of the foreign proc: '{}' in procedure: '{}'",
2127                        r.get_label(), self.get_name())
2128            );
2129        }
2130
2131        return Ok(());
2132    }
2133
2134    /// Sets the current procedure instance as empty i.e no args or 
2135    /// procedures.
2136    pub 
2137    fn set_empty(&mut self)
2138    {
2139        self.is_empty = true;
2140    }
2141
2142    /// Returns the true if procedure does not have args or procedures
2143    pub 
2144    fn is_empty(&self) -> bool
2145    {
2146        return self.is_empty;
2147    }
2148
2149    /// Searches (by `procedure name`) for the [ForegnProc] which has been added previously to
2150    /// current instance.
2151    /// 
2152    /// # Arguments
2153    /// 
2154    /// * `proc_name` - a name of the foreign process to lookup.
2155    /// 
2156    /// # Returns
2157    /// 
2158    /// The [Option] is returned with:
2159    /// 
2160    /// * [Option::Some] with [Rc] to [ForegnProc] reference clonned instance.
2161    /// 
2162    /// * [Option::None] with nothing if not found.
2163    pub 
2164    fn lookup_procedure(&self, proc_name: &String) -> Option<Arc<ForegnProc>>
2165    {
2166        for (_, p) in self.procs.iter()
2167        {
2168            if p.contains_proc(proc_name) == true
2169            {
2170                return Some(p.clone());
2171            }
2172        }
2173
2174        return None;
2175    }
2176
2177    pub 
2178    fn validate(&self, li: LexerInfo) -> Result<(), String>
2179    {
2180        if self.args.is_empty() == true && self.procs.is_empty() == true &&
2181            self.is_empty() == false
2182        {
2183            return Err(
2184                format!("in procedure: '{}', near: '{}' the procedure should either contain \
2185                    foreign procs or arg or to be set to empty (procedure_empty)", self.get_name(), li)
2186            );
2187        }
2188        else if (self.args.is_empty() == false || self.procs.is_empty() == false) && 
2189            self.is_empty() == true
2190        {
2191            return Err(
2192                format!("in procedure: '{}', near: '{}' the procedure both contains \
2193                    foreign procs or arg and set to be empty (procedure_empty)",
2194                    self.get_name(), li)
2195            );
2196        }
2197
2198        return Ok(());
2199    }
2200}
2201
2202
2203/// A struct which holds information about procedures which are
2204/// declared in procedure, which are allowed to appear there.
2205/// 
2206/// i.e 
2207/// (procedure
2208///  (foreign_proc)...
2209/// )
2210#[derive(Debug, Serialize, Deserialize)]
2211pub struct ForegnProc
2212{
2213    /// A label which used to find the path to item
2214    label: Arc<String>,
2215
2216    /// A names of procedures which from which one or many is expected to appear
2217    /// in procedure.
2218    foregn_names: HashSet<String>,
2219
2220    /// A modification flags.
2221    flags: ProcFlags,
2222}
2223
2224impl fmt::Display for ForegnProc
2225{
2226    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
2227    {
2228        write!(f, "[foregn proc] label: '{}'", self.label)
2229    }
2230}
2231
2232impl Eq for ForegnProc {}
2233
2234impl PartialEq for ForegnProc
2235{
2236    fn eq(&self, other: &Self) -> bool 
2237    {
2238        self.label == other.label
2239    }
2240}
2241
2242impl Hash for ForegnProc 
2243{
2244    fn hash<H: Hasher>(&self, state: &mut H) 
2245    {
2246        self.label.hash(state);
2247    }
2248}
2249
2250impl ForegnProc
2251{
2252    pub 
2253    fn new(label: Arc<String>, foregn_names: HashSet<String>, flags: ProcFlags,) -> Self
2254    {
2255        return Self {label: label, foregn_names: foregn_names, flags: flags};
2256    }
2257
2258    pub 
2259    fn clone_label(&self) -> Arc<String>
2260    {
2261        return self.label.clone();
2262    }
2263
2264    pub 
2265    fn get_label(&self) -> &String
2266    {
2267        return &self.label;
2268    }
2269
2270    /// Verifies if procedure with name `proc_name` exists in the
2271    /// list of `foregn_names` - declared.
2272    pub 
2273    fn contains_proc(&self, proc_name: &String) -> bool
2274    {
2275        return self.foregn_names.contains(proc_name);
2276    }
2277
2278    /// Checks if modifier is set.
2279    pub 
2280    fn is_flag_set(&self, flag: ProcFlags) -> bool
2281    {
2282        return self.flags.intersects(flag);
2283    }
2284
2285    pub 
2286    fn get_proc_iter(&self) -> std::collections::hash_set::Iter<'_, String>
2287    {
2288        return self.foregn_names.iter();
2289    }
2290}
2291
2292/// A struct for temporary storage of the argument datatypes which
2293/// is used in `environment.rs` for data type extraction.
2294#[derive(Clone, Debug)]
2295pub struct Arg<'t>
2296{
2297    /// A reference to the arguments datatypes [Argument].
2298    arg_data_types: &'t [ArgDataType],
2299    
2300    /// An argument `arg_data_types` read index.
2301    index: Cell<usize>,
2302
2303    /// A enum bind (if any)
2304    set_enum_bind: Option<&'t String>
2305}
2306
2307impl<'t> Arg<'t>
2308{
2309    fn new(args: &'t [ArgDataType], set_enum_b: Option<&'t String>) -> Arg<'t>
2310    {
2311        return 
2312            Self
2313            { 
2314                arg_data_types: args, 
2315                index: Cell::new(0),
2316                set_enum_bind: set_enum_b
2317            };
2318    }
2319
2320    /// Pop argument data type. Does not check bounds. On first returned 
2321    /// [Option::None] means the end of list was reached.
2322    pub 
2323    fn pop_arg(&self) -> Option<&'t ArgDataType>
2324    {
2325        let arg = self.arg_data_types.get(self.index.get());
2326        self.index.set( self.index.get() + 1 );
2327
2328        return arg;
2329    }
2330
2331    pub 
2332    fn is_arg_enum_bind(&self) -> bool
2333    {
2334        return self.set_enum_bind.is_some();
2335    }
2336
2337    pub 
2338    fn get_arg_enum_bind(&self) -> &String
2339    {
2340        return self.set_enum_bind.as_ref().unwrap();
2341    }
2342}
2343
2344/// A structure which hold information about procedure's argument.
2345#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
2346pub struct Argument
2347{
2348    /// A label which is used to find the item by path.
2349    label: Arc<String>,
2350    //arg_data_type: ArgDataType, 
2351    //arg_collection_type: ArgDataType,
2352    
2353    /// A data type of the argument.
2354    arg_data_types: Vec<ArgDataType>,
2355
2356    /// A validator of argument (not implemented at the moment).
2357    //validators: Vec<Validator>,
2358
2359    /// An arg enumerator name
2360    set_enum_bind: Option<String>,
2361}
2362
2363impl fmt::Display for Argument
2364{
2365    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
2366    {
2367        write!(f, "label: '{}', datatypes: '{}'", 
2368            self.label, self.arg_data_types.iter().map(|d| d.to_string()).collect::<Vec<String>>().join("::"))
2369    }
2370}
2371
2372impl Argument
2373{
2374    /// Validates that the data types chain is correct.
2375    /// This function is recursive.
2376    fn validate_arg_datatypes(arg_data_types: &[ArgDataType]) -> Result<(), String>
2377    {
2378        let arg0_opt = arg_data_types.get(0);
2379        if arg0_opt.is_none() == true || arg0_opt.unwrap() == &ArgDataType::None
2380        {
2381            return Err(format!("argument validation problem: data type is mising"));
2382        }
2383
2384        if arg0_opt.unwrap().has_subtype() == true
2385        {
2386            return Self::validate_arg_datatypes(&arg_data_types[1..]);
2387        }
2388
2389        return Ok(());
2390    }
2391
2392    pub 
2393    fn new(label: Arc<String>, arg_data_types: Vec<ArgDataType>) -> Result<Self, String>
2394    {
2395        // validate ard_data_types
2396        Self::validate_arg_datatypes(arg_data_types.as_slice())?;
2397
2398        return Ok(
2399            Self
2400            { 
2401                label, 
2402                arg_data_types, 
2403                set_enum_bind: None,
2404            }
2405        );
2406    }
2407
2408    pub 
2409    fn clone_label(&self) ->Arc<String>
2410    {
2411        return self.label.clone();
2412    }
2413
2414    pub 
2415    fn get_args(&self) -> Arg<'_>
2416    {
2417        return 
2418            Arg::new(
2419                self.arg_data_types.as_slice(),
2420                self.set_enum_bind.as_ref()
2421            );
2422    }
2423
2424    pub 
2425    fn set_enum_bind(&mut self, enum_bind: Option<String>) -> Result<(), String>
2426    {
2427        if self.arg_data_types.iter().any(|f| f == &ArgDataType::Enumerator) == true 
2428        {
2429            if enum_bind.is_some() == true
2430            {
2431                self.set_enum_bind = enum_bind;
2432            }
2433            else
2434            {
2435                return Err(format!("enum_bind is none, but should be set for emumerator in argument"));
2436            }
2437
2438            return Ok(());
2439        }
2440        else
2441        {
2442            if enum_bind.is_some() == true
2443            {
2444                return Err(format!("enum_bind can only be set to procedure's field of type enum"));
2445            }
2446
2447            return Ok(());
2448        }
2449    }
2450
2451    pub 
2452    fn get_label(&self) -> &String
2453    {
2454        return &self.label;
2455    }
2456
2457    pub 
2458    fn get_data_base_type(&self) -> &ArgDataType
2459    {
2460        return &self.arg_data_types[0];
2461    }
2462
2463    pub 
2464    fn get_data_type(&self) -> &ArgDataType
2465    {
2466        return &self.arg_data_types[0];
2467    }
2468
2469    pub 
2470    fn get_collection_type(&self) -> &ArgDataType
2471    {
2472        return &self.arg_data_types[1];
2473    }
2474
2475    pub 
2476    fn get_collection_type_sub(&self) -> &ArgDataType
2477    {
2478        return &self.arg_data_types[2];
2479    }
2480
2481    pub 
2482    fn get_arg_index(&self, idx: usize) -> Option<&ArgDataType>
2483    {
2484        return self.arg_data_types.get(idx);
2485    }
2486
2487    pub 
2488    fn get_enum_bind(&self) -> Option<&String>
2489    {
2490        return self.set_enum_bind.as_ref();
2491    }
2492}
2493
2494/*
2495/// A validation of arguemnts of procedure. Not implemented yet.
2496#[derive(Clone, Debug, Serialize, Deserialize)]
2497pub struct Validator
2498{
2499    validator: ValidatorType, 
2500    val_data: GenericDataTypes, 
2501    descr: String,
2502}
2503
2504impl Validator
2505{
2506    pub fn new<D: Into<String>>(validator: ValidatorType, val_data: GenericDataTypes, descr: D) -> Self
2507    {
2508        return Self {validator, val_data, descr: descr.into()};
2509    }
2510}
2511*/
2512
2513//let proc = Procedure::new("test");
2514// let arg = proc.add_arg("name", ArgDataType::Vector, ArgDataType::i64);
2515//  arg.add_validate(Validator::NoDup, ValidatorData::None, "duplicate val");
2516//  arg.add_validate(Validator::LessEqual, ValidatorData::I64(100), "more than 100");
2517// drop(arg);
2518// proc.add_proc("proctest", ProcDataType::Struct, ProcDataType::None);
2519//
2520// serializator.add_proc("acls", proc, Serializator::AsHashMap("name", SerHashMap::Struct));
2521
2522