Skip to main content

haloumi_ir/
meta.rs

1//! IR metadata
2
3use haloumi_core::{
4    constraints::CopyConstraint,
5    query::Fixed,
6    table::{Any, Column, RegionIndex},
7};
8use internment::Intern;
9
10use crate::groups::GroupKey;
11
12/// Implemented by IR objects that have metadata.
13pub trait HasMeta {
14    /// Returns a reference to the metadata.
15    fn meta(&self) -> &Meta;
16
17    /// Returns a mutable reference to the metadata.
18    fn meta_mut(&mut self) -> &mut Meta;
19}
20
21/// Metadata associated with an IR object.
22#[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    /// Sets the location at a PLONK gate.
33    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    /// Sets the location at a copy constraint.
53    pub fn at_copy_constraint(&mut self, constraint: CopyConstraint) {
54        self.edit_meta(|meta| meta.location = Location::CopyConstraint(constraint))
55    }
56
57    /// Sets the location at a lookup.
58    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    /// Sets the location at an injection index.
71    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    /// Sets the group information.
76    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    /// Sets the row.
86    pub fn at_row(&mut self, row: usize) {
87        self.edit_meta(|meta| {
88            meta.row = Some(row);
89        });
90    }
91
92    /// Completes the metadata with information from the given instance.
93    ///
94    /// Does not overwrite anything that has already been written.
95    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}