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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Copyright (c) DUSK NETWORK. All rights reserved.

use alloc::string::String;
use alloc::vec::Vec;

use bytecheck::CheckBytes;
use rkyv::{
    ser::serializers::{BufferScratch, BufferSerializer, CompositeSerializer},
    Archive, Deserialize, Serialize,
};

use crate::SCRATCH_BUF_BYTES;

/// And event emitted by a contract.
#[derive(
    Debug,
    Clone,
    PartialEq,
    Eq,
    PartialOrd,
    Ord,
    Hash,
    Archive,
    Serialize,
    Deserialize,
)]
#[archive_attr(derive(CheckBytes))]
pub struct Event {
    pub source: ContractId,
    pub topic: String,
    pub data: Vec<u8>,
}

/// Type with `rkyv` serialization capabilities for specific types.
pub type StandardBufSerializer<'a> = CompositeSerializer<
    BufferSerializer<&'a mut [u8]>,
    BufferScratch<&'a mut [u8; SCRATCH_BUF_BYTES]>,
>;

/// The length of [`ContractId`] in bytes
pub const CONTRACT_ID_BYTES: usize = 32;

/// ID to identify the wasm contracts after they have been deployed
#[derive(
    PartialEq,
    Eq,
    Archive,
    Serialize,
    CheckBytes,
    Deserialize,
    PartialOrd,
    Ord,
    Hash,
    Clone,
    Copy,
)]
#[archive(as = "Self")]
#[repr(C)]
pub struct ContractId([u8; CONTRACT_ID_BYTES]);

impl ContractId {
    /// Creates a placeholder [`ContractId`] until the host deploys the contract
    /// and sets a real [`ContractId`]. This can also be used to determine if a
    /// contract is the first to be called.
    pub const fn uninitialized() -> Self {
        ContractId([0u8; CONTRACT_ID_BYTES])
    }

    /// Creates a new [`ContractId`] from an array of bytes
    pub const fn from_bytes(bytes: [u8; CONTRACT_ID_BYTES]) -> Self {
        Self(bytes)
    }

    /// Returns the array of bytes that make up the [`ContractId`]
    pub const fn to_bytes(self) -> [u8; CONTRACT_ID_BYTES] {
        self.0
    }

    /// Returns a reference to the array of bytes that make up the
    /// [`ContractId`]
    pub fn as_bytes(&self) -> &[u8] {
        &self.0
    }

    /// Returns a mutable reference to the array of bytes that make up the
    /// [`ContractId`]
    pub fn as_bytes_mut(&mut self) -> &mut [u8] {
        &mut self.0
    }

    /// Determines whether the [`ContractId`] is uninitialized, which can be
    /// used to check if this contract is the first to be called.
    pub fn is_uninitialized(&self) -> bool {
        self == &Self::uninitialized()
    }
}

impl From<[u8; CONTRACT_ID_BYTES]> for ContractId {
    fn from(bytes: [u8; CONTRACT_ID_BYTES]) -> Self {
        Self::from_bytes(bytes)
    }
}

impl AsRef<[u8]> for ContractId {
    fn as_ref(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl AsMut<[u8]> for ContractId {
    fn as_mut(&mut self) -> &mut [u8] {
        self.as_bytes_mut()
    }
}

impl core::fmt::Debug for ContractId {
    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
        core::fmt::Display::fmt(self, f)
    }
}

impl core::fmt::Display for ContractId {
    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
        if f.alternate() {
            write!(f, "0x")?
        }
        for byte in self.0 {
            write!(f, "{:02x}", &byte)?
        }
        Ok(())
    }
}