1use crate::cat;
32use crate::traits::Identify;
33use crate::{NonNegative, Reversed};
34
35#[derive(Debug, Clone, PartialEq)]
37pub struct Array {
38 identifier: String,
40 pub size: usize,
42 pub typ: Box<Type>,
44}
45
46impl Identify for Array {
47 fn identifier(&self) -> &str {
48 self.identifier.as_str()
49 }
50}
51
52#[derive(Debug, Clone, PartialEq)]
54pub struct Field {
55 name: String,
57 typ: Type,
59 reversed: bool,
62}
63
64impl Identify for Field {
65 fn identifier(&self) -> &str {
66 self.name.as_str()
67 }
68}
69
70impl Field {
71 pub fn new(name: impl Into<String>, typ: Type, reversed: bool) -> Field {
73 Field {
74 name: name.into(),
75 typ,
76 reversed,
77 }
78 }
79
80 pub fn typ(&self) -> &Type {
81 &self.typ
82 }
83
84 pub fn is_reversed(&self) -> bool {
85 self.reversed
86 }
87}
88
89impl Reversed for Field {
90 fn reversed(&self) -> Self {
91 Field::new(self.name.clone(), self.typ.clone(), !self.reversed)
92 }
93}
94
95#[derive(Debug, Clone, PartialEq)]
97pub struct Record {
98 identifier: String,
100 fields: Vec<Field>,
102}
103
104impl Identify for Record {
105 fn identifier(&self) -> &str {
106 self.identifier.as_str()
107 }
108}
109
110impl Record {
111 pub fn new(name: impl Into<String>, fields: Vec<Field>) -> Record {
113 Record {
115 identifier: name.into(),
116 fields,
117 }
118 }
119
120 pub fn new_empty(name: impl Into<String>) -> Record {
122 Record {
123 identifier: name.into(),
124 fields: vec![],
125 }
126 }
127
128 pub fn new_empty_stream(name: impl Into<String>) -> Record {
130 Record {
131 identifier: name.into(),
132 fields: vec![
133 Field::new("valid", Type::Bit, false),
134 Field::new("ready", Type::Bit, true),
135 ],
136 }
137 }
138
139 pub fn insert_new_field(&mut self, name: impl Into<String>, typ: Type, reversed: bool) {
141 self.fields.push(Field::new(name, typ, reversed));
142 }
143
144 pub fn insert(&mut self, field: Field) {
146 self.fields.push(field);
147 }
148
149 pub fn has_reversed(&self) -> bool {
151 self.fields.iter().any(|i| i.reversed)
152 }
153
154 pub fn fields(&self) -> impl Iterator<Item = &Field> {
156 self.fields.iter()
157 }
158
159 pub fn is_empty(&self) -> bool {
161 self.fields.is_empty()
162 }
163
164 pub fn append_name_nested(&self, with: impl Into<String>) -> Self {
166 let p: String = with.into();
167 let mut result = Record::new_empty(cat!(self.identifier, p.clone()));
168 for f in self.fields() {
169 result.insert(match f.typ() {
170 Type::Record(r) => Field::new(
171 f.identifier(),
172 Type::Record(r.append_name_nested(p.clone())),
173 f.reversed,
174 ),
175 _ => f.clone(),
176 });
177 }
178 result
179 }
180}
181
182#[derive(Debug, Clone, PartialEq)]
184pub enum Type {
185 Bit,
187 BitVec {
189 width: NonNegative,
191 },
192 Array(Array),
194 Record(Record),
196}
197
198pub type TypeBundle = Vec<(Vec<String>, Type, bool)>;
200
201impl Type {
202 pub fn bitvec(width: NonNegative) -> Type {
204 Type::BitVec { width }
205 }
206
207 pub fn record(name: impl Into<String>, fields: Vec<Field>) -> Type {
209 Type::Record(Record::new(name.into(), fields))
210 }
211
212 pub fn flatten(&self, prefix: Vec<String>, reversed: bool) -> TypeBundle {
214 let mut result: TypeBundle = vec![];
215 match self {
216 Type::Record(rec) => rec.fields.iter().for_each(|field| {
217 let mut new_prefix = prefix.clone();
218 new_prefix.push(field.name.clone());
219 result.extend(field.typ.flatten(new_prefix, field.reversed))
220 }),
221 _ => result.push((prefix, self.clone(), reversed)),
222 }
223 result
224 }
225
226 pub fn has_reversed(&self) -> bool {
228 match self {
229 Type::Record(rec) => rec.has_reversed(),
230 _ => false,
231 }
232 }
233}
234
235#[derive(Debug, Clone)]
237pub struct Parameter {
238 pub name: String,
239 pub typ: Type,
240}
241
242#[derive(Copy, Clone, Debug, PartialEq)]
244pub enum Mode {
245 In,
247 Out,
249}
250
251impl Reversed for Mode {
252 fn reversed(&self) -> Self {
253 match self {
254 Mode::In => Mode::Out,
255 Mode::Out => Mode::In,
256 }
257 }
258}
259
260#[derive(Debug, Clone, PartialEq)]
262pub struct Port {
263 identifier: String,
265 mode: Mode,
267 typ: Type,
269}
270
271impl Port {
272 pub fn new(name: impl Into<String>, mode: Mode, typ: Type) -> Port {
273 Port {
274 identifier: name.into(),
275 mode,
276 typ,
277 }
278 }
279
280 pub fn mode(&self) -> Mode {
281 self.mode
282 }
283
284 pub fn typ(&self) -> Type {
285 self.typ.clone()
286 }
287}
288
289impl Identify for Port {
290 fn identifier(&self) -> &str {
291 self.identifier.as_str()
292 }
293}
294
295#[derive(Debug, Clone)]
297pub struct Component {
298 identifier: String,
300 parameters: Vec<Parameter>,
302 ports: Vec<Port>,
304}
305
306impl Identify for Component {
307 fn identifier(&self) -> &str {
308 self.identifier.as_str()
309 }
310}
311
312impl Component {
313 pub fn new(
314 identifier: impl Into<String>,
315 parameters: Vec<Parameter>,
316 ports: Vec<Port>,
317 ) -> Component {
318 Component {
319 identifier: identifier.into(),
320 parameters,
321 ports,
322 }
323 }
324
325 pub fn ports(&self) -> &Vec<Port> {
326 &self.ports
327 }
328
329 pub fn parameters(&self) -> &Vec<Parameter> {
330 &self.parameters
331 }
332
333 pub fn flatten_types(&mut self) {
334 let mut new_ports: Vec<Port> = Vec::new();
335 self.ports.iter().for_each(|port| {
336 let bundle = port
337 .typ
338 .flatten(vec![port.identifier.clone()], port.mode == Mode::Out);
339 for tup in bundle {
340 new_ports.push(Port::new(
341 tup.0.join("_"),
342 if tup.2 { Mode::Out } else { Mode::In },
343 tup.1,
344 ));
345 }
346 });
347 self.ports = new_ports;
348 }
349}
350
351#[derive(Debug)]
353pub struct Library {
354 pub identifier: String,
356 pub components: Vec<Component>,
358}
359
360#[derive(Debug)]
364pub struct Project {
365 pub identifier: String,
367 pub libraries: Vec<Library>,
369}
370
371#[cfg(test)]
372pub(crate) mod test {
373
374 use super::*;
375 use crate::cat;
376
377 pub(crate) mod records {
378
379 use super::*;
380
381 pub(crate) fn prim(bits: u32) -> Type {
382 Type::bitvec(bits)
383 }
384
385 pub(crate) fn rec(name: impl Into<String>) -> Type {
386 Type::record(
387 cat!(name.into(), "type"),
388 vec![
389 Field::new("a", Type::bitvec(42), false),
390 Field::new("b", Type::bitvec(1337), false),
391 ],
392 )
393 }
394
395 pub(crate) fn rec_of_single(name: impl Into<String>) -> Type {
396 Type::record(
397 cat!(name.into(), "type"),
398 vec![Field::new("a", Type::bitvec(42), false)],
399 )
400 }
401
402 pub(crate) fn rec_nested(name: impl Into<String>) -> Type {
403 let n: String = name.into();
404 Type::record(
405 cat!(n, "type"),
406 vec![
407 Field::new("c", rec(cat!(n, "c")), false),
408 Field::new("d", rec(cat!(n, "d")), false),
409 ],
410 )
411 }
412 }
413
414 pub fn test_rec() -> Type {
416 Type::record(
417 "rec",
418 vec![
419 Field::new("a", Type::Bit, false),
420 Field::new("b", Type::bitvec(4), true),
421 ],
422 )
423 }
424
425 pub fn test_rec_nested() -> Type {
426 Type::record(
427 cat!("rec", "nested"),
428 vec![
429 Field::new("a", Type::Bit, false),
430 Field::new("b", test_rec(), false),
431 ],
432 )
433 }
434
435 pub fn test_comp() -> Component {
436 Component {
437 identifier: "test_comp".to_string(),
438 parameters: vec![],
439 ports: vec![
440 Port::new("a", Mode::In, test_rec()),
441 Port::new("b", Mode::Out, test_rec_nested()),
442 ],
443 }
444 }
445
446 pub fn test_lib() -> Library {
447 Library {
448 identifier: "lib".to_string(),
449 components: vec![test_comp()],
450 }
451 }
452
453 pub fn test_proj() -> Project {
454 Project {
455 identifier: "proj".to_string(),
456 libraries: vec![test_lib()],
457 }
458 }
459
460 #[test]
461 fn test_flatten_rec() {
462 let flat = test_rec().flatten(vec![], false);
463 assert_eq!(flat[0].0, vec!["a".to_string()]);
464 assert_eq!(flat[0].1, Type::Bit);
465 assert_eq!(flat[0].2, false);
466 assert_eq!(flat[1].0, vec!["b".to_string()]);
467 assert_eq!(flat[1].1, Type::bitvec(4));
468 assert_eq!(flat[1].2, true);
469 }
470
471 #[test]
472 fn test_flatten_rec_nested() {
473 let flat = test_rec_nested().flatten(vec![], false);
474 assert_eq!(flat[0].0[0], "a".to_string());
475 assert_eq!(flat[0].1, Type::Bit);
476 assert_eq!(flat[0].2, false);
477 assert_eq!(flat[1].0[0], "b".to_string());
478 assert_eq!(flat[1].0[1], "a".to_string());
479 assert_eq!(flat[1].1, Type::Bit);
480 assert_eq!(flat[1].2, false);
481 assert_eq!(flat[2].0[0], "b".to_string());
482 assert_eq!(flat[2].0[1], "b".to_string());
483 assert_eq!(flat[2].1, Type::bitvec(4));
484 assert_eq!(flat[2].2, true);
485 }
486
487 #[test]
488 fn rec_has_reversed() {
489 assert!(test_rec().has_reversed());
490 assert!(!Type::record(
491 "test",
492 vec![
493 Field::new("a", Type::Bit, false),
494 Field::new("b", Type::Bit, false),
495 ],
496 )
497 .has_reversed());
498 }
499}