Skip to main content

ab_io_type/
lib.rs

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