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