use sway_types::SourceId;
use crate::context::Context;
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash)]
pub struct MetadataIndex(pub slotmap::DefaultKey);
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum Metadatum {
Integer(u64),
Index(MetadataIndex),
String(String),
SourceId(SourceId),
Struct(String, Vec<Metadatum>),
List(Vec<MetadataIndex>),
}
pub fn combine(
context: &mut Context,
md_idx_a: &Option<MetadataIndex>,
md_idx_b: &Option<MetadataIndex>,
) -> Option<MetadataIndex> {
match (md_idx_a, md_idx_b) {
(None, None) => None,
(Some(_), None) => *md_idx_a,
(None, Some(_)) => *md_idx_b,
(Some(idx_a), Some(idx_b)) => {
let mut new_list = Vec::new();
if let Metadatum::List(lst_a) = &context.metadata[idx_a.0] {
new_list.append(&mut lst_a.clone());
} else {
new_list.push(*idx_a);
}
if let Metadatum::List(lst_b) = &context.metadata[idx_b.0] {
new_list.append(&mut lst_b.clone());
} else {
new_list.push(*idx_b);
}
Some(MetadataIndex(
context.metadata.insert(Metadatum::List(new_list)),
))
}
}
}
impl MetadataIndex {
pub fn new_integer(context: &mut Context, int: u64) -> Self {
MetadataIndex(context.metadata.insert(Metadatum::Integer(int)))
}
pub fn new_index(context: &mut Context, idx: MetadataIndex) -> Self {
MetadataIndex(context.metadata.insert(Metadatum::Index(idx)))
}
pub fn new_source_id(context: &mut Context, id: SourceId) -> Self {
MetadataIndex(context.metadata.insert(Metadatum::SourceId(id)))
}
pub fn new_string<S: Into<String>>(context: &mut Context, s: S) -> Self {
MetadataIndex(context.metadata.insert(Metadatum::String(s.into())))
}
pub fn new_struct<S: Into<String>>(
context: &mut Context,
tag: S,
fields: Vec<Metadatum>,
) -> Self {
MetadataIndex(
context
.metadata
.insert(Metadatum::Struct(tag.into(), fields)),
)
}
pub fn new_list(context: &mut Context, els: Vec<MetadataIndex>) -> Self {
MetadataIndex(context.metadata.insert(Metadatum::List(els)))
}
pub fn get_content<'a>(&self, context: &'a Context) -> &'a Metadatum {
&context.metadata[self.0]
}
}
impl Metadatum {
pub fn unwrap_integer(&self) -> Option<u64> {
if let Metadatum::Integer(n) = self {
Some(*n)
} else {
None
}
}
pub fn unwrap_index(&self) -> Option<MetadataIndex> {
if let Metadatum::Index(idx) = self {
Some(*idx)
} else {
None
}
}
pub fn unwrap_string(&self) -> Option<&str> {
if let Metadatum::String(s) = self {
Some(s)
} else {
None
}
}
pub fn unwrap_source_id(&self) -> Option<&SourceId> {
if let Metadatum::SourceId(id) = self {
Some(id)
} else {
None
}
}
pub fn unwrap_struct<'a>(&'a self, tag: &str, num_fields: usize) -> Option<&'a [Metadatum]> {
match self {
Metadatum::Struct(t, fs) if t == tag && fs.len() == num_fields => Some(fs),
_otherwise => None,
}
}
pub fn unwrap_list(&self) -> Option<&[MetadataIndex]> {
if let Metadatum::List(els) = self {
Some(els)
} else {
None
}
}
}