1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
use cosmwasm_std::{Addr, Api, StdResult};

/// A type representing a value that can either be cleared or set with a value of type `C`.
/// ```
/// use cosmwasm_std::{StdResult, Response, DepsMut};
/// use cw_storage_plus::Item;
/// use cw_clearable::Clearable;
///
/// const FOO: Item<Option<u32>> = Item::new("foo");
///
/// pub fn update_config(deps: DepsMut, foo: Option<Clearable<u32>>) -> StdResult<Response>{
///     if let Some(foo) = foo {
///         FOO.save(deps.storage, &foo.into());
///     }
///     Ok(Response::new())
/// }
/// ```
#[cosmwasm_schema::cw_serde]
pub enum Clearable<C> {
    /// Clear the current state.
    Clear,
    /// Set state with a value of type `C`.
    Set(C),
}

impl<C> Clearable<C> {
    pub fn new(value: C) -> Clearable<C> {
        Clearable::Set(value)
    }

    pub fn new_opt(value: C) -> Option<Clearable<C>> {
        Some(Clearable::Set(value))
    }
}

impl Clearable<String> {
    pub fn check(&self, api: &dyn Api) -> StdResult<Clearable<Addr>> {
        match self {
            Clearable::Clear => Ok(Clearable::Clear),
            Clearable::Set(human) => Ok(Clearable::Set(api.addr_validate(human)?)),
        }
    }
}

// Get new value for this item
impl<C> Into<Option<C>> for Clearable<C> {
    fn into(self) -> Option<C> {
        match self {
            Clearable::Clear => None,
            Clearable::Set(val) => Some(val),
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use cosmwasm_std::testing::MockStorage;
    use cw_storage_plus::Item;

    const FOO: Item<Option<u32>> = Item::new("foo");

    #[test]
    fn clear() {
        let mut storage = MockStorage::new();
        FOO.save(&mut storage, &Some(0u32)).unwrap();

        let clearable: Clearable<u32> = Clearable::Clear;
        FOO.save(&mut storage, &clearable.into()).unwrap();

        let foo = FOO.load(&storage).unwrap();
        assert_eq!(foo, None);
    }

    #[test]
    fn set() {
        let mut storage = MockStorage::new();
        FOO.save(&mut storage, &Some(0u32)).unwrap();

        let clearable: Clearable<u32> = Clearable::Set(42);
        FOO.save(&mut storage, &clearable.into()).unwrap();

        let foo = FOO.load(&storage).unwrap();
        assert_eq!(foo, Some(42));
    }

    #[test]
    fn constructors() {
        let clearable_new = Clearable::new(5u32);
        assert_eq!(clearable_new, Clearable::Set(5u32));

        let clearable_new_opt = Clearable::new_opt(6u32);
        assert_eq!(clearable_new_opt, Some(Clearable::Set(6u32)))
    }
}