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