use core::fmt::Debug;
#[cfg(doc)]
use crate::{contracttype, Bytes, Map};
use crate::{env::internal, unwrap::UnwrapInfallible, Env, IntoVal, Val, Vec};
const TOPIC_BYTES_LENGTH_LIMIT: u32 = 32;
#[derive(Clone)]
pub struct Events(Env);
impl Debug for Events {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "Events")
}
}
#[cfg(any(test, feature = "testutils"))]
use crate::{testutils, xdr, FromVal};
pub trait Event {
fn topics(&self, env: &Env) -> Vec<Val>;
fn data(&self, env: &Env) -> Val;
fn publish(&self, env: &Env) {
env.events().publish_event(self);
}
#[cfg(any(test, feature = "testutils"))]
fn to_xdr(&self, env: &Env, contract_id: &crate::Address) -> xdr::ContractEvent {
xdr::ContractEvent {
ext: xdr::ExtensionPoint::V0,
type_: xdr::ContractEventType::Contract,
contract_id: Some(contract_id.contract_id()),
body: xdr::ContractEventBody::V0(xdr::ContractEventV0 {
topics: self.topics(env).into(),
data: xdr::ScVal::from_val(env, &self.data(env)),
}),
}
}
}
pub trait Topics: IntoVal<Env, Vec<Val>> {}
impl<T> Topics for Vec<T> {}
impl Events {
#[inline(always)]
pub(crate) fn env(&self) -> &Env {
&self.0
}
#[inline(always)]
pub(crate) fn new(env: &Env) -> Events {
Events(env.clone())
}
#[inline(always)]
pub fn publish_event(&self, e: &(impl Event + ?Sized)) {
let env = self.env();
internal::Env::contract_event(env, e.topics(env).to_object(), e.data(env))
.unwrap_infallible();
}
#[deprecated(note = "use the #[contractevent] macro on a contract event type")]
#[inline(always)]
pub fn publish<T, D>(&self, topics: T, data: D)
where
T: Topics,
D: IntoVal<Env, Val>,
{
let env = self.env();
internal::Env::contract_event(env, topics.into_val(env).to_object(), data.into_val(env))
.unwrap_infallible();
}
}
#[cfg(any(test, feature = "testutils"))]
#[cfg_attr(feature = "docs", doc(cfg(feature = "testutils")))]
impl testutils::Events for Events {
fn all(&self) -> testutils::ContractEvents {
let env = self.env();
let vec: std::vec::Vec<xdr::ContractEvent> = self
.env()
.host()
.get_events()
.unwrap()
.0
.into_iter()
.filter_map(|e| {
if !e.failed_call
&& e.event.type_ == xdr::ContractEventType::Contract
&& e.event.contract_id.is_some()
{
Some(e.event)
} else {
None
}
})
.collect();
testutils::ContractEvents::new(&env, vec)
}
}