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