1use haloumi_core::{
4 constraints::CopyConstraint,
5 query::Fixed,
6 table::{Any, Column, RegionIndex},
7};
8use internment::Intern;
9
10use crate::groups::GroupKey;
11
12pub trait HasMeta {
14 fn meta(&self) -> &Meta;
16
17 fn meta_mut(&mut self) -> &mut Meta;
19}
20
21#[derive(Debug, Copy, Clone, Default)]
23pub struct Meta(Intern<MetaImpl>);
24
25impl Meta {
26 fn edit_meta(&mut self, mut f: impl FnMut(&mut MetaImpl)) {
27 let mut meta = (*self.0.as_ref()).clone();
28 f(&mut meta);
29 self.0 = Intern::new(meta)
30 }
31
32 pub fn at_gate(
34 &mut self,
35 name: impl ToString,
36 region_name: impl ToString,
37 region: Option<RegionIndex>,
38 row: Option<usize>,
39 ) {
40 self.edit_meta(|meta| {
41 meta.location = Location::Gate {
42 name: name.to_string(),
43 region_name: region_name.to_string(),
44 region,
45 };
46 if let Some(row) = row {
47 meta.row = Some(row);
48 }
49 });
50 }
51
52 pub fn at_copy_constraint(&mut self, constraint: CopyConstraint) {
54 self.edit_meta(|meta| meta.location = Location::CopyConstraint(constraint))
55 }
56
57 pub fn at_lookup(&mut self, name: impl ToString, idx: usize, row: Option<usize>) {
59 self.edit_meta(|meta| {
60 meta.location = Location::Lookup {
61 name: name.to_string(),
62 idx,
63 };
64 if let Some(row) = row {
65 meta.row = Some(row);
66 }
67 })
68 }
69
70 pub fn at_inject(&mut self, region: RegionIndex, index: Option<usize>) {
72 self.edit_meta(|meta| meta.location = Location::Injected { region, index })
73 }
74
75 pub fn at_group(&mut self, name: impl ToString, key: Option<GroupKey>) {
77 self.edit_meta(|meta| {
78 meta.group_meta = Some(GroupMeta {
79 name: name.to_string(),
80 key,
81 });
82 });
83 }
84
85 pub fn at_row(&mut self, row: usize) {
87 self.edit_meta(|meta| {
88 meta.row = Some(row);
89 });
90 }
91
92 pub fn complete_with(&mut self, other: Self) {
96 self.edit_meta(|meta| {
97 let other = other.0.as_ref();
98 if let Some(group_meta) = other.group_meta.as_ref() {
99 meta.group_meta.get_or_insert_with(|| group_meta.clone());
100 }
101 if matches!(&meta.location, Location::Unknown) {
102 meta.location = other.location.clone();
103 }
104 if let Some(row) = other.row {
105 meta.row.get_or_insert(row);
106 }
107 })
108 }
109}
110
111fn fmt_cell(
112 column: &Column<Any>,
113 row: &usize,
114 f: &mut std::fmt::Formatter<'_>,
115) -> std::fmt::Result {
116 write!(
117 f,
118 "({}:{}, {row})",
119 match column.column_type() {
120 haloumi_core::table::Any::Fixed => "Fix",
121 haloumi_core::table::Any::Advice => "Adv",
122 haloumi_core::table::Any::Instance => "Ins",
123 },
124 column.index(),
125 )
126}
127
128fn fmt_fixed_cell(
129 column: &Column<Fixed>,
130 row: &usize,
131 f: &mut std::fmt::Formatter<'_>,
132) -> std::fmt::Result {
133 write!(f, "(Fix:{}, {row})", column.index(),)
134}
135
136impl std::fmt::Display for Meta {
137 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
138 let meta = self.0.as_ref();
139 if let Some(group_meta) = meta.group_meta.as_ref() {
140 write!(f, "group({}", group_meta.name)?;
141 if let Some(key) = group_meta.key {
142 write!(f, ", {key}")?;
143 }
144 write!(f, "): ")?;
145 }
146 match &meta.location {
147 Location::Unknown => write!(f, "unknown"),
148 Location::Gate {
149 name,
150 region_name,
151 region,
152 } => {
153 write!(f, "gate '{name}' @ region '{region_name}'")?;
154 match region {
155 Some(index) => write!(f, "({})", **index),
156 None => write!(f, "(unk)"),
157 }
158 }
159 Location::CopyConstraint(CopyConstraint::Cells(lhs_col, lhs_row, rhs_col, rhs_row)) => {
160 write!(f, "copy ")?;
161 fmt_cell(lhs_col, lhs_row, f)?;
162 write!(f, " === ")?;
163 fmt_cell(rhs_col, rhs_row, f)
164 }
165 Location::CopyConstraint(CopyConstraint::Fixed(col, row, value)) => {
166 write!(f, "copy ")?;
167 fmt_fixed_cell(col, row, f)?;
168 write!(f, " === {value}")
169 }
170 Location::Lookup { name, idx } => {
171 write!(f, "lookup '{name}'({idx})")
172 }
173 Location::Injected { region, index } => {
174 write!(f, "injected")?;
175 if let Some(index) = index {
176 write!(f, "({index})")?;
177 }
178 write!(f, " @ R{}", **region)
179 }
180 }?;
181 if let Some(row) = meta.row {
182 write!(f, " @ row {row}")?;
183 }
184 Ok(())
185 }
186}
187
188#[derive(Debug, Default, Hash, PartialEq, Eq, Clone)]
189struct GroupMeta {
190 name: String,
191 key: Option<GroupKey>,
192}
193
194#[derive(Debug, Default, Hash, PartialEq, Eq, Clone)]
195enum Location {
196 #[default]
197 Unknown,
198 Gate {
199 name: String,
200 region_name: String,
201 region: Option<RegionIndex>,
202 },
203 CopyConstraint(CopyConstraint),
204 Lookup {
205 name: String,
206 idx: usize,
207 },
208 Injected {
209 region: RegionIndex,
210 index: Option<usize>,
211 },
212}
213
214#[derive(Debug, Default, Hash, PartialEq, Eq, Clone)]
215struct MetaImpl {
216 group_meta: Option<GroupMeta>,
217 location: Location,
218 row: Option<usize>,
219}