miden_assembly_syntax/ast/constants/
value.rs1use core::fmt;
2
3use miden_core::serde::{
4 ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable,
5};
6use miden_debug_types::{SourceSpan, Span, Spanned};
7#[cfg(feature = "serde")]
8use serde::{Deserialize, Serialize};
9
10use crate::{
11 ast::{HashKind, Ident},
12 parser::{IntValue, WordValue},
13};
14
15#[derive(Clone)]
20#[repr(u8)]
21#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
22#[cfg_attr(
23 all(feature = "arbitrary", test),
24 miden_test_serde_macros::serde_test(binary_serde(true))
25)]
26pub enum ConstantValue {
27 Int(Span<IntValue>) = 1,
29 String(Ident),
31 Word(Span<WordValue>),
33 Hash(HashKind, Ident),
36}
37
38impl Eq for ConstantValue {}
39
40impl PartialEq for ConstantValue {
41 fn eq(&self, other: &Self) -> bool {
42 match (self, other) {
43 (Self::Int(l), Self::Int(y)) => l == y,
44 (Self::Int(_), _) => false,
45 (Self::Word(l), Self::Word(y)) => l == y,
46 (Self::Word(_), _) => false,
47 (Self::String(l), Self::String(y)) => l == y,
48 (Self::String(_), _) => false,
49 (Self::Hash(x_hk, x_i), Self::Hash(y_hk, y_i)) => x_i == y_i && x_hk == y_hk,
50 (Self::Hash(..), _) => false,
51 }
52 }
53}
54
55impl core::hash::Hash for ConstantValue {
56 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
57 core::mem::discriminant(self).hash(state);
58 match self {
59 Self::Int(value) => value.hash(state),
60 Self::Word(value) => value.hash(state),
61 Self::String(value) => value.hash(state),
62 Self::Hash(kind, value) => {
63 kind.hash(state);
64 value.hash(state);
65 },
66 }
67 }
68}
69
70impl fmt::Debug for ConstantValue {
71 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
72 match self {
73 Self::Int(lit) => fmt::Debug::fmt(&**lit, f),
74 Self::Word(lit) => fmt::Debug::fmt(&**lit, f),
75 Self::String(name) => fmt::Debug::fmt(&**name, f),
76 Self::Hash(hash_kind, str) => fmt::Debug::fmt(&(str, hash_kind), f),
77 }
78 }
79}
80
81impl crate::prettier::PrettyPrint for ConstantValue {
82 fn render(&self) -> crate::prettier::Document {
83 use crate::prettier::*;
84
85 match self {
86 Self::Int(literal) => literal.render(),
87 Self::Word(literal) => literal.render(),
88 Self::String(ident) => text(format!("\"{}\"", ident.as_str().escape_debug())),
89 Self::Hash(hash_kind, str) => flatten(
90 display(hash_kind)
91 + const_text("(")
92 + text(format!("\"{}\"", str.as_str().escape_debug()))
93 + const_text(")"),
94 ),
95 }
96 }
97}
98
99impl Spanned for ConstantValue {
100 fn span(&self) -> SourceSpan {
101 match self {
102 Self::Int(spanned) => spanned.span(),
103 Self::Word(spanned) => spanned.span(),
104 Self::String(spanned) => spanned.span(),
105 Self::Hash(_, spanned) => spanned.span(),
106 }
107 }
108}
109
110impl ConstantValue {
111 const fn tag(&self) -> u8 {
112 unsafe { *(self as *const Self).cast::<u8>() }
119 }
120}
121
122impl Serializable for ConstantValue {
123 fn write_into<W: ByteWriter>(&self, target: &mut W) {
124 target.write_u8(self.tag());
125 match self {
126 Self::Int(value) => value.inner().write_into(target),
127 Self::String(id) => id.write_into(target),
128 Self::Word(value) => value.inner().write_into(target),
129 Self::Hash(kind, id) => {
130 kind.write_into(target);
131 id.write_into(target);
132 },
133 }
134 }
135}
136
137impl Deserializable for ConstantValue {
138 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
139 match source.read_u8()? {
140 1 => IntValue::read_from(source).map(Span::unknown).map(Self::Int),
141 2 => Ident::read_from(source).map(Self::String),
142 3 => WordValue::read_from(source).map(Span::unknown).map(Self::Word),
143 4 => {
144 let kind = HashKind::read_from(source)?;
145 let id = Ident::read_from(source)?;
146 Ok(Self::Hash(kind, id))
147 },
148 invalid => Err(DeserializationError::InvalidValue(format!(
149 "unexpected ConstantValue tag: '{invalid}'"
150 ))),
151 }
152 }
153}
154
155#[cfg(feature = "arbitrary")]
156impl proptest::arbitrary::Arbitrary for ConstantValue {
157 type Parameters = ();
158
159 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
160 use proptest::{arbitrary::any, prop_oneof, strategy::Strategy};
161
162 prop_oneof![
163 any::<IntValue>().prop_map(|n| Self::Int(Span::unknown(n))),
164 any::<Ident>().prop_map(Self::String),
165 any::<WordValue>().prop_map(|word| Self::Word(Span::unknown(word))),
166 any::<(HashKind, Ident)>().prop_map(|(kind, s)| Self::Hash(kind, s)),
167 ]
168 .boxed()
169 }
170
171 type Strategy = proptest::prelude::BoxedStrategy<Self>;
172}