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
47unsafe impl<Data> TrivialType for Unaligned<Data>
48where
49    Data: TrivialType,
50{
51    const METADATA: &[u8] = {
52        const fn metadata(inner_metadata: &[u8]) -> ([u8; MAX_METADATA_CAPACITY], usize) {
53            concat_metadata_sources(&[&[IoTypeMetadataKind::Unaligned as u8], inner_metadata])
54        }
55
56        // Strange syntax to allow Rust to extend the lifetime of metadata scratch automatically
57        metadata(Data::METADATA)
58            .0
59            .split_at(metadata(Data::METADATA).1)
60            .0
61    };
62}
63
64#[cfg(feature = "scale-codec")]
65impl<Data> Encode for Unaligned<Data>
66where
67    Data: TrivialType + Encode,
68{
69    #[inline(always)]
70    fn size_hint(&self) -> usize {
71        let inner = self.0;
72        inner.size_hint()
73    }
74
75    #[inline(always)]
76    fn encode_to<T: Output + ?Sized>(&self, dest: &mut T) {
77        let inner = self.0;
78        inner.encode_to(dest)
79    }
80
81    #[inline(always)]
82    fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
83        let inner = self.0;
84        inner.using_encoded(f)
85    }
86}
87
88#[cfg(feature = "scale-codec")]
89impl<Data> EncodeLike for Unaligned<Data> where Data: TrivialType + Encode {}
90
91#[cfg(feature = "serde")]
92impl<Data> Serialize for Unaligned<Data>
93where
94    Data: TrivialType + Serialize,
95{
96    #[inline(always)]
97    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
98    where
99        S: Serializer,
100    {
101        let inner = self.0;
102        inner.serialize(serializer)
103    }
104}
105
106impl<Data> Unaligned<Data>
107where
108    Data: TrivialType,
109{
110    /// Create a new instance
111    #[inline(always)]
112    pub const fn new(inner: Data) -> Self {
113        Self(inner)
114    }
115
116    /// Get inner value
117    #[inline(always)]
118    pub const fn as_inner(&self) -> Data {
119        self.0
120    }
121
122    /// Replace inner value
123    pub const fn replace(&mut self, value: Data) {
124        self.0 = value;
125    }
126}