1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
use core::fmt::Debug;
#[cfg(doc)]
use crate::{contracttype, Bytes, BytesN, Map};
use crate::{env::internal, Env, IntoVal, RawVal, Vec};
// TODO: consolidate with host::events::TOPIC_BYTES_LENGTH_LIMIT
const TOPIC_BYTES_LENGTH_LIMIT: u32 = 32;
/// Events publishes events for the currently executing contract.
///
/// ```
/// use soroban_sdk::Env;
///
/// # use soroban_sdk::{contractimpl, vec, map, RawVal, BytesN};
/// #
/// # pub struct Contract;
/// #
/// # #[contractimpl]
/// # impl Contract {
/// # pub fn f(env: Env) {
/// let event = env.events();
/// let data = map![&env, (1u32, 2u32)];
/// let topics0 = ();
/// let topics1 = (0u32,);
/// let topics2 = (0u32, 1u32);
/// let topics3 = (0u32, 1u32, 2u32);
/// let topics4 = (0u32, 1u32, 2u32, 3u32);
/// event.publish(topics0, data.clone());
/// event.publish(topics1, data.clone());
/// event.publish(topics2, data.clone());
/// event.publish(topics3, data.clone());
/// event.publish(topics4, data.clone());
/// # }
/// # }
///
/// # #[cfg(feature = "testutils")]
/// # fn main() {
/// # let env = Env::default();
/// # let contract_id = BytesN::from_array(&env, &[0; 32]);
/// # env.register_contract(&contract_id, Contract);
/// # f::invoke(&env, &contract_id);
/// # }
/// # #[cfg(not(feature = "testutils"))]
/// # fn main() { }
/// ```
#[derive(Clone)]
pub struct Events(Env);
impl Debug for Events {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "Events")
}
}
pub trait Topics: IntoVal<Env, Vec<RawVal>> {}
impl IntoVal<Env, Vec<RawVal>> for () {
fn into_val(self, env: &Env) -> Vec<RawVal> {
Vec::<RawVal>::new(env)
}
}
macro_rules! impl_topics_for_tuple {
( $($typ:ident $idx:tt)* ) => {
impl<$($typ),*> Topics for ($($typ,)*)
where
$($typ: IntoVal<Env, RawVal>),*
{
}
};
}
// 0 topics
impl Topics for () {}
// 1-4 topics
impl_topics_for_tuple! { T0 0 }
impl_topics_for_tuple! { T0 0 T1 1 }
impl_topics_for_tuple! { T0 0 T1 1 T2 2 }
impl_topics_for_tuple! { T0 0 T1 1 T2 2 T3 3 }
impl Events {
#[inline(always)]
pub(crate) fn env(&self) -> &Env {
&self.0
}
#[inline(always)]
pub(crate) fn new(env: &Env) -> Events {
Events(env.clone())
}
/// Publish an event.
///
/// Event data is specified in `data`. Data may be any value or
/// type, including types defined by contracts using [contracttype].
///
/// Event topics must not contain:
///
/// - [Vec]
/// - [Map]
/// - [Bytes]/[BytesN] longer than 32 bytes
/// - [contracttype]
#[inline(always)]
pub fn publish<T, D>(&self, topics: T, data: D)
where
T: Topics,
D: IntoVal<Env, RawVal>,
{
let env = self.env();
internal::Env::contract_event(env, topics.into_val(env).to_object(), data.into_val(env));
}
}