1use crate::ty::Type;
2use std::fmt;
3
4#[derive(Clone)]
5pub enum Seg<'a> {
6 NamedIndex(usize, &'a str),
7 Index(usize),
8}
9impl<'a> fmt::Debug for Seg<'a> {
10 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
11 match self {
12 Seg::NamedIndex(_, name) => f.write_str(name),
13 Seg::Index(i) => write!(f, "{}", i),
14 }
15 }
16}
17
18#[derive(Clone, Debug)]
19pub struct MemberVariableRouting<'a> {
20 pub sym: Vec<Seg<'a>>,
21 pub offset: usize,
22 pub ty: &'a Type,
23}
24
25struct WalkFrame<'a> {
26 sym_stem: Option<Vec<Seg<'a>>>,
27 base_offset: usize,
28 ty: &'a Type,
29 i: usize,
30}
31pub struct Walk<'a> {
32 inner: Vec<WalkFrame<'a>>,
33}
34impl<'a> Walk<'a> {
35 pub fn new(ty: &'a Type) -> Walk<'a> {
36 let frame = WalkFrame {
37 sym_stem: None,
38 base_offset: 0,
39 ty: ty,
40 i: 0,
41 };
42 Walk { inner: vec![frame] }
43 }
44}
45impl<'a> Iterator for Walk<'a> {
46 type Item = MemberVariableRouting<'a>;
47 fn next(&mut self) -> Option<MemberVariableRouting<'a>> {
48 fn get_child_ty_offset_seg<'a>(
49 ty: &'a Type,
50 i: usize,
51 ) -> Option<(&'a Type, usize, Seg<'a>)> {
52 match ty {
53 Type::Struct(struct_ty) => {
54 let member = struct_ty.members.get(i)?;
55 let seg = if let Some(name) = &member.name {
56 Seg::NamedIndex(i, &name)
57 } else {
58 Seg::Index(i)
59 };
60 Some((&member.ty, member.offset.unwrap_or_default(), seg))
61 }
62 Type::Array(arr_ty) => {
63 if i < arr_ty.nelement.unwrap_or_default() as usize {
65 Some((
66 &arr_ty.element_ty,
67 arr_ty.stride.unwrap_or_default() * i,
68 Seg::Index(i),
69 ))
70 } else {
71 None
72 }
73 }
74 _ => None,
75 }
76 }
77 enum LoopEnd<'a> {
78 Push(WalkFrame<'a>),
79 PopReturn(MemberVariableRouting<'a>),
80 }
81 loop {
82 let loop_end = if let Some(frame) = self.inner.last_mut() {
86 if let Some((child_ty, offset, seg)) = get_child_ty_offset_seg(frame.ty, frame.i) {
87 frame.i += 1; let offset = frame.base_offset + offset;
89 let ty = child_ty;
90 let sym = if let Some(sym_stem) = &frame.sym_stem {
91 let mut sym = sym_stem.clone();
92 sym.push(seg);
93 sym
94 } else {
95 vec![seg]
96 };
97 if child_ty.is_struct() || child_ty.is_array() {
98 LoopEnd::Push(WalkFrame {
100 sym_stem: Some(sym),
101 base_offset: offset,
102 ty,
103 i: 0,
104 })
105 } else {
106 return Some(MemberVariableRouting { sym, offset, ty });
108 }
109 } else {
110 let ty = frame.ty;
114 let offset = frame.base_offset;
115 let sym = frame.sym_stem.clone().unwrap_or_default();
116 LoopEnd::PopReturn(MemberVariableRouting { sym, offset, ty })
117 }
118 } else {
119 return None;
122 };
123 match loop_end {
124 LoopEnd::Push(frame) => self.inner.push(frame),
125 LoopEnd::PopReturn(route) => {
126 self.inner.pop();
127 return Some(route);
128 }
129 }
130 }
131 }
132}