use super::{ConstExpr, MemoryIdx};
use crate::Error;
use alloc::{boxed::Box, sync::Arc, vec::Vec};
use core::slice;
#[derive(Debug)]
pub struct DataSegment {
inner: DataSegmentInner,
}
#[derive(Debug)]
pub enum DataSegmentInner {
Active(ActiveDataSegment),
Passive {
bytes: PassiveDataSegmentBytes,
},
}
#[derive(Debug)]
pub struct ActiveDataSegment {
memory_index: MemoryIdx,
offset: ConstExpr,
len: u32,
}
impl ActiveDataSegment {
pub fn memory_index(&self) -> MemoryIdx {
self.memory_index
}
pub fn offset(&self) -> &ConstExpr {
&self.offset
}
pub fn len(&self) -> usize {
self.len as usize
}
}
#[derive(Debug, Clone)]
pub struct PassiveDataSegmentBytes {
bytes: Arc<[u8]>,
}
impl AsRef<[u8]> for PassiveDataSegmentBytes {
fn as_ref(&self) -> &[u8] {
&self.bytes[..]
}
}
#[test]
fn size_of_data_segment() {
assert!(core::mem::size_of::<DataSegment>() <= 32);
assert!(core::mem::size_of::<DataSegmentInner>() <= 32);
}
impl DataSegment {
pub fn passive_data_segment_bytes(&self) -> Option<PassiveDataSegmentBytes> {
match &self.inner {
DataSegmentInner::Active { .. } => None,
DataSegmentInner::Passive { bytes } => Some(bytes.clone()),
}
}
}
#[derive(Debug)]
pub struct DataSegments {
segments: Box<[DataSegment]>,
bytes: Vec<u8>,
}
impl DataSegments {
pub fn build() -> DataSegmentsBuilder {
DataSegmentsBuilder {
segments: Vec::new(),
bytes: Vec::new(),
}
}
}
#[derive(Debug)]
pub struct DataSegmentsBuilder {
segments: Vec<DataSegment>,
bytes: Vec<u8>,
}
impl DataSegmentsBuilder {
pub fn reserve(&mut self, count: usize) {
assert!(
self.segments.capacity() == 0,
"must not reserve multiple times"
);
self.segments.reserve(count);
}
pub fn push_data_segment(&mut self, segment: wasmparser::Data) -> Result<(), Error> {
match segment.kind {
wasmparser::DataKind::Passive => {
self.segments.push(DataSegment {
inner: DataSegmentInner::Passive {
bytes: PassiveDataSegmentBytes {
bytes: segment.data.into(),
},
},
});
}
wasmparser::DataKind::Active {
memory_index,
offset_expr,
} => {
let memory_index = MemoryIdx::from(memory_index);
let offset = ConstExpr::new(offset_expr);
let len = u32::try_from(segment.data.len()).unwrap_or_else(|_x| {
panic!("data segment has too many bytes: {}", segment.data.len())
});
self.bytes.extend_from_slice(segment.data);
self.segments.push(DataSegment {
inner: DataSegmentInner::Active(ActiveDataSegment {
memory_index,
offset,
len,
}),
});
}
}
Ok(())
}
pub fn finish(self) -> DataSegments {
DataSegments {
segments: self.segments.into(),
bytes: self.bytes,
}
}
}
impl<'a> IntoIterator for &'a DataSegments {
type Item = InitDataSegment<'a>;
type IntoIter = InitDataSegmentIter<'a>;
fn into_iter(self) -> Self::IntoIter {
InitDataSegmentIter {
segments: self.segments.iter(),
bytes: &self.bytes[..],
}
}
}
#[derive(Debug)]
pub struct InitDataSegmentIter<'a> {
segments: slice::Iter<'a, DataSegment>,
bytes: &'a [u8],
}
impl<'a> Iterator for InitDataSegmentIter<'a> {
type Item = InitDataSegment<'a>;
fn next(&mut self) -> Option<Self::Item> {
let segment = self.segments.next()?;
match &segment.inner {
DataSegmentInner::Active(segment) => {
let (bytes, rest) = self.bytes.split_at(segment.len());
self.bytes = rest;
Some(InitDataSegment::Active {
memory_index: segment.memory_index(),
offset: segment.offset(),
bytes,
})
}
DataSegmentInner::Passive { bytes } => Some(InitDataSegment::Passive {
bytes: bytes.clone(),
}),
}
}
}
pub enum InitDataSegment<'a> {
Active {
memory_index: MemoryIdx,
offset: &'a ConstExpr,
bytes: &'a [u8],
},
Passive {
bytes: PassiveDataSegmentBytes,
},
}