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
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
use crate::{
    api::{ErrorApi, ManagedTypeApi, StorageWriteApi},
    err_msg,
    types::{BigInt, BigUint, ManagedBuffer, ManagedBufferCachedBuilder, ManagedInto, ManagedType},
};
use elrond_codec::*;

use super::StorageKey;

struct StorageSetOutput<'k, A>
where
    A: StorageWriteApi + ManagedTypeApi + ErrorApi + 'static,
{
    api: A,
    key: &'k StorageKey<A>,
}

impl<'k, A> StorageSetOutput<'k, A>
where
    A: StorageWriteApi + ManagedTypeApi + ErrorApi + 'static,
{
    #[inline]
    fn new(api: A, key: &'k StorageKey<A>) -> Self {
        StorageSetOutput { api, key }
    }

    fn set_managed_buffer(&self, managed_buffer: &ManagedBuffer<A>) {
        self.api.storage_store_managed_buffer_raw(
            self.key.buffer.get_raw_handle(),
            managed_buffer.handle,
        );
    }
}

impl<'k, A> TopEncodeOutput for StorageSetOutput<'k, A>
where
    A: StorageWriteApi + ManagedTypeApi + ErrorApi + 'static,
{
    type NestedBuffer = ManagedBufferCachedBuilder<A>;

    fn set_slice_u8(self, bytes: &[u8]) {
        self.set_managed_buffer(&bytes.managed_into(self.api.clone()))
    }

    fn set_u64(self, value: u64) {
        using_encoded_number(value, 64, false, true, |bytes| {
            self.set_managed_buffer(&bytes.managed_into(self.api.clone()))
        });
    }

    fn set_i64(self, value: i64) {
        using_encoded_number(value as u64, 64, true, true, |bytes| {
            self.set_managed_buffer(&bytes.managed_into(self.api.clone()))
        });
    }

    #[inline]
    fn set_specialized<T, F>(self, value: &T, else_serialization: F) -> Result<(), EncodeError>
    where
        T: TryStaticCast,
        F: FnOnce(Self) -> Result<(), EncodeError>,
    {
        if let Some(managed_buffer) = value.try_cast_ref::<ManagedBuffer<A>>() {
            self.set_managed_buffer(managed_buffer);
            Ok(())
        } else if let Some(big_uint) = value.try_cast_ref::<BigUint<A>>() {
            self.set_managed_buffer(&big_uint.to_bytes_be_buffer());
            Ok(())
        } else if let Some(big_int) = value.try_cast_ref::<BigInt<A>>() {
            self.set_managed_buffer(&big_int.to_signed_bytes_be_buffer());
            Ok(())
        } else {
            else_serialization(self)
        }
    }

    fn start_nested_encode(&self) -> Self::NestedBuffer {
        ManagedBufferCachedBuilder::new_from_slice(self.api.clone(), &[])
    }

    fn finalize_nested_encode(self, nb: Self::NestedBuffer) {
        self.set_managed_buffer(&nb.into_managed_buffer());
    }
}

// #[inline]
pub fn storage_set<A, T>(api: A, key: &StorageKey<A>, value: &T)
where
    T: TopEncode,
    A: StorageWriteApi + ManagedTypeApi + ErrorApi + Clone + 'static,
{
    value.top_encode_or_exit(
        StorageSetOutput::new(api.clone(), key),
        api,
        storage_set_exit,
    );
}

/// Useful for storage mappers.
/// Also calls to it generated by macro.
pub fn storage_clear<A>(api: A, key: &StorageKey<A>)
where
    A: StorageWriteApi + ManagedTypeApi + ErrorApi + Clone + 'static,
{
    api.storage_store_managed_buffer_clear(key.buffer.get_raw_handle());
}

#[inline(always)]
fn storage_set_exit<A>(api: A, encode_err: EncodeError) -> !
where
    A: StorageWriteApi + ManagedTypeApi + ErrorApi + 'static,
{
    let mut message_buffer =
        ManagedBuffer::new_from_bytes(api.clone(), err_msg::STORAGE_ENCODE_ERROR);
    message_buffer.append_bytes(encode_err.message_bytes());
    api.signal_error_from_buffer(message_buffer.get_raw_handle())
}