1#![allow(clippy::missing_errors_doc)]
3
4mod traits;
5use core::{fmt, mem, result};
6
7pub use traits::*;
8mod impls;
9
10#[cfg(test)]
11mod test;
12
13#[cfg(not(feature = "std"))]
14use alloc::vec::Vec;
15
16pub const ABI_ALIGNMENT: usize = 32;
18pub const ABI_WORD_SIZE: u32 = 32;
19pub type AbiWord = [u8; ABI_WORD_SIZE as usize];
20
21pub type Result<T, E = Error> = result::Result<T, E>;
23
24#[derive(Debug)]
26pub enum Error {
27 OutOfOffset,
29 InvalidRange,
31 Custom(&'static str),
33}
34impl fmt::Display for Error {
35 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36 match self {
37 Error::OutOfOffset => write!(f, "out of offset"),
38 Error::InvalidRange => write!(f, "invalid range"),
39 Error::Custom(m) => write!(f, "{m}"),
40 }
41 }
42}
43impl From<&'static str> for Error {
44 fn from(value: &'static str) -> Self {
45 Self::Custom(value)
46 }
47}
48
49#[derive(Debug)]
51pub struct AbiEncoder {
52 out: Vec<u8>,
53 offset: usize,
54 dynamic_offset: usize,
55}
56impl AbiEncoder {
57 fn new(out: Vec<u8>, offset: usize, dynamic_offset: usize) -> Self {
58 assert_eq!((dynamic_offset - offset) % 32, 0);
59 Self {
60 out,
61 offset,
62 dynamic_offset,
63 }
64 }
65 pub fn reserve_head(&mut self, words: u32) {
66 assert_eq!(self.offset, self.dynamic_offset);
67 assert_eq!(self.dynamic_offset, self.out.len());
68 self.out
69 .resize(self.out.len() + words as usize * ABI_WORD_SIZE as usize, 0);
70 self.dynamic_offset += words as usize * ABI_WORD_SIZE as usize;
71 }
72 pub fn append_head(&mut self, word: AbiWord) {
73 assert!(self.offset < self.dynamic_offset);
74 self.out[self.offset..self.offset + 32].copy_from_slice(&word);
75 self.offset += 32;
76 }
77 fn append_tail(&mut self, word: AbiWord) {
78 self.out.extend_from_slice(&word);
79 }
80 fn tail_size(&self) -> u32 {
81 self.out.len() as u32 - self.dynamic_offset as u32
82 }
83 fn encode_tail<T: AbiEncode>(&mut self, data: &T) {
84 let offset = self.out.len();
85 let mut out = mem::take(&mut self.out);
86 let size = T::HEAD_WORDS as usize * ABI_WORD_SIZE as usize;
87 out.resize(out.len() + size, 0);
88 let mut encoder = AbiEncoder::new(
89 out,
90 offset,
91 offset + T::HEAD_WORDS as usize * ABI_WORD_SIZE as usize,
92 );
93 data.enc(&mut encoder);
94 self.out = encoder.into_inner()
95 }
96 fn into_inner(self) -> Vec<u8> {
97 self.out
98 }
99}
100
101#[derive(Clone)]
102pub struct AbiDecoder<'d> {
103 data: &'d [u8],
104 offset: usize,
105 global_frame_offset: usize,
106}
107impl<'d> AbiDecoder<'d> {
108 fn new(data: &'d [u8], global_frame_offset: usize) -> Result<Self> {
109 if data.len() % 32 != 0 {
110 return Err(Error::OutOfOffset);
111 }
112 Ok(Self {
113 data,
114 offset: 0,
115 global_frame_offset,
116 })
117 }
118 pub fn get_head(&mut self) -> Result<AbiWord> {
119 if self.offset >= self.data.len() {
120 return Err(Error::OutOfOffset);
121 }
122 let mut word = [0; ABI_WORD_SIZE as usize];
123 word.copy_from_slice(&self.data[self.offset..self.offset + 32]);
124 self.offset += 32;
125 Ok(word)
126 }
127 pub fn start_frame(&self) -> Self {
128 self.dynamic_at(self.offset as u32).expect("not oob")
129 }
130 pub fn dynamic_at(&self, offset: u32) -> Result<Self> {
131 if offset % 32 != 0 || self.data.len() < offset as usize {
132 return Err(Error::OutOfOffset);
134 }
135 Self::new(
136 &self.data[offset as usize..],
137 self.global_frame_offset + offset as usize,
138 )
139 }
140}