1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3use thiserror::Error;
4
5use cosmwasm_std::{Addr, CustomQuery, Deps, StdError, StdResult, Storage, SubMsg};
6use cw_storage_plus::Item;
7
8#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, JsonSchema, Debug)]
9pub struct HooksResponse {
10 pub hooks: Vec<String>,
11}
12
13#[derive(Error, Debug, PartialEq)]
14pub enum HookError {
15 #[error("{0}")]
16 Std(#[from] StdError),
17
18 #[error("Given address already registered as a hook")]
19 HookAlreadyRegistered {},
20
21 #[error("Given address not registered as a hook")]
22 HookNotRegistered {},
23}
24
25pub struct Hooks<'a>(Item<'a, Vec<Addr>>);
27
28impl<'a> Hooks<'a> {
29 pub const fn new(storage_key: &'a str) -> Self {
30 Hooks(Item::new(storage_key))
31 }
32
33 pub fn add_hook(&self, storage: &mut dyn Storage, addr: Addr) -> Result<(), HookError> {
34 let mut hooks = self.0.may_load(storage)?.unwrap_or_default();
35 if !hooks.iter().any(|h| h == &addr) {
36 hooks.push(addr);
37 } else {
38 return Err(HookError::HookAlreadyRegistered {});
39 }
40 Ok(self.0.save(storage, &hooks)?)
41 }
42
43 pub fn remove_hook(&self, storage: &mut dyn Storage, addr: Addr) -> Result<(), HookError> {
44 let mut hooks = self.0.load(storage)?;
45 if let Some(p) = hooks.iter().position(|x| x == &addr) {
46 hooks.remove(p);
47 } else {
48 return Err(HookError::HookNotRegistered {});
49 }
50 Ok(self.0.save(storage, &hooks)?)
51 }
52
53 pub fn remove_hook_by_index(
54 &self,
55 storage: &mut dyn Storage,
56 index: u64,
57 ) -> Result<(), HookError> {
58 let mut hooks = self.0.load(storage)?;
59 hooks.remove(index as usize);
60 Ok(self.0.save(storage, &hooks)?)
61 }
62
63 pub fn prepare_hooks<F: FnMut(Addr) -> StdResult<SubMsg>>(
64 &self,
65 storage: &dyn Storage,
66 prep: F,
67 ) -> StdResult<Vec<SubMsg>> {
68 self.0
69 .may_load(storage)?
70 .unwrap_or_default()
71 .into_iter()
72 .map(prep)
73 .collect()
74 }
75
76 pub fn query_hooks<Q: CustomQuery>(&self, deps: Deps<Q>) -> StdResult<HooksResponse> {
77 let hooks = self.0.may_load(deps.storage)?.unwrap_or_default();
78 let hooks = hooks.into_iter().map(String::from).collect();
79 Ok(HooksResponse { hooks })
80 }
81}