pub mod eof;
pub mod legacy;
pub use eof::{Eof, EOF_MAGIC, EOF_MAGIC_BYTES, EOF_MAGIC_HASH};
pub use legacy::{JumpTable, LegacyAnalyzedBytecode};
use std::sync::Arc;
use crate::{keccak256, Bytes, B256, KECCAK_EMPTY};
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Bytecode {
LegacyRaw(Bytes),
LegacyAnalyzed(LegacyAnalyzedBytecode),
Eof(Arc<Eof>),
}
impl Default for Bytecode {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl Bytecode {
#[inline]
pub fn new() -> Self {
Self::LegacyAnalyzed(LegacyAnalyzedBytecode::default())
}
#[inline]
pub fn legacy_jump_table(&self) -> Option<&JumpTable> {
match &self {
Self::LegacyAnalyzed(analyzed) => Some(analyzed.jump_table()),
_ => None,
}
}
pub fn hash_slow(&self) -> B256 {
if self.is_empty() {
KECCAK_EMPTY
} else {
keccak256(self.original_byte_slice())
}
}
#[inline]
pub const fn eof(&self) -> Option<&Arc<Eof>> {
match self {
Self::Eof(eof) => Some(eof),
_ => None,
}
}
#[inline]
pub const fn is_eof(&self) -> bool {
matches!(self, Self::Eof(_))
}
#[inline]
pub fn new_raw(bytecode: Bytes) -> Self {
Self::LegacyRaw(bytecode)
}
pub unsafe fn new_analyzed(
bytecode: Bytes,
original_len: usize,
jump_table: JumpTable,
) -> Self {
Self::LegacyAnalyzed(LegacyAnalyzedBytecode::new(
bytecode,
original_len,
jump_table,
))
}
#[inline]
pub fn bytecode(&self) -> &Bytes {
match self {
Self::LegacyRaw(bytes) => bytes,
Self::LegacyAnalyzed(analyzed) => analyzed.bytecode(),
Self::Eof(eof) => eof
.body
.code(0)
.expect("Valid EOF has at least one code section"),
}
}
pub fn is_execution_ready(&self) -> bool {
!matches!(self, Self::LegacyRaw(_))
}
#[inline]
pub fn bytes(&self) -> Bytes {
match self {
Self::LegacyRaw(bytes) => bytes.clone(),
Self::LegacyAnalyzed(analyzed) => analyzed.bytecode().clone(),
Self::Eof(eof) => eof.raw().clone(),
}
}
#[inline]
pub fn bytes_slice(&self) -> &[u8] {
match self {
Self::LegacyRaw(bytes) => bytes,
Self::LegacyAnalyzed(analyzed) => analyzed.bytecode(),
Self::Eof(eof) => eof.raw(),
}
}
#[inline]
pub fn original_bytes(&self) -> Bytes {
match self {
Self::LegacyRaw(bytes) => bytes.clone(),
Self::LegacyAnalyzed(analyzed) => analyzed.original_bytes(),
Self::Eof(eof) => eof.raw().clone(),
}
}
#[inline]
pub fn original_byte_slice(&self) -> &[u8] {
match self {
Self::LegacyRaw(bytes) => bytes,
Self::LegacyAnalyzed(analyzed) => analyzed.original_byte_slice(),
Self::Eof(eof) => eof.raw(),
}
}
#[inline]
pub fn len(&self) -> usize {
match self {
Self::LegacyRaw(bytes) => bytes.len(),
Self::LegacyAnalyzed(analyzed) => analyzed.original_len(),
Self::Eof(eof) => eof.size(),
}
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::Arc;
#[test]
fn eof_arc_clone() {
let eof = Arc::new(Eof::default());
let bytecode = Bytecode::Eof(Arc::clone(&eof));
let cloned_bytecode = bytecode.clone();
if let Bytecode::Eof(original_arc) = bytecode {
if let Bytecode::Eof(cloned_arc) = cloned_bytecode {
assert!(Arc::ptr_eq(&original_arc, &cloned_arc));
} else {
panic!("Cloned bytecode is not Eof");
}
} else {
panic!("Original bytecode is not Eof");
}
}
}