source_generator 0.0.3

Basic source code generation features
Documentation
use crate::element::Element;
use crate::vhdl::vhdl_error::VhdlError;
use crate::element::to_source_code_list;
use crate::vhdl::concurrent_statement::ConcurrentStatement;
use crate::vhdl::entity::Entity;
use crate::vhdl::entity_interface::EntityInterface;
use crate::vhdl::entity_interface_binding_list::EntityInterfaceBindingList;
use crate::vhdl::entity_interface_binding::EntityInterfaceBinding;
use crate::vhdl::generic_binding::GenericBinding;
use crate::vhdl::keywords::*;
use crate::vhdl::match_index::*;
use crate::vhdl::signal_declaration::SignalDeclaraion;

#[derive(Clone)]
pub struct Instance {
    name : String,
    library : String,
    entity : String,
    bindings : EntityInterfaceBindingList,
}

impl Instance {
    pub fn from_entity( name : & str, entity : & Entity ) -> Instance {
        Instance { name : name.to_string(),
                library : entity.get_target_library().to_string(),
                entity : entity.get_name().to_string(),
                bindings : EntityInterfaceBindingList::from_entity( entity ) }
    }

    pub fn connect_to_entity( & mut self, entity : & Entity ) {
        let entity_interfaces = entity.get_interfaces();
        let mut unbound_entity_interfaces = vec![ true; entity_interfaces.len() ];
        for instance_interface in self.bindings.get_interfaces_mut() {
            let mut match_index = MatchIndex::new();
            for ( entity_idx, entity_interface ) in entity_interfaces.iter().enumerate() {
                if ! unbound_entity_interfaces[ entity_idx ] {
                    continue;
                }
                match_index.update( entity_idx, Instance::get_match_strength(
                        instance_interface, entity_interface ) );
            }
            if match_index.is_match() {
                instance_interface.connect_to_entity_interface( & entity_interfaces[ match_index.position() ] );
                unbound_entity_interfaces[ match_index.position() ] = false;
            }
        }
    }

    pub fn connect_interface_by_name_to_signal_list( & mut self, name : & str, signal_list : & Vec< SignalDeclaraion > ) {
        let interface = self.bindings.get_interface_by_name_mut( name ).unwrap();
        interface.connect_to_signal_list( signal_list );
    }

    pub fn connect_interface_by_index_to_signal_list( & mut self, index : usize, signal_list : & Vec< SignalDeclaraion > ) {
        self.bindings.get_interfaces_mut()[ index ].connect_to_signal_list( signal_list );
    }

    pub fn connect_generic( & mut self, inner : & str, outer : & str ) -> Result< (), VhdlError > {
        let binding = self.bindings.get_generic_mut( inner )?;
        binding.connect_by_name( outer );
        Ok(())
    }

    pub fn connect_to_port( & mut self, inner : & str, outer : & str ) -> Result< (), VhdlError > {
        let binding = self.bindings.get_port_mut( inner )?;
        binding.connect_by_name( outer );
        Ok(())
    }

    pub fn get_name( & self ) -> & String {
        & self.name
    }

    pub fn get_interfaces( & self ) -> & Vec< EntityInterfaceBinding > {
        & self.bindings.get_interfaces()
    }

    pub fn get_interface_by_name( & self, name : & str ) -> Option< & EntityInterfaceBinding > {
        self.bindings.get_interface_by_name( name )
    }

    pub fn get_instance_interface_matches( & self, inst_b : & Instance ) -> Vec< ( usize, usize ) > {
        let mut matches = Vec::new();
        for ( idx_a, interface_a ) in self.get_interfaces().iter().enumerate() {
            let mut match_index = MatchIndex::new();
            for ( idx_b, interface_b ) in inst_b.get_interfaces().iter().enumerate() {
                match_index.update( idx_b, interface_a.get_instance_matching( interface_b ) );
            }
            if match_index.is_match() {
                matches.push( ( idx_a, match_index.position() ) );
            }
        }
        return matches;
    }

