ab_contracts_io_type/
lib.rs

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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
#![feature(non_null_from_ref)]
#![no_std]

pub mod maybe_data;
pub mod metadata;
pub mod trivial_type;
pub mod variable_bytes;

use crate::trivial_type::TrivialType;
use core::ops::{Deref, DerefMut};
use core::ptr::NonNull;

// Refuse to compile on lower than 32-bit platforms
static_assertions::const_assert!(size_of::<usize>() >= size_of::<u32>());

// Only support little-endian environments, in big-endian byte order will be different, and
// it'll not be possible to simply send bytes of data structures that implement `TrivialType` from
// host to guest environment
static_assertions::const_assert_eq!(u16::from_ne_bytes(1u16.to_le_bytes()), 1u16);

// Only support targets with expected alignment and refuse to compile on other targets
static_assertions::const_assert_eq!(align_of::<()>(), 1);
static_assertions::const_assert_eq!(align_of::<u8>(), 1);
static_assertions::const_assert_eq!(align_of::<u16>(), 2);
static_assertions::const_assert_eq!(align_of::<u32>(), 4);
static_assertions::const_assert_eq!(align_of::<u64>(), 8);
static_assertions::const_assert_eq!(align_of::<u128>(), 16);
static_assertions::const_assert_eq!(align_of::<i8>(), 1);
static_assertions::const_assert_eq!(align_of::<i16>(), 2);
static_assertions::const_assert_eq!(align_of::<i32>(), 4);
static_assertions::const_assert_eq!(align_of::<i64>(), 8);
static_assertions::const_assert_eq!(align_of::<i128>(), 16);

struct DerefWrapper<T>(T);

impl<T> Deref for DerefWrapper<T> {
    type Target = T;

