miden_assembly_syntax/parser/
value.rs1use core::fmt;
2
3use miden_core::{
4 Felt,
5 field::PrimeField64,
6 serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
7};
8#[cfg(feature = "serde")]
9use serde::{Deserialize, Serialize};
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub enum PushValue {
16 Int(IntValue),
17 Word(WordValue),
18}
19
20impl From<u8> for PushValue {
21 fn from(value: u8) -> Self {
22 Self::Int(value.into())
23 }
24}
25
26impl From<u16> for PushValue {
27 fn from(value: u16) -> Self {
28 Self::Int(value.into())
29 }
30}
31
32impl From<u32> for PushValue {
33 fn from(value: u32) -> Self {
34 Self::Int(value.into())
35 }
36}
37
38impl From<Felt> for PushValue {
39 fn from(value: Felt) -> Self {
40 Self::Int(value.into())
41 }
42}
43
44impl From<IntValue> for PushValue {
45 fn from(value: IntValue) -> Self {
46 Self::Int(value)
47 }
48}
49
50impl From<WordValue> for PushValue {
51 fn from(value: WordValue) -> Self {
52 Self::Word(value)
53 }
54}
55
56impl fmt::Display for PushValue {
57 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58 match self {
59 Self::Int(value) => fmt::Display::fmt(value, f),
60 Self::Word(value) => fmt::Display::fmt(value, f),
61 }
62 }
63}
64
65impl crate::prettier::PrettyPrint for PushValue {
66 fn render(&self) -> crate::prettier::Document {
67 match self {
68 Self::Int(value) => value.render(),
69 Self::Word(value) => value.render(),
70 }
71 }
72}
73
74#[derive(Debug, Clone, Copy, PartialEq, Eq)]
78#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
79#[cfg_attr(feature = "serde", serde(transparent))]
80#[cfg_attr(
81 all(feature = "arbitrary", test),
82 miden_test_serde_macros::serde_test(binary_serde(true))
83)]
84pub struct WordValue(pub [Felt; 4]);
85
86impl fmt::Display for WordValue {
87 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88 let mut builder = f.debug_list();
89 for value in self.0 {
90 builder.entry(&value.as_canonical_u64());
91 }
92 builder.finish()
93 }
94}
95
96impl crate::prettier::PrettyPrint for WordValue {
97 fn render(&self) -> crate::prettier::Document {
98 use crate::prettier::*;
99
100 const_text("[")
101 + self
102 .0
103 .iter()
104 .copied()
105 .map(display)
106 .reduce(|acc, doc| acc + const_text(",") + doc)
107 .unwrap_or_default()
108 + const_text("]")
109 }
110}
111
112impl PartialOrd for WordValue {
113 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
114 Some(self.cmp(other))
115 }
116}
117
118impl Ord for WordValue {
119 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
120 let (WordValue([l0, l1, l2, l3]), WordValue([r0, r1, r2, r3])) = (self, other);
121 l0.as_canonical_u64()
122 .cmp(&r0.as_canonical_u64())
123 .then_with(|| l1.as_canonical_u64().cmp(&r1.as_canonical_u64()))
124 .then_with(|| l2.as_canonical_u64().cmp(&r2.as_canonical_u64()))
125 .then_with(|| l3.as_canonical_u64().cmp(&r3.as_canonical_u64()))
126 }
127}
128
129impl core::hash::Hash for WordValue {
130 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
131 let WordValue([a, b, c, d]) = self;
132 [
133 a.as_canonical_u64(),
134 b.as_canonical_u64(),
135 c.as_canonical_u64(),
136 d.as_canonical_u64(),
137 ]
138 .hash(state)
139 }
140}
141
142#[cfg(feature = "arbitrary")]
143impl proptest::arbitrary::Arbitrary for WordValue {
144 type Parameters = ();
145
146 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
147 use proptest::{array::uniform4, strategy::Strategy};
148 uniform4((0..crate::FIELD_MODULUS).prop_map(Felt::new_unchecked))
149 .prop_map(WordValue)
150 .no_shrink()
151 .boxed()
152 }
153
154 type Strategy = proptest::prelude::BoxedStrategy<Self>;
155}
156
157impl Serializable for WordValue {
158 fn write_into<W: ByteWriter>(&self, target: &mut W) {
159 self.0[0].write_into(target);
160 self.0[1].write_into(target);
161 self.0[2].write_into(target);
162 self.0[3].write_into(target);
163 }
164}
165
166impl Deserializable for WordValue {
167 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
168 let a = Felt::read_from(source)?;
169 let b = Felt::read_from(source)?;
170 let c = Felt::read_from(source)?;
171 let d = Felt::read_from(source)?;
172 Ok(Self([a, b, c, d]))
173 }
174}
175
176#[derive(Debug, Copy, Clone, PartialEq, Eq)]
182#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
183#[cfg_attr(feature = "serde", serde(untagged))]
184#[cfg_attr(
185 all(feature = "arbitrary", test),
186 miden_test_serde_macros::serde_test(binary_serde(true))
187)]
188pub enum IntValue {
189 U8(u8),
191 U16(u16),
193 U32(u32),
195 Felt(Felt),
197}
198
199impl From<u8> for IntValue {
200 fn from(value: u8) -> Self {
201 Self::U8(value)
202 }
203}
204
205impl From<u16> for IntValue {
206 fn from(value: u16) -> Self {
207 Self::U16(value)
208 }
209}
210
211impl From<u32> for IntValue {
212 fn from(value: u32) -> Self {
213 Self::U32(value)
214 }
215}
216
217impl From<Felt> for IntValue {
218 fn from(value: Felt) -> Self {
219 Self::Felt(value)
220 }
221}
222
223impl IntValue {
224 pub fn as_int(&self) -> u64 {
225 match self {
226 Self::U8(value) => *value as u64,
227 Self::U16(value) => *value as u64,
228 Self::U32(value) => *value as u64,
229 Self::Felt(value) => value.as_canonical_u64(),
230 }
231 }
232
233 pub fn as_canonical_u64(&self) -> u64 {
237 self.as_int()
238 }
239
240 pub fn checked_add(&self, rhs: Self) -> Option<Self> {
241 let value = self.as_int().checked_add(rhs.as_int())?;
242 if value >= crate::FIELD_MODULUS {
243 return None;
244 }
245 Some(shrink_u64_hex(value))
246 }
247
248 pub fn checked_sub(&self, rhs: Self) -> Option<Self> {
249 let value = self.as_int().checked_sub(rhs.as_int())?;
250 if value >= crate::FIELD_MODULUS {
251 return None;
252 }
253 Some(shrink_u64_hex(value))
254 }
255
256 pub fn checked_mul(&self, rhs: Self) -> Option<Self> {
257 let value = self.as_int().checked_mul(rhs.as_int())?;
258 if value >= crate::FIELD_MODULUS {
259 return None;
260 }
261 Some(shrink_u64_hex(value))
262 }
263
264 pub fn checked_div(&self, rhs: Self) -> Option<Self> {
265 let value = self.as_int().checked_div(rhs.as_int())?;
266 if value >= crate::FIELD_MODULUS {
267 return None;
268 }
269 Some(shrink_u64_hex(value))
270 }
271}
272
273impl core::ops::Add<IntValue> for IntValue {
274 type Output = IntValue;
275
276 fn add(self, rhs: IntValue) -> Self::Output {
277 shrink_u64_hex(self.as_int() + rhs.as_int())
278 }
279}
280
281impl core::ops::Sub<IntValue> for IntValue {
282 type Output = IntValue;
283
284 fn sub(self, rhs: IntValue) -> Self::Output {
285 shrink_u64_hex(self.as_int() - rhs.as_int())
286 }
287}
288
289impl core::ops::Mul<IntValue> for IntValue {
290 type Output = IntValue;
291
292 fn mul(self, rhs: IntValue) -> Self::Output {
293 shrink_u64_hex(self.as_int() * rhs.as_int())
294 }
295}
296
297impl core::ops::Div<IntValue> for IntValue {
298 type Output = IntValue;
299
300 fn div(self, rhs: IntValue) -> Self::Output {
301 shrink_u64_hex(self.as_int() / rhs.as_int())
302 }
303}
304
305impl PartialEq<Felt> for IntValue {
306 fn eq(&self, other: &Felt) -> bool {
307 match self {
308 Self::U8(lhs) => (*lhs as u64) == other.as_canonical_u64(),
309 Self::U16(lhs) => (*lhs as u64) == other.as_canonical_u64(),
310 Self::U32(lhs) => (*lhs as u64) == other.as_canonical_u64(),
311 Self::Felt(lhs) => lhs == other,
312 }
313 }
314}
315
316impl fmt::Display for IntValue {
317 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
318 match self {
319 Self::U8(value) => write!(f, "{value}"),
320 Self::U16(value) => write!(f, "{value}"),
321 Self::U32(value) => write!(f, "{value:#04x}"),
322 Self::Felt(value) => write!(f, "{:#08x}", &value.as_canonical_u64().to_be()),
323 }
324 }
325}
326
327impl crate::prettier::PrettyPrint for IntValue {
328 fn render(&self) -> crate::prettier::Document {
329 match self {
330 Self::U8(v) => v.render(),
331 Self::U16(v) => v.render(),
332 Self::U32(v) => v.render(),
333 Self::Felt(v) => v.as_canonical_u64().render(),
334 }
335 }
336}
337
338impl PartialOrd for IntValue {
339 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
340 Some(self.cmp(other))
341 }
342}
343
344impl Ord for IntValue {
345 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
346 use core::cmp::Ordering;
347 match (self, other) {
348 (Self::U8(l), Self::U8(r)) => l.cmp(r),
349 (Self::U8(_), _) => Ordering::Less,
350 (Self::U16(_), Self::U8(_)) => Ordering::Greater,
351 (Self::U16(l), Self::U16(r)) => l.cmp(r),
352 (Self::U16(_), _) => Ordering::Less,
353 (Self::U32(_), Self::U8(_) | Self::U16(_)) => Ordering::Greater,
354 (Self::U32(l), Self::U32(r)) => l.cmp(r),
355 (Self::U32(_), _) => Ordering::Less,
356 (Self::Felt(_), Self::U8(_) | Self::U16(_) | Self::U32(_)) => Ordering::Greater,
357 (Self::Felt(l), Self::Felt(r)) => l.as_canonical_u64().cmp(&r.as_canonical_u64()),
358 }
359 }
360}
361
362impl core::hash::Hash for IntValue {
363 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
364 core::mem::discriminant(self).hash(state);
365 match self {
366 Self::U8(value) => value.hash(state),
367 Self::U16(value) => value.hash(state),
368 Self::U32(value) => value.hash(state),
369 Self::Felt(value) => value.as_canonical_u64().hash(state),
370 }
371 }
372}
373
374impl Serializable for IntValue {
375 fn write_into<W: ByteWriter>(&self, target: &mut W) {
376 self.as_int().write_into(target)
377 }
378}
379
380impl Deserializable for IntValue {
381 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
382 let raw = source.read_u64()?;
383 if raw >= Felt::ORDER_U64 {
384 Err(DeserializationError::InvalidValue(
385 "int value is greater than field modulus".into(),
386 ))
387 } else {
388 Ok(shrink_u64_hex(raw))
389 }
390 }
391}
392
393#[cfg(feature = "arbitrary")]
394impl proptest::arbitrary::Arbitrary for IntValue {
395 type Parameters = ();
396
397 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
398 use proptest::{num, prop_oneof, strategy::Strategy};
399 prop_oneof![
400 num::u8::ANY.prop_map(IntValue::U8),
401 (u8::MAX as u16 + 1..=u16::MAX).prop_map(IntValue::U16),
402 (u16::MAX as u32 + 1..=u32::MAX).prop_map(IntValue::U32),
403 (num::u64::ANY).prop_filter_map("valid felt value", |n| {
404 if n > u32::MAX as u64 && n < crate::FIELD_MODULUS {
405 Some(IntValue::Felt(Felt::new_unchecked(n)))
406 } else {
407 None
408 }
409 }),
410 ]
411 .no_shrink()
412 .boxed()
413 }
414
415 type Strategy = proptest::prelude::BoxedStrategy<Self>;
416}
417
418#[inline]
419pub(crate) fn shrink_u64_hex(n: u64) -> IntValue {
420 if n <= (u8::MAX as u64) {
421 IntValue::U8(n as u8)
422 } else if n <= (u16::MAX as u64) {
423 IntValue::U16(n as u16)
424 } else if n <= (u32::MAX as u64) {
425 IntValue::U32(n as u32)
426 } else {
427 IntValue::Felt(Felt::new_unchecked(n))
428 }
429}