source_generator/vhdl/
entity_interface.rs

1use std::error::Error;
2use std::fs;
3use std::path::Path;
4use std::collections::HashSet;
5use serde_derive::Deserialize;
6use serde_json_schema::Schema;
7use crate::vhdl::generic::Generic;
8use crate::vhdl::port::Port;
9
10#[derive(Deserialize, Debug, Clone)]
11pub struct EntityInterface {
12    #[serde(default)]
13    name : String,
14    class : String,
15    #[serde(default)]
16    inverted : bool,
17    #[serde(default)]
18    generics : Vec< Generic >,
19    #[serde(default)]
20    ports : Vec< Port >,
21}
22
23impl EntityInterface {
24    pub fn new( name : & str, class : & str ) -> EntityInterface {
25        EntityInterface { name : name.to_string(), class : class.to_string(),
26            inverted : false, generics : Vec::new(), ports : Vec::new() }
27    }
28
29    pub fn new_unnamed( class : & str ) -> EntityInterface {
30        EntityInterface::new( "", class )
31    }
32
33    pub fn from_file( name : & str, filename : & Path ) -> Result< EntityInterface, Box< dyn Error > > {
34        let mut interface = EntityInterface::from_file_unnamed( filename )?;
35        interface.rename( name );
36        Ok( interface )
37    }
38
39    pub fn from_file_unnamed( file : & Path ) -> Result< EntityInterface, Box< dyn Error > > {
40        let schema = EntityInterface::read_schema()?;
41        let interface = EntityInterface::read_and_validate_description( file, & schema )?;
42        Ok( interface )
43    }
44
45    pub fn from_file_inverted( name : & str, filename : & Path ) -> Result< EntityInterface, Box< dyn Error > > {
46        let mut interface = EntityInterface::from_file( name, filename )?;
47        interface.invert();
48        Ok( interface )
49    }
50
51    pub fn from_file_unnamed_inverted( file : & Path ) -> Result< EntityInterface, Box< dyn Error > > {
52        let schema = EntityInterface::read_schema()?;
53        let interface = EntityInterface::read_and_validate_description( file, & schema )?;
54        Ok( interface )
55    }
56
57    pub fn clone_inverted( & self ) -> EntityInterface {
58        let mut inverted = self.clone();
59        inverted.invert();
60        return inverted;
61    }
62
63    pub fn clone_inverted_with_rename( & self, name : & str ) -> EntityInterface {
64        let mut inverted = self.clone();
65        inverted.invert();
66        inverted.rename( name );
67        return inverted;
68    }
69
70    pub fn get_name( & self ) -> & String {
71        & self.name
72    }
73
74    pub fn get_class( & self ) -> & String {
75        & self.class
76    }
77
78    pub fn get_generics( & self ) -> & Vec< Generic > {
79        & self.generics
80    }
81
82    pub fn get_ports( & self ) -> & Vec< Port > {
83        & self.ports
84    }
85
86    pub fn get_data_types( & self ) -> HashSet< String > {
87        let mut data_types = HashSet::new();
88        for generic in & self.generics {
89            data_types.insert( generic.get_data_type().clone() );
90        }
91        for port in & self.ports {
92            data_types.insert( port.get_data_type().clone() );
93        }
94        return data_types;
95    }
96
97    pub fn rename( & mut self, name : & str ) {
98        self.name = name.to_string();
99        for generic in & mut self.generics {
100            generic.set_interface( & self.name );
101        }
102        for port in & mut self.ports {
103            port.set_interface( & self.name );
104        }
105    }
106
107    pub fn invert( & mut self ) {
108        for port in & mut self.ports {
109            port.invert();
110        }
111        self.inverted = ! self.inverted;
112    }
113
114    pub fn add_generic( & mut self, generic : Generic ) {
115        self.generics.push( generic );
116    }
117
118    pub fn remove_generics( & mut self ) {
119        self.generics.clear();
120    }
121
122    pub fn remove_interface_from_generics( & mut self ) {
123        for generic in & mut self.generics {
124            generic.remove_interface();
125        }
126    }
127
128    pub fn add_port( & mut self, port : Port ) {
129        self.ports.push( port );
130    }
131
132    fn read_schema() -> Result< Schema, Box< dyn Error > > {
133        let schema_file_name = "data/schema/entity_interface.json";
134        let schema_str = fs::read_to_string( schema_file_name )?;
135        let schema = Schema::try_from( schema_str )?;
136        Ok( schema )
137    }
138
139    fn read_and_validate_description( file : & Path, schema : & Schema )
140            -> Result< EntityInterface, Box< dyn Error > > {
141        let module_str = fs::read_to_string( file )?;
142        let module_json : serde_json::Value = serde_json::from_str( & module_str )?;
143        match schema.validate( & module_json ) {
144            Ok(_)   => {},
145            Err( err ) => { eprintln!( "Failed to validate the {:?}\n    with error {:?}",
146                file.to_string_lossy(), err ) }, };
147        let description : EntityInterface = serde_json::from_str( & module_str )?;
148        Ok( description )
149    }
150}
151
152//------------------------------------------------------------------------------
153#[cfg(test)]
154mod tests {
155    use super::*;
156    use crate::element::Element;
157    use crate::vhdl::direction::Direction;
158
159    const PORTS : &'static str = concat!( "a : in integer := 0",
160        "b : out std_logic := '0'", "c : inout boolean",
161        "d : buffer positive" );
162
163    const GENERICS : &'static str = concat!( "A : integer := 0",
164        "B : std_logic := '0'", "C : boolean",
165        "D : positive" );
166
167
168    const INVERTED : &'static str = concat!( "A : integer := 0",
169        "B : std_logic := '0'", "C : boolean",
170        "D : positive", "a : out integer := 0",
171        "b : in std_logic := '0'", "c : inout boolean",
172        "d : in positive" );
173
174    /**
175     * Create an entity interface with multiple ports but no generics
176     */
177    #[test]
178    fn port_interface() {
179        let interface = new_test_interface_ports_only();
180        let source = interface_to_string( & interface );
181        assert_eq!( PORTS, source );
182    }
183
184    /**
185     * Create an entity interface with multiple generics but no ports
186     */
187    #[test]
188    fn generic_interface() {
189        let interface = new_test_interface_generics_only();
190        let source = interface_to_string( & interface );
191        assert_eq!( GENERICS, source );
192    }
193
194    #[test]
195    fn interface_from_json() -> Result< (), Box< dyn Error > > {
196        let interface = EntityInterface::from_file_unnamed(
197                Path::new( "tests/vhdl/interface.json" ) )?;
198        let source = interface_to_string( & interface );
199        assert_eq!( format!( "{}{}", GENERICS, PORTS ), source );
200        Ok(())
201    }
202
203    /**
204     * Invert an entity interface with multiple generics and ports
205     */
206    #[test]
207    fn invert() {
208        let mut interface = new_test_interface();
209        interface.invert();
210        let source = interface_to_string( & interface );
211        assert_eq!( INVERTED, source );
212    }
213
214    #[test]
215    fn clone_inverted() {
216        let interface = new_test_interface();
217        let interface = interface.clone_inverted();
218        let source = interface_to_string( & interface );
219        assert_eq!( INVERTED, source );
220    }
221
222    fn new_test_interface() -> EntityInterface {
223        let mut interface = EntityInterface::new_unnamed( "test" );
224        add_generics( & mut interface );
225        add_ports( & mut interface );
226        return interface;
227    }
228
229    fn new_test_interface_generics_only() -> EntityInterface {
230        let mut interface = EntityInterface::new_unnamed( "test" );
231        add_generics( & mut interface );
232        return interface;
233    }
234
235    fn new_test_interface_ports_only() -> EntityInterface {
236        let mut interface = EntityInterface::new_unnamed( "test" );
237        add_ports( & mut interface );
238        return interface;
239    }
240
241    fn add_generics( interface : & mut EntityInterface ) {
242        interface.add_generic( Generic::new_with_default( "A", "integer", "0" ) );
243        interface.add_generic( Generic::new_with_default( "B", "std_logic", "'0'" ) );
244        interface.add_generic( Generic::new( "C", "boolean" ) );
245        interface.add_generic( Generic::new( "D", "positive" ) );
246    }
247
248    fn add_ports( interface : & mut EntityInterface ) {
249        interface.add_port( Port::new_with_default( "a", Direction::IN, "integer", "0" ) );
250        interface.add_port( Port::new_with_default( "b", Direction::OUT, "std_logic", "'0'" ) );
251        interface.add_port( Port::new( "c", Direction::INOUT, "boolean" ) );
252        interface.add_port( Port::new( "d", Direction::BUFFER, "positive" ) );
253    }
254
255    fn interface_to_string( interface : & EntityInterface ) -> String {
256        let mut source = String::new();
257        for generic in interface.get_generics() {
258            source.push_str( & format!( "{}", generic.to_source_code( 0 ) ) );
259        }
260        for port in interface.get_ports() {
261            source.push_str( & format!( "{}", port.to_source_code( 0 ) ) );
262        }
263        return source;
264    }
265}
266
267