ab_contracts_io_type/lib.rs
1#![feature(maybe_uninit_slice, non_null_from_ref)]
2#![no_std]
3
4pub mod maybe_data;
5pub mod metadata;
6pub mod trivial_type;
7pub mod variable_bytes;
8pub mod variable_elements;
9
10use crate::trivial_type::TrivialType;
11use core::ops::{Deref, DerefMut};
12use core::ptr::NonNull;
13
14/// The maximum alignment supported by [`IoType`] types (16 bytes, corresponds to alignment of
15/// `u128`)
16pub const MAX_ALIGNMENT: u8 = 16;
17
18const _: () = {
19 assert!(
20 size_of::<usize>() >= size_of::<u32>(),
21 "At least 32-bit platform required"
22 );
23
24 // Only support little-endian environments, in big-endian byte order will be different, and
25 // it'll not be possible to simply send bytes of data structures that implement `TrivialType`
26 // from host to guest environment
27 assert!(
28 u16::from_ne_bytes(1u16.to_le_bytes()) == 1u16,
29 "Only little-endian platform supported"
30 );
31
32 // Max alignment is expected to match that of `u128`
33 assert!(
34 align_of::<u128>() == MAX_ALIGNMENT as usize,
35 "Max alignment mismatch"
36 );
37
38 // Only support targets with expected alignment and refuse to compile on other targets
39 assert!(align_of::<()>() == 1, "Unsupported alignment of `()`");
40 assert!(align_of::<u8>() == 1, "Unsupported alignment of `u8`");
41 assert!(align_of::<u16>() == 2, "Unsupported alignment of `u16`");
42 assert!(align_of::<u32>() == 4, "Unsupported alignment of `u32`");
43 assert!(align_of::<u64>() == 8, "Unsupported alignment of `u64`");
44 assert!(align_of::<u128>() == 16, "Unsupported alignment of `u128`");
45 assert!(align_of::<i8>() == 1, "Unsupported alignment of `i8`");
46 assert!(align_of::<i16>() == 2, "Unsupported alignment of `i16`");
47 assert!(align_of::<i32>() == 4, "Unsupported alignment of `i32`");
48 assert!(align_of::<i64>() == 8, "Unsupported alignment of `i64`");
49 assert!(align_of::<i128>() == 16, "Unsupported alignment of `i128`");
50};
51
52struct DerefWrapper<T>(T);
53
54impl<T> Deref for DerefWrapper<T> {
55 type Target = T;
56
57 #[inline(always)]
58 fn deref(&self) -> &Self::Target {
59 &self.0
60 }
61}
62
63impl<T> DerefMut for DerefWrapper<T> {
64 #[inline(always)]
65 fn deref_mut(&mut self) -> &mut Self::Target {
66 &mut self.0
67 }
68}
69
70// TODO: A way to point output types to input types in order to avoid unnecessary memory copy
71// (setting a pointer)
72/// Trait that is used for types that are crossing host/guest boundary in contracts.
73///
74/// Crucially, it is implemented for any type that implements [`TrivialType`] and for
75/// [`VariableBytes`](crate::variable_bytes::VariableBytes).
76///
77/// # Safety
78/// This trait is used for types with memory transmutation capabilities, it must not be relied on
79/// with untrusted data. Serializing and deserializing of types that implement this trait is simply
80/// casting of underlying memory. As a result, all the types implementing this trait must not use
81/// implicit padding, unions or anything similar that might make it unsound to access any bits of
82/// the type.
83///
84/// Helper functions are provided to make casting to/from bytes a bit safer than it would otherwise,
85/// but extra care is still needed.
86///
87/// **Do not implement this trait explicitly!** Use `#[derive(TrivialType)]` instead, which will
88/// ensure safety requirements are upheld, or use `VariableBytes` if more flexibility is needed.
89///
90/// In case of variable state size is needed, create a wrapper struct around `VariableBytes` and
91/// implement traits on it by forwarding everything to inner implementation.
92pub unsafe trait IoType {
93 /// Data structure metadata in binary form, describing shape and types of the contents, see
94 /// [`IoTypeMetadataKind`] for encoding details
95 ///
96 /// [`IoTypeMetadataKind`]: crate::metadata::IoTypeMetadataKind
97 const METADATA: &[u8];
98
99 /// Pointer with trivial type that this `IoType` represents
100 type PointerType: TrivialType;
101
102 /// Number of bytes that are currently used to store data
103 fn size(&self) -> u32;
104
105 /// Pointer to the number of bytes that are currently used to store data.
106 ///
107 /// # Safety
108 /// While calling this function is technically safe, it and allows to ignore many of its
109 /// invariants, so requires extra care. In particular, no modifications must be done to the
110 /// value while this returned pointer might be used and no changes must be done through the
111 /// returned pointer. Also, lifetimes are only superficial here and can be easily (and
112 /// incorrectly) ignored by using `Copy`.
113 unsafe fn size_ptr(&self) -> impl Deref<Target = NonNull<u32>>;
114
115 /// An exclusive pointer to the number of bytes that are currently used to store data.
116 ///
117 /// NOTE: Pointer might be `null` for [`TrivialType`]s that don't store size internally, in
118 /// which case type's capacity should be used as size.
119 ///
120 /// # Safety
121 /// While calling this function is technically safe, it and allows to ignore many of its
122 /// invariants, so requires extra care. In particular, the value's contents must not be read or
123 /// written to while returned point might be used. Also, lifetimes are only superficial here and
124 /// can be easily (and incorrectly) ignored by using `Copy`.
125 unsafe fn size_mut_ptr(&mut self) -> impl DerefMut<Target = *mut u32>;
126
127 /// Number of bytes are allocated right now
128 fn capacity(&self) -> u32;
129
130 /// Number of bytes are allocated right now
131 ///
132 /// # Safety
133 /// While calling this function is technically safe, it and allows to ignore many of its
134 /// invariants, so requires extra care. In particular, no modifications must be done to the
135 /// value while this returned pointer might be used and no changes must be done through the
136 /// returned pointer. Also, lifetimes are only superficial here and can be easily (and
137 /// incorrectly) ignored by using `Copy`.
138 unsafe fn capacity_ptr(&self) -> impl Deref<Target = NonNull<u32>>;
139
140 /// Set the number of used bytes
141 ///
142 /// # Safety
143 /// `size` must be set to number of properly initialized bytes
144 unsafe fn set_size(&mut self, size: u32);
145
146 /// Create a reference to a type, which is represented by provided memory.
147 ///
148 /// Memory must be correctly aligned and sufficient in size, but padding beyond the size of the
149 /// type is allowed. Memory behind a pointer must not be written to in the meantime either.
150 ///
151 /// Only `size` are guaranteed to be allocated for types that can store variable amount of
152 /// data due to read-only nature of read-only access here.
153 ///
154 /// # Panics
155 /// Panics if `size` is a `null` pointer in case of non-[`TrivialType`]
156 ///
157 /// # Safety
158 /// Input bytes must be previously produced by taking underlying bytes of the same type.
159 // `impl Deref` is used to tie lifetime of returned value to inputs, but still treat it as a
160 // shared reference for most practical purposes. While lifetime here is somewhat superficial due
161 // to `Copy` nature of the value, it must be respected. Size must point to properly initialized
162 // memory.
163 #[track_caller]
164 unsafe fn from_ptr<'a>(
165 ptr: &'a NonNull<Self::PointerType>,
166 size: &'a u32,
167 capacity: u32,
168 ) -> impl Deref<Target = Self> + 'a;
169
170 /// Create a mutable reference to a type, which is represented by provided memory.
171 ///
172 /// Memory must be correctly aligned and sufficient in size or else `None` will be returned, but
173 /// padding beyond the size of the type is allowed. Memory behind a pointer must not be read or
174 /// written to in the meantime either.
175 ///
176 /// `size` indicates how many bytes are used within larger allocation for types that can
177 /// store variable amount of data.
178 ///
179 /// # Panics
180 /// Panics if `size` is a `null` pointer in case of non-[`TrivialType`]
181 ///
182 /// # Safety
183 /// Input bytes must be previously produced by taking underlying bytes of the same type.
184 // `impl DerefMut` is used to tie lifetime of returned value to inputs, but still treat it as an
185 // exclusive reference for most practical purposes. While lifetime here is somewhat superficial
186 // due to `Copy` nature of the value, it must be respected. Size must point to properly
187 // initialized memory for non-[`TrivialType`].
188 #[track_caller]
189 unsafe fn from_mut_ptr<'a>(
190 ptr: &'a mut NonNull<Self::PointerType>,
191 size: &'a mut *mut u32,
192 capacity: u32,
193 ) -> impl DerefMut<Target = Self> + 'a;
194
195 /// Get a raw pointer to the underlying data with no checks.
196 ///
197 /// # Safety
198 /// While calling this function is technically safe, it and allows to ignore many of its
199 /// invariants, so requires extra care. In particular, no modifications must be done to the
200 /// value while this returned pointer might be used and no changes must be done through the
201 /// returned pointer. Also, lifetimes are only superficial here and can be easily (and
202 /// incorrectly) ignored by using `Copy`.
203 unsafe fn as_ptr(&self) -> impl Deref<Target = NonNull<Self::PointerType>>;
204
205 /// Get an exclusive raw pointer to the underlying data with no checks.
206 ///
207 /// # Safety
208 /// While calling this function is technically safe, it and allows to ignore many of its
209 /// invariants, so requires extra care. In particular, the value's contents must not be read or
210 /// written to while returned point might be used. Also, lifetimes are only superficial here and
211 /// can be easily (and incorrectly) ignored by using `Copy`.
212 unsafe fn as_mut_ptr(&mut self) -> impl DerefMut<Target = NonNull<Self::PointerType>>;
213}
214
215/// Marker trait, companion to [`IoType`] that indicates the ability to store optional contents
216pub trait IoTypeOptional: IoType {}