    pub fn get_unbound_generics( & self ) -> Vec< GenericBinding > {
        let mut generics : Vec< GenericBinding > = Vec::new();
        for interface in self.bindings.get_interfaces() {
            for generic in interface.get_unbound_generics()  {
                generics.push( generic );
            }
        }
        return generics;
    }

    pub fn get_port_data_type_by_name( & self, name : & str ) -> Option< & String > {
        for interface in self.bindings.get_interfaces() {
            for port in interface.get_ports() {
                if port.get_inner() == name {
                    return Some( port.get_data_type() )
                }
            }
        }
        None
    }

    fn get_generic_bindings( & self ) -> Vec< Box::< dyn Element > > {
        let mut bindings : Vec< Box< dyn Element > > = Vec::new();
        for interface in self.bindings.get_interfaces() {
            for generic in interface.get_generics() {
                if generic.is_bound() || generic.requires_binding() {
                    bindings.push( Box::new( ( * generic ).clone() ) );
                }
            }
        }
        return bindings;
    }

    fn get_port_bindings( & self ) -> Vec< Box::< dyn Element > > {
        let mut bindings : Vec< Box< dyn Element > > = Vec::new();
        for interface in self.bindings.get_interfaces() {
            for port in interface.get_ports() {
                bindings.push( Box::new( ( * port ).clone() ) );
            }
        }
        return bindings;
    }

    fn get_match_strength( instance : & EntityInterfaceBinding, entity : & EntityInterface )
            -> u32 {
        if instance.is_bound() {
            return NONE;
        }
        let instance_name = instance.get_name().to_string().to_lowercase();
        let entity_name = entity.get_name().to_string().to_lowercase();
        let class_match : bool = instance.get_class() == entity.get_class();
        let name_match : bool = instance_name == entity_name;
        let instance_in_entity = entity_name.contains( & instance_name );
        let entity_in_instance = instance_name.contains( & entity_name );
        if class_match && name_match {
            return FULL;
        }
        else if instance_in_entity || entity_in_instance {
            return PARTIAL;
        }
        else if class_match {
            return CLASS;
        }
        else {
            return NONE;
        }
    }

    pub fn contains_interface( & self, name : & str ) -> bool {
        self.bindings.contains_interface( name )
    }
}

impl Element for Instance {
    fn to_source_code( & self, indent : usize ) -> String {
        let mut source = String::new();
        let indent_str = crate::util::indent( indent );
        let map_indent_str = crate::util::indent( indent + 1 );
        let binding_indent_str = crate::util::indent( indent + 2 );
        source.push_str( & format!( "{}{} : {} {}.{}\n", indent_str, self.name, ENTITY,
                self.library, self.entity ) );

        let generic_bindings : Vec< Box< dyn Element > > = self.get_generic_bindings();
        let has_generic_bindings : bool = ! generic_bindings.is_empty();
        if has_generic_bindings {
            source.push_str( & format!( "{}{} {} (\n", map_indent_str, GENERIC, MAP ) );
            source.push_str( & format!( "{}{}\n", binding_indent_str,
                    to_source_code_list( & generic_bindings, & format!( ",\n{}", binding_indent_str ) ) ) );
            source.push_str( & format!( "{})", map_indent_str ) );
        }
        let port_bindings : Vec< Box< dyn Element > > = self.get_port_bindings();
        let has_port_bindings : bool = ! port_bindings.is_empty();
        if has_port_bindings {
            if has_generic_bindings {
                source.push_str( "\n" );
            }
            source.push_str( & format!( "{}{} {} (\n", map_indent_str, PORT, MAP ) );
            source.push_str( & format!( "{}{}\n", binding_indent_str,
                    to_source_code_list( & port_bindings, & format!( ",\n{}", binding_indent_str ) ) ) );
            source.push_str( & format!( "{})", map_indent_str ) );
        }
        source.push_str( ";\n" );
        return source;
    }
}

impl ConcurrentStatement for Instance {
}

//------------------------------------------------------------------------------
#[cfg(test)]
mod tests {
}