ethcontract/contract/event/
data.rs1use crate::{errors::ExecutionError, tokens::Tokenize};
3use ethcontract_common::abi::{Event as AbiEvent, RawLog as AbiRawLog, Token};
4use web3::types::{Log, H160, H256};
5
6#[derive(Clone, Debug, Eq, PartialEq)]
8pub struct Event<T> {
9 pub data: T,
11 pub meta: Option<EventMetadata>,
15}
16
17pub type StreamEvent<T> = Event<EventStatus<T>>;
22
23#[derive(Clone, Debug, Eq, PartialEq)]
27pub enum EventStatus<T> {
28 Added(T),
30 Removed(T),
32}
33
34impl<T> Event<T> {
35 pub(crate) fn from_past_log<E, F>(log: Log, f: F) -> Result<Self, ExecutionError>
37 where
38 F: FnOnce(RawLog) -> Result<T, E>,
39 ExecutionError: From<E>,
40 {
41 if log.removed == Some(true) {
42 return Err(ExecutionError::RemovedLog(Box::new(log)));
43 }
44
45 let meta = EventMetadata::from_log(&log);
46 let raw = RawLog::from(log);
47 let data = f(raw)?;
48
49 Ok(Event { data, meta })
50 }
51}
52
53impl<T> Event<EventStatus<T>> {
54 pub(crate) fn from_streamed_log<E, F>(log: Log, f: F) -> Result<Self, ExecutionError>
56 where
57 F: FnOnce(RawLog) -> Result<T, E>,
58 ExecutionError: From<E>,
59 {
60 let removed = log.removed == Some(true);
61 let meta = EventMetadata::from_log(&log);
62 let raw = RawLog::from(log);
63 let inner_data = f(raw)?;
64
65 let data = if removed {
66 EventStatus::Removed(inner_data)
67 } else {
68 EventStatus::Added(inner_data)
69 };
70
71 Ok(Event { data, meta })
72 }
73
74 pub fn inner_data(&self) -> &T {
77 match &self.data {
78 EventStatus::Added(value) => value,
79 EventStatus::Removed(value) => value,
80 }
81 }
82
83 pub fn is_added(&self) -> bool {
85 matches!(&self.data, EventStatus::Added(_))
86 }
87
88 pub fn is_removed(&self) -> bool {
90 matches!(&self.data, EventStatus::Removed(_))
91 }
92
93 pub fn added(self) -> Option<T> {
95 match self.data {
96 EventStatus::Added(value) => Some(value),
97 EventStatus::Removed(_) => None,
98 }
99 }
100
101 pub fn removed(self) -> Option<T> {
104 match self.data {
105 EventStatus::Removed(value) => Some(value),
106 EventStatus::Added(_) => None,
107 }
108 }
109
110 pub fn map<U, F>(self, f: F) -> StreamEvent<U>
112 where
113 F: FnOnce(T) -> U,
114 {
115 Event {
116 data: match self.data {
117 EventStatus::Added(inner) => EventStatus::Added(f(inner)),
118 EventStatus::Removed(inner) => EventStatus::Removed(f(inner)),
119 },
120 meta: self.meta,
121 }
122 }
123}
124
125#[derive(Clone, Debug, Default, Eq, PartialEq)]
127pub struct EventMetadata {
128 pub address: H160,
130 pub block_hash: H256,
132 pub block_number: u64,
134 pub transaction_hash: H256,
136 pub transaction_index: usize,
138 pub log_index: usize,
140 pub transaction_log_index: Option<usize>,
143 pub log_type: Option<String>,
146}
147
148impl EventMetadata {
149 fn from_log(log: &Log) -> Option<Self> {
150 Some(EventMetadata {
151 address: log.address,
152 block_hash: log.block_hash?,
153 block_number: log.block_number?.as_u64(),
154 transaction_hash: log.transaction_hash?,
155 transaction_index: log.transaction_index?.as_usize(),
156 log_index: log.log_index?.as_usize(),
157 transaction_log_index: log.transaction_log_index.map(|index| index.as_usize()),
158 log_type: log.log_type.clone(),
159 })
160 }
161}
162
163#[derive(Clone, Debug, Eq, PartialEq)]
165pub struct RawLog {
166 pub topics: Vec<H256>,
168 pub data: Vec<u8>,
170}
171
172impl RawLog {
173 pub fn decode<D>(self, event: &AbiEvent) -> Result<D, ExecutionError>
175 where
176 D: Tokenize,
177 {
178 let event_log = event.parse_log(AbiRawLog {
179 topics: self.topics,
180 data: self.data,
181 })?;
182
183 let tokens = event_log
184 .params
185 .into_iter()
186 .map(|param| param.value)
187 .collect::<Vec<_>>();
188 let data = D::from_token(Token::Tuple(tokens))?;
189
190 Ok(data)
191 }
192}
193
194impl From<Log> for RawLog {
195 fn from(log: Log) -> Self {
196 RawLog {
197 topics: log.topics,
198 data: log.data.0,
199 }
200 }
201}
202
203pub trait ParseLog: Sized + Send + Sync {
206 fn parse_log(log: RawLog) -> Result<Self, ExecutionError>;
208}
209
210impl ParseLog for RawLog {
211 fn parse_log(log: RawLog) -> Result<Self, ExecutionError> {
212 Ok(log)
213 }
214}