1use core::mem::MaybeUninit;
2
3#[cfg(feature = "alloc")]
4use alloc::{borrow::Cow, vec::Vec};
5
6use crate::program::Reg;
7
8#[derive(Clone, PartialEq, Eq, Debug, Default)]
10#[repr(transparent)]
11pub struct CowBytes<'a>(CowBytesImpl<'a>);
12
13#[cfg(feature = "alloc")]
14type CowBytesImpl<'a> = Cow<'a, [u8]>;
15
16#[cfg(not(feature = "alloc"))]
17type CowBytesImpl<'a> = &'a [u8];
18
19impl<'a> CowBytes<'a> {
20 #[cfg(feature = "alloc")]
21 pub fn into_owned(self) -> CowBytes<'static> {
22 match self.0 {
23 Cow::Borrowed(data) => CowBytes(Cow::Owned(data.into())),
24 Cow::Owned(data) => CowBytes(Cow::Owned(data)),
25 }
26 }
27}
28
29impl<'a> core::ops::Deref for CowBytes<'a> {
30 type Target = [u8];
31
32 fn deref(&self) -> &Self::Target {
33 &self.0
34 }
35}
36
37impl<'a> From<&'a [u8]> for CowBytes<'a> {
38 fn from(slice: &'a [u8]) -> Self {
39 CowBytes(slice.into())
40 }
41}
42
43impl<'a> From<&'a str> for CowBytes<'a> {
44 fn from(slice: &'a str) -> Self {
45 CowBytes(slice.as_bytes().into())
46 }
47}
48
49#[cfg(feature = "alloc")]
50impl<'a> From<Vec<u8>> for CowBytes<'a> {
51 fn from(vec: Vec<u8>) -> Self {
52 CowBytes(vec.into())
53 }
54}
55
56#[cfg(feature = "alloc")]
57impl<'a> From<Cow<'a, [u8]>> for CowBytes<'a> {
58 fn from(cow: Cow<'a, [u8]>) -> Self {
59 CowBytes(cow)
60 }
61}
62
63macro_rules! define_align_to_next_page {
64 ($name:ident, $type:ty) => {
65 #[inline]
67 pub const fn $name(page_size: $type, value: $type) -> Option<$type> {
68 assert!(
69 page_size != 0 && (page_size & (page_size - 1)) == 0,
70 "page size is not a power of two"
71 );
72 if value & page_size - 1 == 0 {
73 Some(value)
74 } else {
75 if value <= <$type>::MAX - page_size {
76 Some((value + page_size) & !(page_size - 1))
77 } else {
78 None
79 }
80 }
81 }
82 };
83}
84
85define_align_to_next_page!(align_to_next_page_u32, u32);
86define_align_to_next_page!(align_to_next_page_u64, u64);
87define_align_to_next_page!(align_to_next_page_usize, usize);
88
89#[test]
90fn test_align_to_next_page() {
91 assert_eq!(align_to_next_page_u64(4096, 0), Some(0));
92 assert_eq!(align_to_next_page_u64(4096, 1), Some(4096));
93 assert_eq!(align_to_next_page_u64(4096, 4095), Some(4096));
94 assert_eq!(align_to_next_page_u64(4096, 4096), Some(4096));
95 assert_eq!(align_to_next_page_u64(4096, 4097), Some(8192));
96 let max = (0x10000000000000000_u128 - 4096) as u64;
97 assert_eq!(align_to_next_page_u64(4096, max), Some(max));
98 assert_eq!(align_to_next_page_u64(4096, max + 1), None);
99}
100
101pub trait AsUninitSliceMut {
102 fn as_uninit_slice_mut(&mut self) -> &mut [MaybeUninit<u8>];
103}
104
105impl AsUninitSliceMut for [MaybeUninit<u8>] {
106 fn as_uninit_slice_mut(&mut self) -> &mut [MaybeUninit<u8>] {
107 self
108 }
109}
110
111impl AsUninitSliceMut for [u8] {
112 fn as_uninit_slice_mut(&mut self) -> &mut [MaybeUninit<u8>] {
113 #[allow(unsafe_code)]
114 unsafe {
117 core::slice::from_raw_parts_mut(self.as_mut_ptr().cast(), self.len())
118 }
119 }
120}
121
122impl<const N: usize> AsUninitSliceMut for MaybeUninit<[u8; N]> {
123 fn as_uninit_slice_mut(&mut self) -> &mut [MaybeUninit<u8>] {
124 #[allow(unsafe_code)]
125 unsafe {
128 core::slice::from_raw_parts_mut(self.as_mut_ptr().cast(), N)
129 }
130 }
131}
132
133impl<const N: usize> AsUninitSliceMut for [u8; N] {
134 fn as_uninit_slice_mut(&mut self) -> &mut [MaybeUninit<u8>] {
135 let slice: &mut [u8] = &mut self[..];
136 slice.as_uninit_slice_mut()
137 }
138}
139
140#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
142#[repr(transparent)]
143pub struct Gas(u64);
144
145impl core::fmt::Display for Gas {
146 fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
147 self.0.fmt(fmt)
148 }
149}
150
151impl Gas {
152 pub const MAX: Self = Gas(i64::MAX as u64);
154
155 pub const MIN: Self = Gas(0);
157
158 pub const fn new(gas: u64) -> Option<Self> {
160 Self::from_u64(gas)
161 }
162
163 pub const fn from_u64(gas: u64) -> Option<Self> {
165 let gas = Self(gas);
166 if gas.0 > Self::MAX.0 {
167 None
168 } else {
169 Some(gas)
170 }
171 }
172
173 pub const fn from_i64(gas: i64) -> Option<Self> {
175 Self::from_u64(gas as u64)
176 }
177
178 pub const fn get(self) -> u64 {
180 self.0
181 }
182
183 pub const fn is_empty(self) -> bool {
185 self.0 == 0
186 }
187}
188
189impl From<u32> for Gas {
190 fn from(gas: u32) -> Self {
191 Gas(u64::from(gas))
192 }
193}
194
195impl TryFrom<u64> for Gas {
196 type Error = &'static str;
197 fn try_from(gas: u64) -> Result<Self, Self::Error> {
198 Self::from_u64(gas).ok_or("out of range gas")
199 }
200}
201
202impl TryFrom<i64> for Gas {
203 type Error = &'static str;
204 fn try_from(gas: i64) -> Result<Self, Self::Error> {
205 Self::from_i64(gas).ok_or("out of range gas")
206 }
207}
208
209pub trait Access<'a> {
210 type Error: core::fmt::Display;
211
212 fn get_reg(&self, reg: Reg) -> u32;
213 fn set_reg(&mut self, reg: Reg, value: u32);
214 fn read_memory_into_slice<'slice, T>(&self, address: u32, buffer: &'slice mut T) -> Result<&'slice mut [u8], Self::Error>
215 where
216 T: ?Sized + AsUninitSliceMut;
217 fn write_memory(&mut self, address: u32, data: &[u8]) -> Result<(), Self::Error>;
218
219 fn sbrk(&mut self, size: u32) -> Option<u32>;
220
221 fn heap_size(&self) -> u32;
223
224 fn program_counter(&self) -> Option<u32>;
225 fn native_program_counter(&self) -> Option<u64>;
226
227 fn gas_remaining(&self) -> Option<Gas>;
232
233 fn consume_gas(&mut self, gas: u64);
234
235 #[cfg(feature = "alloc")]
236 fn read_memory_into_vec(&self, address: u32, length: u32) -> Result<Vec<u8>, Self::Error> {
237 let mut buffer = Vec::new();
238 buffer.reserve_exact(length as usize);
239
240 let pointer = buffer.as_ptr();
241 let slice = self.read_memory_into_slice(address, buffer.spare_capacity_mut())?;
242
243 assert_eq!(slice.as_ptr(), pointer);
246 assert_eq!(slice.len(), length as usize);
247
248 #[allow(unsafe_code)]
249 unsafe {
251 buffer.set_len(length as usize);
252 }
253
254 Ok(buffer)
255 }
256}
257
258#[allow(clippy::missing_safety_doc)]
261#[allow(unsafe_code)]
262pub unsafe fn slice_assume_init_mut<T>(slice: &mut [MaybeUninit<T>]) -> &mut [T] {
263 unsafe { &mut *(slice as *mut [MaybeUninit<T>] as *mut [T]) }
265}
266
267#[allow(unsafe_code)]
268pub fn byte_slice_init<'dst>(dst: &'dst mut [MaybeUninit<u8>], src: &[u8]) -> &'dst mut [u8] {
269 assert_eq!(dst.len(), src.len());
270
271 let length = dst.len();
272 let src_ptr: *const u8 = src.as_ptr();
273 let dst_ptr: *mut u8 = dst.as_mut_ptr().cast::<u8>();
274
275 unsafe {
278 core::ptr::copy_nonoverlapping(src_ptr, dst_ptr, length);
279 }
280
281 unsafe { slice_assume_init_mut(dst) }
283}