1use alloc::{borrow::Cow, string::String};
2use core::fmt::{Display, Formatter};
3
4#[cfg(feature = "serde")]
5use serde::{Deserialize, Serialize};
6use winter_utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable};
7
8use crate::{Felt, utils::hash_string_to_word};
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
25#[cfg_attr(feature = "serde", serde(transparent))]
26#[cfg_attr(
27 all(feature = "arbitrary", test),
28 miden_test_serde_macros::serde_test(winter_serde(true))
29)]
30pub struct EventId(Felt);
31
32impl EventId {
33 pub fn from_name(name: impl AsRef<str>) -> Self {
48 let digest_word = hash_string_to_word(name.as_ref());
49 Self(digest_word[0])
50 }
51
52 pub const fn from_felt(event_id: Felt) -> Self {
54 Self(event_id)
55 }
56
57 pub const fn from_u64(event_id: u64) -> Self {
59 Self(Felt::new(event_id))
60 }
61
62 pub const fn as_felt(&self) -> Felt {
64 self.0
65 }
66
67 pub const fn as_u64(&self) -> u64 {
69 self.0.as_int()
70 }
71}
72
73impl PartialOrd for EventId {
74 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
75 Some(self.cmp(other))
76 }
77}
78
79impl Ord for EventId {
80 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
81 self.0.inner().cmp(&other.0.inner())
82 }
83}
84
85impl core::hash::Hash for EventId {
86 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
87 self.0.inner().hash(state);
88 }
89}
90
91impl Display for EventId {
92 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
93 core::fmt::Display::fmt(&self.0, f)
94 }
95}
96
97#[derive(Debug, Clone, PartialEq, Eq)]
112#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
113#[cfg_attr(feature = "serde", serde(transparent))]
114#[cfg_attr(
115 all(feature = "arbitrary", test),
116 miden_test_serde_macros::serde_test(winter_serde(true))
117)]
118pub struct EventName(Cow<'static, str>);
119
120impl EventName {
121 pub const fn new(name: &'static str) -> Self {
125 Self(Cow::Borrowed(name))
126 }
127
128 pub fn from_string(name: String) -> Self {
132 Self(Cow::Owned(name))
133 }
134
135 pub fn as_str(&self) -> &str {
137 self.0.as_ref()
138 }
139
140 pub fn to_event_id(&self) -> EventId {
144 EventId::from_name(self.as_str())
145 }
146}
147
148impl Display for EventName {
149 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
150 write!(f, "{}", self.0)
151 }
152}
153
154impl AsRef<str> for EventName {
155 fn as_ref(&self) -> &str {
156 self.0.as_ref()
157 }
158}
159
160impl Serializable for EventId {
164 fn write_into<W: ByteWriter>(&self, target: &mut W) {
165 self.0.write_into(target);
166 }
167}
168
169impl Deserializable for EventId {
170 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
171 Ok(Self(Felt::read_from(source)?))
172 }
173}
174
175impl Serializable for EventName {
176 fn write_into<W: ByteWriter>(&self, target: &mut W) {
177 self.0.as_ref().write_into(target)
179 }
180}
181
182impl Deserializable for EventName {
183 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
184 let name = String::read_from(source)?;
185 Ok(Self::from_string(name))
186 }
187}
188
189#[cfg(all(feature = "arbitrary", test))]
190impl proptest::prelude::Arbitrary for EventId {
191 type Parameters = ();
192
193 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
194 use proptest::prelude::*;
195 any::<u64>().prop_map(EventId::from_u64).boxed()
196 }
197
198 type Strategy = proptest::prelude::BoxedStrategy<Self>;
199}
200
201#[cfg(all(feature = "arbitrary", test))]
202impl proptest::prelude::Arbitrary for EventName {
203 type Parameters = ();
204
205 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
206 use proptest::prelude::*;
207
208 prop_oneof![
210 Just(EventName::new("test::static::event")),
212 Just(EventName::new("stdlib::handler::example")),
213 Just(EventName::new("user::custom::event")),
214 any::<(u32, u32)>()
216 .prop_map(|(a, b)| EventName::from_string(format!("dynamic::event::{}::{}", a, b))),
217 ]
218 .boxed()
219 }
220
221 type Strategy = proptest::prelude::BoxedStrategy<Self>;
222}
223
224#[cfg(test)]
228mod tests {
229 use alloc::string::ToString;
230
231 use super::*;
232
233 #[test]
234 fn event_basics() {
235 let id1 = EventId::from_u64(100);
237 assert_eq!(id1.as_u64(), 100);
238 assert_eq!(id1.as_felt(), Felt::new(100));
239
240 let id2 = EventId::from_felt(Felt::new(200));
241 assert_eq!(id2.as_u64(), 200);
242
243 let id3 = EventId::from_name("test::event");
245 let id4 = EventId::from_name("test::event");
246 assert_eq!(id3, id4);
247
248 let name1 = EventName::new("static::event");
250 assert_eq!(name1.as_str(), "static::event");
251 assert_eq!(format!("{}", name1), "static::event");
252
253 let name2 = EventName::from_string("dynamic::event".to_string());
254 assert_eq!(name2.as_str(), "dynamic::event");
255
256 assert_eq!(name1.to_event_id(), EventId::from_name("static::event"));
258 }
259}