thruput_event/lib.rs
1//! Event types for Thruput contracts: the [`Event`] trait that
2//! `#[derive(Event)]` implements, topics ([`Topic`], [`TopicSrc`]), and the
3//! [`EmittedEvent`] and [`TypedEvent`] views of an emitted event.
4//!
5//! Split out of `thruput-sdk` so host-side tooling can decode events without
6//! the SDK. Contracts use the re-exports in `thruput_sdk`.
7
8#![no_std]
9
10mod emitted_event;
11pub use emitted_event::{EmittedEvent, TOPIC_SIZE, TypedEvent};
12
13/// A topic is a fixed-length, opaque 32-byte array.
14pub type Topic = [u8; 32];
15
16/// An `impl Event` publishes each topic as a `TopicSrc` value.
17pub enum TopicSrc<'a> {
18 /// The topic is this owned value.
19 Owned(Topic),
20 /// The topic is available via a reference into the event
21 /// (or a `'static` reference).
22 Shared(&'a Topic),
23}
24
25// A `TopicSrc` can be converted to an owned `Topic`.
26impl<'a> From<TopicSrc<'a>> for Topic {
27 fn from(src: TopicSrc<'a>) -> Topic {
28 match src {
29 TopicSrc::Owned(topic) => topic,
30 TopicSrc::Shared(topic) => *topic,
31 }
32 }
33}
34
35/// Trait implemented by event types that can be emitted by contracts.
36///
37/// Provides the number of topics and their values. Topic 0 is
38/// conventionally the event-type discriminant (e.g. a hash of the
39/// event name). The XDR-serialized payload is everything *after*
40/// the topics in the on-chain representation.
41pub trait Event: xdrs::WriteXDR {
42 /// The decoded payload type. Uses a GAT so it can borrow from
43 /// the input bytes (e.g. `&'a [u8]` fields stay borrowed).
44 type Payload<'a>;
45
46 /// Number of topics this event type carries (0..=3), including the
47 /// signature topic when present.
48 ///
49 /// This is a static property of the type: every emission carries the
50 /// same count, and typed-event matching ([`TypedEvent::try_new`] /
51 /// [`TypedEvent::new`]) rejects a raw event whose `num_topics` differs —
52 /// so a matching topic 0 plus a coincidentally decodable payload cannot
53 /// pass for an `E` emitted with a different topic count.
54 fn num_topics() -> u32
55 where
56 Self: Sized;
57
58 /// The static topic-0 discriminant for this event type, if it has one.
59 ///
60 /// Topic 0 is conventionally the event-type discriminant (see the trait
61 /// docs). Return `Some(sig)` when topic 0 is a fixed per-type constant:
62 /// [`TypedEvent::new`](crate::TypedEvent::new) then rejects a raw event
63 /// whose topic 0 belongs to a different type before trusting the decoded
64 /// payload. Return `None` only when topic 0 is data-dependent (computed
65 /// from payload fields, or absent), which opts out of that check.
66 ///
67 /// This is deliberately not defaulted: a silent `None` would let an impl
68 /// with a fixed discriminant skip the check by omission. `#[derive(Event)]`
69 /// implements it as `Some(Self::SIGNATURE)`.
70 fn signature() -> Option<&'static Topic>
71 where
72 Self: Sized;
73
74 /// Retrieve the topic at the given index.
75 fn topic<'a>(&'a self, index: u32) -> Option<TopicSrc<'a>> {
76 let _ = index;
77 None
78 }
79
80 /// Decode the payload portion of a serialized event.
81 fn decode_payload<'a>(
82 bytes: &'a [u8],
83 ) -> Result<Self::Payload<'a>, xdrs::ReadError>;
84}