Skip to content

Commit 1b510f0

Browse files
committed
Implement fmt::Display for variable types
1 parent 705d2f6 commit 1b510f0

File tree

2 files changed

+105
-0
lines changed

2 files changed

+105
-0
lines changed

src/core/types.rs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::merkle::common::{MerkleRoot, TypeMerkleRoot};
22
use crate::merkle::tmr::Tmr;
3+
use crate::util::replace_to_buffer;
34
use std::collections::VecDeque;
45
use std::iter::FromIterator;
56
use std::{cell::RefCell, cmp, fmt, rc::Rc, sync::Arc};
@@ -128,6 +129,65 @@ pub(crate) enum VariableType {
128129
Product(RcVar, RcVar),
129130
}
130131

132+
impl VariableType {
133+
fn uncompressed_display<W: fmt::Write>(&self, w: &mut W) -> fmt::Result {
134+
match self {
135+
VariableType::Unit => w.write_str("1"),
136+
VariableType::Sum(a, b) => {
137+
w.write_str("(")?;
138+
a.borrow().inner.uncompressed_display(w)?;
139+
w.write_str(" + ")?;
140+
b.borrow().inner.uncompressed_display(w)?;
141+
w.write_str(")")
142+
}
143+
VariableType::Product(a, b) => {
144+
w.write_str("(")?;
145+
a.borrow().inner.uncompressed_display(w)?;
146+
w.write_str(" × ")?;
147+
b.borrow().inner.uncompressed_display(w)?;
148+
w.write_str(")")
149+
}
150+
// Uncomment to use intermediate compression: more allocation of smaller strings
151+
// VariableType::Sum(a, b) => write!(w, "({} + {})", a, b),
152+
// VariableType::Product(a, b) => write!(w, "({} × {})", a, b),
153+
}
154+
}
155+
}
156+
157+
fn into_compressed_display(mut buffer1: String) -> String {
158+
let mut buffer2 = String::with_capacity(buffer1.len());
159+
160+
replace_to_buffer(&buffer1, &mut buffer2, "(1 + 1)", "2");
161+
buffer1.clear();
162+
replace_to_buffer(&buffer2, &mut buffer1, "(2 × 2)", "2^2");
163+
buffer2.clear();
164+
replace_to_buffer(&buffer1, &mut buffer2, "(2^2 × 2^2)", "2^4");
165+
buffer1.clear();
166+
replace_to_buffer(&buffer2, &mut buffer1, "(2^4 × 2^4)", "2^8");
167+
buffer2.clear();
168+
replace_to_buffer(&buffer1, &mut buffer2, "(2^8 × 2^8)", "2^16");
169+
buffer1.clear();
170+
replace_to_buffer(&buffer2, &mut buffer1, "(2^16 × 2^16)", "2^32");
171+
buffer2.clear();
172+
replace_to_buffer(&buffer1, &mut buffer2, "(2^32 × 2^32)", "2^64");
173+
buffer1.clear();
174+
replace_to_buffer(&buffer2, &mut buffer1, "(2^64 × 2^64)", "2^128");
175+
buffer2.clear();
176+
replace_to_buffer(&buffer1, &mut buffer2, "(2^128 × 2^128)", "2^256");
177+
178+
buffer2
179+
}
180+
181+
impl fmt::Display for VariableType {
182+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
183+
let mut buffer1 = String::new();
184+
self.uncompressed_display(&mut buffer1)?;
185+
let buffer2 = into_compressed_display(buffer1);
186+
187+
write!(f, "{}", buffer2)
188+
}
189+
}
190+
131191
/// Variable that can be cheaply cloned and internally mutated
132192
pub(crate) type RcVar = Rc<RefCell<Variable>>;
133193

@@ -182,6 +242,16 @@ impl fmt::Debug for Variable {
182242
}
183243
}
184244

245+
impl fmt::Display for Variable {
246+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
247+
let mut buffer1 = String::new();
248+
self.inner.uncompressed_display(&mut buffer1)?;
249+
let buffer2 = into_compressed_display(buffer1);
250+
251+
write!(f, "{}", buffer2)
252+
}
253+
}
254+
185255
/// Unification variable without metadata (see [`Variable`])
186256
#[derive(Clone)]
187257
pub(crate) enum VariableInner {
@@ -208,6 +278,19 @@ impl fmt::Debug for VariableInner {
208278
}
209279
}
210280

281+
impl VariableInner {
282+
fn uncompressed_display<W: fmt::Write>(&self, w: &mut W) -> fmt::Result {
283+
match self {
284+
VariableInner::Free(id) => w.write_str(id),
285+
VariableInner::Bound(ty, _) => ty.uncompressed_display(w),
286+
// Uncomment to use intermediate compression: more allocation of smaller strings
287+
// VariableInner::Bound(ty, _) => write!(w, "{}", ty),
288+
VariableInner::EqualTo(parent) => parent.borrow().inner.uncompressed_display(w),
289+
VariableInner::Finalized(ty) => write!(w, "{}", ty),
290+
}
291+
}
292+
}
293+
211294
/// Factory for creating free variables with fresh names.
212295
/// Identifiers are assigned sequentially as follows:
213296
/// `A`, `B`, `C`, ... `Z`, `AA`, `AB`, `AC`, ...

src/util.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,25 @@ pub(crate) fn bitvec_to_bytevec(bitvec: &[bool]) -> Vec<u8> {
6565
}
6666
ret
6767
}
68+
69+
/// Replace all occurrences of a `pattern` in a `src` string with a `replacement` string,
70+
/// and write the result to a `dst` string.
71+
///
72+
/// This method does not allocate if `dst` is sufficiently long (e.g., as long as `src`).
73+
pub(crate) fn replace_to_buffer(src: &str, dst: &mut String, pattern: &str, replacement: &str) {
74+
let mut last_index = 0;
75+
let len = pattern.len();
76+
77+
for (index, _) in src.match_indices(pattern) {
78+
if last_index < index {
79+
dst.push_str(&src[last_index..index])
80+
}
81+
82+
dst.push_str(replacement);
83+
last_index = index + len;
84+
}
85+
86+
if last_index < src.len() {
87+
dst.push_str(&src[last_index..])
88+
}
89+
}

0 commit comments

Comments
 (0)