ab_io_type/
lib.rs

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