ab_io_type/
lib.rs

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