use crate::ir::instructions::ValueListPool;
use crate::ir::BlockCall;
use alloc::vec::Vec;
use core::fmt::{self, Display, Formatter};
use core::slice::{Iter, IterMut};
#[cfg(feature = "enable-serde")]
use serde_derive::{Deserialize, Serialize};
#[derive(Clone, PartialEq, Hash)]
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
pub struct JumpTableData {
table: Vec<BlockCall>,
}
impl JumpTableData {
pub fn new(def: BlockCall, table: &[BlockCall]) -> Self {
Self {
table: std::iter::once(def).chain(table.iter().copied()).collect(),
}
}
pub fn default_block(&self) -> BlockCall {
*self.table.first().unwrap()
}
pub fn default_block_mut(&mut self) -> &mut BlockCall {
self.table.first_mut().unwrap()
}
pub fn all_branches(&self) -> &[BlockCall] {
self.table.as_slice()
}
pub fn all_branches_mut(&mut self) -> &mut [BlockCall] {
self.table.as_mut_slice()
}
pub fn as_slice(&self) -> &[BlockCall] {
&self.table.as_slice()[1..]
}
pub fn as_mut_slice(&mut self) -> &mut [BlockCall] {
&mut self.table.as_mut_slice()[1..]
}
#[deprecated(since = "7.0.0", note = "please use `.as_slice()` instead")]
pub fn iter(&self) -> Iter<BlockCall> {
self.as_slice().iter()
}
#[deprecated(since = "7.0.0", note = "please use `.as_mut_slice()` instead")]
pub fn iter_mut(&mut self) -> IterMut<BlockCall> {
self.as_mut_slice().iter_mut()
}
pub fn clear(&mut self) {
self.table.drain(1..);
}
pub fn display<'a>(&'a self, pool: &'a ValueListPool) -> DisplayJumpTable<'a> {
DisplayJumpTable { jt: self, pool }
}
}
pub struct DisplayJumpTable<'a> {
jt: &'a JumpTableData,
pool: &'a ValueListPool,
}
impl<'a> Display for DisplayJumpTable<'a> {
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
write!(fmt, "{}, [", self.jt.default_block().display(self.pool))?;
if let Some((first, rest)) = self.jt.as_slice().split_first() {
write!(fmt, "{}", first.display(self.pool))?;
for block in rest {
write!(fmt, ", {}", block.display(self.pool))?;
}
}
write!(fmt, "]")
}
}
#[cfg(test)]
mod tests {
use super::JumpTableData;
use crate::entity::EntityRef;
use crate::ir::instructions::ValueListPool;
use crate::ir::{Block, BlockCall, Value};
use std::string::ToString;
#[test]
fn empty() {
let mut pool = ValueListPool::default();
let def = BlockCall::new(Block::new(0), &[], &mut pool);
let jt = JumpTableData::new(def, &[]);
assert_eq!(jt.all_branches().get(0), Some(&def));
assert_eq!(jt.as_slice().get(0), None);
assert_eq!(jt.as_slice().get(10), None);
assert_eq!(jt.display(&pool).to_string(), "block0, []");
assert_eq!(jt.all_branches(), [def]);
assert_eq!(jt.as_slice(), []);
}
#[test]
fn insert() {
let mut pool = ValueListPool::default();
let v0 = Value::new(0);
let v1 = Value::new(1);
let e0 = Block::new(0);
let e1 = Block::new(1);
let e2 = Block::new(2);
let def = BlockCall::new(e0, &[], &mut pool);
let b1 = BlockCall::new(e1, &[v0], &mut pool);
let b2 = BlockCall::new(e2, &[], &mut pool);
let b3 = BlockCall::new(e1, &[v1], &mut pool);
let jt = JumpTableData::new(def, &[b1, b2, b3]);
assert_eq!(jt.default_block(), def);
assert_eq!(
jt.display(&pool).to_string(),
"block0, [block1(v0), block2, block1(v1)]"
);
assert_eq!(jt.all_branches(), [def, b1, b2, b3]);
assert_eq!(jt.as_slice(), [b1, b2, b3]);
assert_eq!(jt.as_slice()[0].args_slice(&pool), [v0]);
assert_eq!(jt.as_slice()[1].args_slice(&pool), []);
assert_eq!(jt.as_slice()[2].args_slice(&pool), [v1]);
}
}