cosmwasm_std/results/
events.rs1use crate::__internal::forward_ref_partial_eq;
2use schemars::JsonSchema;
3use serde::{Deserialize, Serialize};
4
5use crate::prelude::*;
6
7#[derive(
16 Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, cw_schema::Schemaifier,
17)]
18#[non_exhaustive]
19pub struct Event {
20 #[serde(rename = "type")]
22 pub ty: String,
23 pub attributes: Vec<Attribute>,
29}
30
31forward_ref_partial_eq!(Event, Event);
32
33impl Event {
34 pub fn new(ty: impl Into<String>) -> Self {
36 Event {
37 ty: ty.into(),
38 attributes: Vec::with_capacity(10),
39 }
40 }
41
42 pub fn add_attribute(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
44 self.attributes.push(Attribute {
45 key: key.into(),
46 value: value.into(),
47 });
48 self
49 }
50
51 pub fn add_attributes<A: Into<Attribute>>(
56 mut self,
57 attrs: impl IntoIterator<Item = A>,
58 ) -> Self {
59 self.attributes.extend(attrs.into_iter().map(A::into));
60 self
61 }
62}
63
64#[derive(
66 Serialize, Deserialize, Clone, Default, Debug, PartialEq, Eq, JsonSchema, cw_schema::Schemaifier,
67)]
68pub struct Attribute {
69 pub key: String,
70 pub value: String,
71}
72
73forward_ref_partial_eq!(Attribute, Attribute);
74
75impl Attribute {
76 pub fn new(key: impl Into<String>, value: impl Into<String>) -> Self {
78 let key = key.into();
79
80 #[cfg(debug_assertions)]
81 if key.starts_with('_') {
82 panic!(
83 "attribute key `{key}` is invalid - keys starting with an underscore are reserved"
84 );
85 }
86
87 Self {
88 key,
89 value: value.into(),
90 }
91 }
92}
93
94impl<K: Into<String>, V: Into<String>> From<(K, V)> for Attribute {
95 fn from((k, v): (K, V)) -> Self {
96 Attribute::new(k, v)
97 }
98}
99
100impl<K: AsRef<str>, V: AsRef<str>> PartialEq<(K, V)> for Attribute {
101 fn eq(&self, (k, v): &(K, V)) -> bool {
102 (self.key.as_str(), self.value.as_str()) == (k.as_ref(), v.as_ref())
103 }
104}
105
106impl<K: AsRef<str>, V: AsRef<str>> PartialEq<Attribute> for (K, V) {
107 fn eq(&self, attr: &Attribute) -> bool {
108 attr == self
109 }
110}
111
112impl<K: AsRef<str>, V: AsRef<str>> PartialEq<(K, V)> for &Attribute {
113 fn eq(&self, (k, v): &(K, V)) -> bool {
114 (self.key.as_str(), self.value.as_str()) == (k.as_ref(), v.as_ref())
115 }
116}
117
118impl<K: AsRef<str>, V: AsRef<str>> PartialEq<&Attribute> for (K, V) {
119 fn eq(&self, attr: &&Attribute) -> bool {
120 attr == self
121 }
122}
123
124#[inline]
126pub fn attr(key: impl Into<String>, value: impl Into<String>) -> Attribute {
127 Attribute::new(key, value)
128}
129
130#[cfg(test)]
131mod tests {
132 use super::*;
133 use crate::Uint128;
134
135 #[test]
136 fn event_construction() {
137 let event_direct = Event {
138 ty: "test".to_string(),
139 attributes: vec![attr("foo", "bar"), attr("bar", "baz")],
140 };
141 let event_builder = Event::new("test").add_attributes(vec![("foo", "bar"), ("bar", "baz")]);
142
143 assert_eq!(event_direct, event_builder);
144 }
145
146 #[test]
147 #[should_panic]
148 fn attribute_new_reserved_key_panicks() {
149 Attribute::new("_invalid", "value");
150 }
151
152 #[test]
153 #[should_panic]
154 fn attribute_new_reserved_key_panicks2() {
155 Attribute::new("_", "value");
156 }
157
158 #[test]
159 fn attr_works_for_different_types() {
160 let expected = ("foo", "42");
161
162 assert_eq!(attr("foo", "42"), expected);
163 assert_eq!(attr("foo", "42"), expected);
164 assert_eq!(attr("foo", "42"), expected);
165 assert_eq!(attr("foo", Uint128::new(42)), expected);
166 }
167}