use crate::passes::Roots;
use crate::tombstone_arena::{Id, Tombstone, TombstoneArena};
use crate::CodeTransform;
use crate::IdsToIndices;
use std::any::Any;
use std::borrow::Cow;
use std::fmt::{self, Debug};
use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
pub trait CustomSection: WalrusAny + Debug + Send + Sync {
fn name(&self) -> &str;
fn data(&self, ids_to_indices: &IdsToIndices) -> Cow<'_, [u8]>;
fn add_gc_roots(&self, _roots: &mut Roots) {}
fn apply_code_transform(&mut self, transform: &CodeTransform) {
let _ = transform;
}
}
pub trait WalrusAny: Any + Send + Sync {
#[doc(hidden)]
fn walrus_into_any(self: Box<Self>) -> Box<dyn Any + Send + 'static>;
#[doc(hidden)]
fn walrus_as_any(&self) -> &(dyn Any + Send + Sync);
#[doc(hidden)]
fn walrus_as_any_mut(&mut self) -> &mut (dyn Any + Send + Sync);
}
impl<T: Any + Send + Sync> WalrusAny for T {
fn walrus_into_any(self: Box<Self>) -> Box<dyn Any + Send + 'static> {
self
}
fn walrus_as_any(&self) -> &(dyn Any + Send + Sync) {
self
}
fn walrus_as_any_mut(&mut self) -> &mut (dyn Any + Send + Sync) {
self
}
}
impl dyn CustomSection {
pub fn into_any(self: Box<Self>) -> Box<dyn Any + Send + 'static> {
self.walrus_into_any()
}
pub fn as_any(&self) -> &(dyn Any + Send + Sync) {
self.walrus_as_any()
}
pub fn as_any_mut(&mut self) -> &mut (dyn Any + Send + Sync) {
self.walrus_as_any_mut()
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct RawCustomSection {
pub name: String,
pub data: Vec<u8>,
}
impl CustomSection for RawCustomSection {
fn name(&self) -> &str {
&self.name
}
fn data(&self, _: &IdsToIndices) -> Cow<'_, [u8]> {
self.data.as_slice().into()
}
}
pub trait CustomSectionId {
type CustomSection: ?Sized;
#[doc(hidden)]
fn into_inner_id(self) -> Id<Option<Box<dyn CustomSection>>>;
#[doc(hidden)]
fn section(s: &dyn CustomSection) -> Option<&Self::CustomSection>;
#[doc(hidden)]
fn section_mut(s: &mut dyn CustomSection) -> Option<&mut Self::CustomSection>;
#[doc(hidden)]
fn section_box(s: Box<dyn CustomSection>) -> Option<Box<Self::CustomSection>>;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct UntypedCustomSectionId(Id<Option<Box<dyn CustomSection>>>);
impl CustomSectionId for UntypedCustomSectionId {
type CustomSection = dyn CustomSection;
fn into_inner_id(self) -> Id<Option<Box<dyn CustomSection>>> {
self.0
}
fn section(s: &dyn CustomSection) -> Option<&dyn CustomSection> {
Some(s)
}
fn section_mut(s: &mut dyn CustomSection) -> Option<&mut dyn CustomSection> {
Some(s)
}
fn section_box(s: Box<dyn CustomSection>) -> Option<Box<dyn CustomSection>> {
Some(s)
}
}
pub struct TypedCustomSectionId<T>
where
T: CustomSection,
{
id: UntypedCustomSectionId,
_phantom: PhantomData<T>,
}
impl<T> Debug for TypedCustomSectionId<T>
where
T: CustomSection,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("TypedCustomSectionId")
.field(&self.id)
.finish()
}
}
impl<T> Clone for TypedCustomSectionId<T>
where
T: CustomSection,
{
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for TypedCustomSectionId<T> where T: CustomSection {}
impl<T> PartialEq for TypedCustomSectionId<T>
where
T: CustomSection,
{
fn eq(&self, rhs: &Self) -> bool {
self.id == rhs.id
}
}
impl<T> Eq for TypedCustomSectionId<T> where T: CustomSection {}
impl<T> Hash for TypedCustomSectionId<T>
where
T: CustomSection,
{
fn hash<H: Hasher>(&self, state: &mut H) {
self.id.hash(state);
}
}
impl<T> CustomSectionId for TypedCustomSectionId<T>
where
T: CustomSection,
{
type CustomSection = T;
fn into_inner_id(self) -> Id<Option<Box<dyn CustomSection>>> {
self.id.0
}
fn section(s: &dyn CustomSection) -> Option<&T> {
s.as_any().downcast_ref::<T>()
}
fn section_mut(s: &mut dyn CustomSection) -> Option<&mut T> {
s.as_any_mut().downcast_mut::<T>()
}
fn section_box(s: Box<dyn CustomSection>) -> Option<Box<T>> {
s.into_any().downcast().ok()
}
}
impl<T> From<TypedCustomSectionId<T>> for UntypedCustomSectionId
where
T: CustomSection,
{
#[inline]
fn from(a: TypedCustomSectionId<T>) -> Self {
a.id
}
}
impl Tombstone for Option<Box<dyn CustomSection>> {
fn on_delete(&mut self) {
*self = None;
}
}
#[derive(Debug, Default)]
pub struct ModuleCustomSections {
arena: TombstoneArena<Option<Box<dyn CustomSection>>>,
}
impl ModuleCustomSections {
pub fn add<T>(&mut self, custom_section: T) -> TypedCustomSectionId<T>
where
T: CustomSection,
{
let id = self
.arena
.alloc(Some(Box::new(custom_section) as Box<dyn CustomSection>));
TypedCustomSectionId {
id: UntypedCustomSectionId(id),
_phantom: PhantomData,
}
}
pub fn delete<I>(&mut self, id: I) -> Option<Box<I::CustomSection>>
where
I: CustomSectionId,
{
let id = id.into_inner_id();
let ret = self.arena.get_mut(id)?.take()?;
self.arena.delete(id);
I::section_box(ret)
}
pub fn remove_raw(&mut self, name: &str) -> Option<RawCustomSection> {
let id = self
.arena
.iter()
.filter(|(_id, s)| {
if let Some(s) = s {
s.as_any().is::<RawCustomSection>() && s.name() == name
} else {
false
}
})
.map(|(id, _)| id)
.next()?;
let section = self.arena[id].take().unwrap();
self.arena.delete(id);
let raw = section.into_any().downcast::<RawCustomSection>().unwrap();
Some(*raw)
}
pub fn get<T>(&self, id: T) -> Option<&T::CustomSection>
where
T: CustomSectionId,
{
self.arena
.get(id.into_inner_id())
.and_then(|s| T::section(&**s.as_ref().unwrap()))
}
pub fn get_mut<T>(&mut self, id: T) -> Option<&mut T::CustomSection>
where
T: CustomSectionId,
{
self.arena
.get_mut(id.into_inner_id())
.and_then(|s| T::section_mut(&mut **s.as_mut().unwrap()))
}
pub fn iter(&self) -> impl Iterator<Item = (UntypedCustomSectionId, &dyn CustomSection)> {
self.arena
.iter()
.flat_map(|(id, s)| Some((UntypedCustomSectionId(id), &**s.as_ref()?)))
}
pub fn iter_mut(
&mut self,
) -> impl Iterator<Item = (UntypedCustomSectionId, &mut dyn CustomSection)> {
self.arena
.iter_mut()
.flat_map(|(id, s)| Some((UntypedCustomSectionId(id), &mut **s.as_mut()?)))
}
pub fn delete_typed<T>(&mut self) -> Option<Box<T>>
where
T: CustomSection,
{
let (id, _) = self.iter().find(|(_, s)| s.as_any().is::<T>())?;
self.delete(id)?.into_any().downcast().ok()
}
pub fn get_typed<T>(&self) -> Option<&T>
where
T: CustomSection,
{
self.iter()
.filter_map(|(_, s)| s.as_any().downcast_ref())
.next()
}
pub fn get_typed_mut<T>(&mut self) -> Option<&mut T>
where
T: CustomSection,
{
self.iter_mut()
.filter_map(|(_, s)| s.as_any_mut().downcast_mut())
.next()
}
}