use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::Binary;
use super::{Attribute, CosmosMsg, Empty, Event, SubMsg};
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[non_exhaustive]
pub struct Response<T = Empty> {
pub messages: Vec<SubMsg<T>>,
pub attributes: Vec<Attribute>,
pub events: Vec<Event>,
pub data: Option<Binary>,
}
impl<T> Default for Response<T> {
fn default() -> Self {
Response {
messages: vec![],
attributes: vec![],
events: vec![],
data: None,
}
}
}
impl<T> Response<T> {
pub fn new() -> Self {
Self::default()
}
pub fn add_attribute(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
self.attributes.push(Attribute::new(key, value));
self
}
pub fn add_message(mut self, msg: impl Into<CosmosMsg<T>>) -> Self {
self.messages.push(SubMsg::new(msg));
self
}
pub fn add_submessage(mut self, msg: SubMsg<T>) -> Self {
self.messages.push(msg);
self
}
pub fn add_event(mut self, event: Event) -> Self {
self.events.push(event);
self
}
pub fn add_attributes<A: Into<Attribute>>(
mut self,
attrs: impl IntoIterator<Item = A>,
) -> Self {
self.attributes.extend(attrs.into_iter().map(A::into));
self
}
pub fn add_messages<M: Into<CosmosMsg<T>>>(self, msgs: impl IntoIterator<Item = M>) -> Self {
self.add_submessages(msgs.into_iter().map(SubMsg::new))
}
pub fn add_submessages(mut self, msgs: impl IntoIterator<Item = SubMsg<T>>) -> Self {
self.messages.extend(msgs.into_iter());
self
}
pub fn add_events(mut self, events: impl IntoIterator<Item = Event>) -> Self {
self.events.extend(events.into_iter());
self
}
pub fn set_data(mut self, data: impl Into<Binary>) -> Self {
self.data = Some(data.into());
self
}
}
#[cfg(test)]
mod tests {
use super::super::BankMsg;
use super::*;
use crate::results::submessages::{ReplyOn, UNUSED_MSG_ID};
use crate::{coins, from_slice, to_vec, ContractResult};
#[test]
fn response_add_attributes_works() {
let res = Response::<Empty>::new().add_attributes(std::iter::empty::<Attribute>());
assert_eq!(res.attributes.len(), 0);
let res = Response::<Empty>::new().add_attributes([Attribute::new("test", "ing")]);
assert_eq!(res.attributes.len(), 1);
assert_eq!(
res.attributes[0],
Attribute {
key: "test".to_string(),
value: "ing".to_string(),
}
);
let attrs = vec![
("action", "reaction"),
("answer", "42"),
("another", "attribute"),
];
let res: Response = Response::new().add_attributes(attrs.clone());
assert_eq!(res.attributes, attrs);
let optional = Option::<Attribute>::None;
let res: Response = Response::new().add_attributes(optional.into_iter());
assert_eq!(res.attributes.len(), 0);
let optional = Option::<Attribute>::Some(Attribute::new("test", "ing"));
let res: Response = Response::new().add_attributes(optional.into_iter());
assert_eq!(res.attributes.len(), 1);
assert_eq!(
res.attributes[0],
Attribute {
key: "test".to_string(),
value: "ing".to_string(),
}
);
}
#[test]
fn can_serialize_and_deserialize_init_response() {
let original = Response {
messages: vec![
SubMsg {
id: 12,
msg: BankMsg::Send {
to_address: String::from("checker"),
amount: coins(888, "moon"),
}
.into(),
gas_limit: Some(12345u64),
reply_on: ReplyOn::Always,
},
SubMsg {
id: UNUSED_MSG_ID,
msg: BankMsg::Send {
to_address: String::from("you"),
amount: coins(1015, "earth"),
}
.into(),
gas_limit: None,
reply_on: ReplyOn::Never,
},
],
attributes: vec![Attribute {
key: "action".to_string(),
value: "release".to_string(),
}],
events: vec![],
data: Some(Binary::from([0xAA, 0xBB])),
};
let serialized = to_vec(&original).expect("encode contract result");
let deserialized: Response = from_slice(&serialized).expect("decode contract result");
assert_eq!(deserialized, original);
}
#[test]
fn contract_result_is_ok_works() {
let success = ContractResult::<()>::Ok(());
let failure = ContractResult::<()>::Err("broken".to_string());
assert!(success.is_ok());
assert!(!failure.is_ok());
}
#[test]
fn contract_result_is_err_works() {
let success = ContractResult::<()>::Ok(());
let failure = ContractResult::<()>::Err("broken".to_string());
assert!(failure.is_err());
assert!(!success.is_err());
}
}