    #[inline]
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<T> DerefMut for DerefWrapper<T> {
    #[inline]
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

// TODO: A way to point output types to input types in order to avoid unnecessary memory copy
//  (setting a pointer)
/// Trait that is used for types that are crossing host/guest boundary in smart contracts.
///
/// Crucially, it is implemented for any type that implements [`TrivialType`] and for
/// [`VariableBytes`](crate::variable_bytes::VariableBytes).
///
/// # Safety
/// This trait is used for types with memory transmutation capabilities, it must not be relied on
/// with untrusted data. Serializing and deserializing of types that implement this trait is simply
/// casting of underlying memory. As a result, all the types implementing this trait must not use
/// implicit padding, unions or anything similar that might make it unsound to access any bits of
/// the type.
///
/// Helper functions are provided to make casting to/from bytes a bit safer than it would otherwise,
/// but extra care is still needed.
///
/// **Do not implement this trait explicitly!** Use `#[derive(TrivialType)]` instead, which will
/// ensure safety requirements are upheld, or use `VariableBytes` if more flexibility is needed.
///
/// In case of variable state size is needed, create a wrapper struct around `VariableBytes` and
/// implement traits on it by forwarding everything to inner implementation.
pub unsafe trait IoType {
    /// Data structure metadata in binary form, describing shape and types of the contents, see
    /// [`IoTypeMetadataKind`] for encoding details
    ///
    /// [`IoTypeMetadataKind`]: crate::metadata::IoTypeMetadataKind
    const METADATA: &[u8];

    /// Pointer with trivial type that this `IoType` represents
    type PointerType: TrivialType;

    /// Number of bytes that are currently used to store data
    fn size(&self) -> u32;

    /// Pointer to the number of bytes that are currently used to store data.
    ///
    /// # Safety
    /// While calling this function is technically safe, it and allows to ignore many of its
    /// invariants, so requires extra care. In particular, no modifications must be done to the
    /// value while this returned pointer might be used and no changes must be done through the
    /// returned pointer. Also, lifetimes are only superficial here and can be easily (and
    /// incorrectly) ignored by using `Copy`.
    unsafe fn size_ptr(&self) -> impl Deref<Target = NonNull<u32>>;

    /// An exclusive pointer to the number of bytes that are currently used to store data.
    ///
    /// NOTE: Pointer might be `null` for [`TrivialType`]s that don't store size internally, in
    /// which case type's capacity should be used as size.
    ///
    /// # Safety
    /// While calling this function is technically safe, it and allows to ignore many of its
    /// invariants, so requires extra care. In particular, the value's contents must not be read or
    /// written to while returned point might be used. Also, lifetimes are only superficial here and
    /// can be easily (and incorrectly) ignored by using `Copy`.
    unsafe fn size_mut_ptr(&mut self) -> impl DerefMut<Target = *mut u32>;

    /// Number of bytes are allocated right now
    fn capacity(&self) -> u32;

    /// Number of bytes are allocated right now
    ///
    /// # Safety
    /// While calling this function is technically safe, it and allows to ignore many of its
    /// invariants, so requires extra care. In particular, no modifications must be done to the
    /// value while this returned pointer might be used and no changes must be done through the
    /// returned pointer. Also, lifetimes are only superficial here and can be easily (and
    /// incorrectly) ignored by using `Copy`.
    unsafe fn capacity_ptr(&self) -> impl Deref<Target = NonNull<u32>>;

    /// Set the number of used bytes
    ///
    /// # Safety
    /// `size` must be set to number of properly initialized bytes
    unsafe fn set_size(&mut self, size: u32);

    /// Create a reference to a type, which is represented by provided memory.
    ///
    /// Memory must be correctly aligned and sufficient in size, but padding beyond the size of the
    /// type is allowed. Memory behind a pointer must not be written to in the meantime either.
    ///
    /// Only `size` are guaranteed to be allocated for types that can store variable amount of
    /// data due to read-only nature of read-only access here.
    ///
    /// # Panics
    /// Panics if `size` is a `null` pointer in case of non-[`TrivialType`]
    ///
    /// # Safety
    /// Input bytes must be previously produced by taking underlying bytes of the same type.
    // `impl Deref` is used to tie lifetime of returned value to inputs, but still treat it as a
    // shared reference for most practical purposes. While lifetime here is somewhat superficial due
    // to `Copy` nature of the value, it must be respected. Size must point to properly initialized
    // memory.
    #[track_caller]
    unsafe fn from_ptr<'a>(
        ptr: &'a NonNull<Self::PointerType>,
        size: &'a u32,
        capacity: u32,
    ) -> impl Deref<Target = Self> + 'a;

    /// Create a mutable reference to a type, which is represented by provided memory.
    ///
    /// Memory must be correctly aligned and sufficient in size or else `None` will be returned, but
    /// padding beyond the size of the type is allowed. Memory behind pointer must not be read or
    /// written to in the meantime either.
    ///
    /// `size` indicates how many bytes are used within larger allocation for types that can
    /// store variable amount of data.
    ///
    /// # Panics
    /// Panics if `size` is a `null` pointer in case of non-[`TrivialType`]
    ///
    /// # Safety
    /// Input bytes must be previously produced by taking underlying bytes of the same type.
    // `impl DerefMut` is used to tie lifetime of returned value to inputs, but still treat it as an
    // exclusive reference for most practical purposes. While lifetime here is somewhat superficial
    // due to `Copy` nature of the value, it must be respected. Size must point to properly
    // initialized memory for non-[`TrivialType`].
    #[track_caller]
    unsafe fn from_mut_ptr<'a>(
        ptr: &'a mut NonNull<Self::PointerType>,
        size: &'a mut *mut u32,
        capacity: u32,
    ) -> impl DerefMut<Target = Self> + 'a;

    /// Get a raw pointer to the underlying data with no checks.
    ///
    /// # Safety
    /// While calling this function is technically safe, it and allows to ignore many of its
    /// invariants, so requires extra care. In particular, no modifications must be done to the
    /// value while this returned pointer might be used and no changes must be done through the
    /// returned pointer. Also, lifetimes are only superficial here and can be easily (and
    /// incorrectly) ignored by using `Copy`.
    unsafe fn as_ptr(&self) -> impl Deref<Target = NonNull<Self::PointerType>>;

    /// Get an exclusive raw pointer to the underlying data with no checks.
    ///
    /// # Safety
    /// While calling this function is technically safe, it and allows to ignore many of its
    /// invariants, so requires extra care. In particular, the value's contents must not be read or
    /// written to while returned point might be used. Also, lifetimes are only superficial here and
    /// can be easily (and incorrectly) ignored by using `Copy`.
    unsafe fn as_mut_ptr(&mut self) -> impl DerefMut<Target = NonNull<Self::PointerType>>;
}

/// Marker trait, companion to [`IoType`] that indicates ability to store optional contents
pub trait IoTypeOptional: IoType {}