celox-runtime 0.3.1

Backend-independent Celox simulation runtime contracts
Documentation
use std::cell::UnsafeCell;
use std::sync::atomic::{AtomicU64, Ordering};

pub struct RuntimeEventBuffer {
    words: Box<[UnsafeCell<u64>]>,
    byte_size: usize,
}

unsafe impl Send for RuntimeEventBuffer {}
unsafe impl Sync for RuntimeEventBuffer {}

impl RuntimeEventBuffer {
    pub fn new(byte_size: usize) -> Self {
        let word_count = byte_size.div_ceil(8);
        let words = (0..word_count)
            .map(|_| UnsafeCell::new(0u64))
            .collect::<Vec<_>>()
            .into_boxed_slice();
        Self { words, byte_size }
    }

    pub fn as_ptr(&self) -> *const u8 {
        self.words.as_ptr() as *const u8
    }

    pub fn as_mut_ptr(&self) -> *mut u8 {
        self.words.as_ptr() as *mut u8
    }

    pub fn byte_size(&self) -> usize {
        self.byte_size
    }

    pub fn load_atomic_u64(&self, byte_offset: usize, ordering: Ordering) -> u64 {
        assert_eq!(byte_offset % 8, 0);
        assert!(byte_offset + 8 <= self.byte_size);
        let word = byte_offset / 8;
        unsafe {
            let ptr = self.words[word].get() as *const AtomicU64;
            (*ptr).load(ordering)
        }
    }

    pub fn read_u64(&self, byte_offset: usize) -> u64 {
        assert_eq!(byte_offset % 8, 0);
        assert!(byte_offset + 8 <= self.byte_size);
        let word = byte_offset / 8;
        unsafe { std::ptr::read_volatile(self.words[word].get()) }
    }

    pub fn reset(&self) {
        for word in &self.words {
            unsafe {
                std::ptr::write_volatile(word.get(), 0);
            }
        }
    }
}