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