use alloc::{borrow::Cow, string::String};
use core::fmt::{Display, Formatter};
use miden_crypto::{
field::PrimeField64,
utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::{Felt, utils::hash_string_to_word};
mod sys_events;
pub use sys_events::SystemEvent;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
#[cfg_attr(
all(feature = "arbitrary", test),
miden_test_serde_macros::serde_test(binary_serde(true))
)]
pub struct EventId(u64);
impl EventId {
pub fn from_name(name: impl AsRef<str>) -> Self {
let digest_word = hash_string_to_word(name.as_ref());
Self(digest_word[0].as_canonical_u64())
}
pub fn from_felt(event_id: Felt) -> Self {
Self(event_id.as_canonical_u64())
}
pub const fn from_u64(event_id: u64) -> Self {
Self(event_id % Felt::ORDER_U64)
}
pub const fn as_felt(&self) -> Felt {
Felt::new(self.0)
}
pub const fn as_u64(&self) -> u64 {
self.0
}
}
impl Display for EventId {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
core::fmt::Display::fmt(&self.0, f)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
#[cfg_attr(
all(feature = "arbitrary", test),
miden_test_serde_macros::serde_test(binary_serde(true))
)]
pub struct EventName(Cow<'static, str>);
impl EventName {
pub const fn new(name: &'static str) -> Self {
Self(Cow::Borrowed(name))
}
pub fn from_string(name: String) -> Self {
Self(Cow::Owned(name))
}
pub fn as_str(&self) -> &str {
self.0.as_ref()
}
pub fn to_event_id(&self) -> EventId {
EventId::from_name(self.as_str())
}
}
impl Display for EventName {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", self.0)
}
}
impl AsRef<str> for EventName {
fn as_ref(&self) -> &str {
self.0.as_ref()
}
}
impl Serializable for EventId {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
self.as_felt().write_into(target);
}
}
impl Deserializable for EventId {
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
Ok(Self(Felt::read_from(source)?.as_canonical_u64()))
}
}
impl Serializable for EventName {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
self.0.as_ref().write_into(target)
}
}
impl Deserializable for EventName {
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
let name = String::read_from(source)?;
Ok(Self::from_string(name))
}
}
#[cfg(all(feature = "arbitrary", test))]
impl proptest::prelude::Arbitrary for EventId {
type Parameters = ();
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
use proptest::prelude::*;
any::<u64>().prop_map(EventId::from_u64).boxed()
}
type Strategy = proptest::prelude::BoxedStrategy<Self>;
}
#[cfg(all(feature = "arbitrary", test))]
impl proptest::prelude::Arbitrary for EventName {
type Parameters = ();
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
use proptest::prelude::*;
prop_oneof![
Just(EventName::new("test::static::event")),
Just(EventName::new("core::handler::example")),
Just(EventName::new("user::custom::event")),
any::<(u32, u32)>()
.prop_map(|(a, b)| EventName::from_string(format!("dynamic::event::{}::{}", a, b))),
]
.boxed()
}
type Strategy = proptest::prelude::BoxedStrategy<Self>;
}
#[cfg(test)]
mod tests {
use alloc::string::ToString;
use super::*;
#[test]
fn event_basics() {
let id1 = EventId::from_u64(100);
assert_eq!(id1.as_u64(), 100);
assert_eq!(id1.as_felt(), Felt::new(100));
let id2 = EventId::from_felt(Felt::new(200));
assert_eq!(id2.as_u64(), 200);
let id3 = EventId::from_name("test::event");
let id4 = EventId::from_name("test::event");
assert_eq!(id3, id4);
let name1 = EventName::new("static::event");
assert_eq!(name1.as_str(), "static::event");
assert_eq!(format!("{}", name1), "static::event");
let name2 = EventName::from_string("dynamic::event".to_string());
assert_eq!(name2.as_str(), "dynamic::event");
assert_eq!(name1.to_event_id(), EventId::from_name("static::event"));
}
}