source_generator/vhdl/
entity_interface.rs1use 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#[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 #[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 #[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 #[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