source_generator 0.0.3

Basic source code generation features
Documentation
use serde_derive::Deserialize;
use crate::vhdl::direction::Direction;
use crate::element::Element;

#[derive(Deserialize, Debug, Clone)]
pub struct Port {
    name : String,
    #[serde(default)]
    interface : String,
    direction : Direction,
    data_type : String,
    #[serde(default)]
    default : String
}

impl Port {
    pub fn new( name : & str, direction : Direction, data_type : & str )
            -> Port  {
        Port{ name : name.to_string(), interface : String::new(), direction : direction,
            data_type : data_type.to_string(), default : String::new() }

    }

    pub fn new_with_default( name : & str, direction : Direction, data_type : & str,
            default : & str ) -> Port  {
        Port{ name : name.to_string(), interface : String::new(), direction : direction,
            data_type : data_type.to_string(), default : default.to_string() }
    }

    pub fn clone_inverted( & self ) -> Port {
        Port::new_with_default( & self.name, self.direction.get_inverted(), & self.data_type,
            & self.default )
    }

    pub fn get_name( & self ) -> String {
        if ! self.interface.is_empty() {
            format!( "{}_{}", self.interface, self.name )
        }
        else {
            format!( "{}", self.name )
        }
    }

    pub fn set_name( & mut self, name : & str ) {
        self.name = name.to_string();
    }

    pub fn get_interface( & self ) -> & String {
        & self.interface
    }

    pub fn set_interface( & mut self, interface : & str ) {
        self.interface = interface.to_string();
    }

    pub fn get_direction( & self ) -> Direction {
        self.direction
    }

    pub fn get_data_type( & self ) -> & String {
        & self.data_type
    }

    pub fn invert( & mut self ) {
        self.direction.invert();
    }
}

impl Element for Port {
    fn to_source_code( & self, indent : usize ) -> String {
        let mut source = String::new();
        let indent_str = crate::util::indent( indent );
        source.push_str( & format!( "{}{} : {} {}", indent_str, self.get_name(),
            self.direction, self.data_type ) );
        if ! self.default.is_empty() {
            source.push_str( & format!( " := {}", self.default ) );
        }

        return source;
    }
}

//------------------------------------------------------------------------------
#[cfg(test)]
mod tests {
    use super::*;
    use std::error::Error;

    const INPUT : &'static str = "test : in boolean";
    const INPUT_WITH_DEFAULT : &'static str = "test : in boolean := true";
    const OUTPUT : &'static str = "test : out boolean";
    const INOUT : &'static str = "test : inout boolean";
    const BUFFER : &'static str = "test : buffer boolean";

    #[test]
    fn input_port() {
        let port = Port::new( "test", Direction::IN, "boolean" );
        assert_eq!( port.to_source_code( 0 ), INPUT.to_string() );
    }

    #[test]
    fn output_port() {
        let port = Port::new( "test", Direction::OUT, "boolean" );
        assert_eq!( port.to_source_code( 0 ), OUTPUT.to_string() );
    }

    #[test]
    fn inout_port() {
        let port = Port::new( "test", Direction::INOUT, "boolean" );
        assert_eq!( port.to_source_code( 0 ), INOUT.to_string() );
    }

    #[test]
    fn buffer_port() {
        let port = Port::new( "test", Direction::BUFFER, "boolean" );
        assert_eq!( port.to_source_code( 0 ), BUFFER.to_string() );
    }

    #[test]
    fn input_port_with_default() {
        let port = Port::new_with_default( "test", Direction::IN, "boolean", "true" );
        assert_eq!( port.to_source_code( 0 ), INPUT_WITH_DEFAULT.to_string() );
    }

    #[test]
    fn deserialize() -> Result< (), Box< dyn Error > > {
        let port : Port = serde_json::from_str(
            "{\"name\" : \"test\", \"direction\" : \"in\", \"data_type\" : \"boolean\"}" )?;
        assert_eq!( port.to_source_code( 0 ), INPUT.to_string() );
        Ok(())
    }

    #[test]
    fn deserialize_with_default() -> Result< (), Box< dyn Error > > {
        let port : Port = serde_json::from_str(
            "{\"name\" : \"test\", \"direction\" : \"in\", \"data_type\" : \"boolean\", \"default\" : \"true\"}" )?;
        assert_eq!( port.to_source_code( 0 ), INPUT_WITH_DEFAULT.to_string() );
        Ok(())
    }

    #[test]
    fn deserialize_invalid() {
        let ret : Result< Port, serde_json::Error > = serde_json::from_str( "\"invalid\"" );
        assert!( ret.is_err() );
    }

    #[test]
    fn invert() {
        let mut port = Port::new( "test", Direction::IN, "boolean" );
        port.invert();
        assert_eq!( port.to_source_code( 0 ), OUTPUT.to_string() );
    }

    #[test]
    fn clone_inverted() {
        let port = Port::new( "test", Direction::IN, "boolean" );
        let port = port.clone_inverted();
        assert_eq!( port.to_source_code( 0 ), OUTPUT.to_string() );
    }
}