ab_io_type/
unaligned.rs

1use crate::metadata::{IoTypeMetadataKind, MAX_METADATA_CAPACITY, concat_metadata_sources};
2use crate::trivial_type::TrivialType;
3use core::fmt;
4#[cfg(feature = "scale-codec")]
5use parity_scale_codec::{Decode, Encode, EncodeLike, MaxEncodedLen, Output};
6#[cfg(feature = "scale-codec")]
7use scale_info::TypeInfo;
8#[cfg(feature = "serde")]
9use serde::{Deserialize, Serialize, Serializer};
10
11/// Wrapper type for `Data` that is the same size, but doesn't need to be aligned/has alignment of
12/// one byte.
13///
14/// This is similar to `#[repr(packed)]`, but makes sure to only expose safe API when dealing with
15/// the contents. For example, if `Data` is unaligned and has fields, it is not sounds having
16/// references to its fields. This data structure prevents such invalid invariants.
17#[derive(Debug, Default, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
18#[cfg_attr(feature = "scale-codec", derive(Decode, MaxEncodedLen, TypeInfo))]
19#[cfg_attr(feature = "serde", derive(Deserialize))]
20#[cfg_attr(feature = "serde", serde(transparent))]
21#[repr(C, packed)]
22pub struct Unaligned<Data>(Data)
23where
24    Data: TrivialType;
25
26impl<Data> From<Data> for Unaligned<Data>
27where
28    Data: TrivialType,
29{
30    #[inline(always)]
31    fn from(value: Data) -> Self {
32        Self(value)
33    }
34}
35
36impl<Data> fmt::Display for Unaligned<Data>
37where
38    Data: TrivialType + fmt::Display,
39{
40    #[inline]
41    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42        let inner = self.0;
43        inner.fmt(f)
44    }
45}
46
47// SAFETY: Any bit pattern is valid, so it is safe to implement `TrivialType` for this type
48unsafe impl<Data> TrivialType for Unaligned<Data>
49where
50    Data: TrivialType,
51{
52    const METADATA: &[u8] = {
53        const fn metadata(inner_metadata: &[u8]) -> ([u8; MAX_METADATA_CAPACITY], usize) {
54            concat_metadata_sources(&[&[IoTypeMetadataKind::Unaligned as u8], inner_metadata])
55        }
56
57        // Strange syntax to allow Rust to extend the lifetime of metadata scratch automatically
58        metadata(Data::METADATA)
59            .0
60            .split_at(metadata(Data::METADATA).1)
61            .0
62    };
63}
64
65#[cfg(feature = "scale-codec")]
66impl<Data> Encode for Unaligned<Data>
67where
68    Data: TrivialType + Encode,
69{
70    #[inline(always)]
71    fn size_hint(&self) -> usize {
72        let inner = self.0;
73        inner.size_hint()
74    }
75
76    #[inline(always)]
77    fn encode_to<T: Output + ?Sized>(&self, dest: &mut T) {
78        let inner = self.0;
79        inner.encode_to(dest)
80    }
81
82    #[inline(always)]
83    fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
84        let inner = self.0;
85        inner.using_encoded(f)
86    }
87}
88
89#[cfg(feature = "scale-codec")]
90impl<Data> EncodeLike for Unaligned<Data> where Data: TrivialType + Encode {}
91
92#[cfg(feature = "serde")]
93impl<Data> Serialize for Unaligned<Data>
94where
95    Data: TrivialType + Serialize,
96{
97    #[inline(always)]
98    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
99    where
100        S: Serializer,
101    {
102        let inner = self.0;
103        inner.serialize(serializer)
104    }
105}
106
107impl<Data> Unaligned<Data>
108where
109    Data: TrivialType,
110{
111    /// Create a new instance
112    #[inline(always)]
113    pub const fn new(inner: Data) -> Self {
114        Self(inner)
115    }
116
117    /// Get inner value
118    #[inline(always)]
119    pub const fn as_inner(&self) -> Data {
120        self.0
121    }
122
123    /// Replace inner value
124    pub const fn replace(&mut self, value: Data) {
125        self.0 = value;
126    }
127}