use crate::raw::{
tableGenBitArrayFree, tableGenBitInitGetValue, tableGenBitsInitGetValue,
tableGenDagRecordArgName, tableGenDagRecordGet, tableGenDagRecordNumArgs,
tableGenDefInitGetValue, tableGenInitRecType, tableGenIntInitGetValue, tableGenListRecordGet,
tableGenStringInitGetValueNewString, TableGenRecTyKind, TableGenTypedInitRef,
};
use paste::paste;
use crate::{
error::{self, TableGenError},
record::Record,
};
use std::ffi::CStr;
#[derive(Debug)]
pub enum TypedValue {
Bit(i8),
Bits(Vec<i8>),
Code(String),
Int(i64),
String(String),
List(ListValue),
Dag(DagValue),
Record(Record),
Invalid,
}
macro_rules! as_inner {
($name:ident, $variant:ident, $type:ty) => {
paste! {
pub fn [<as_ $name>](&self) -> Option<&$type> {
if let Self::$variant(v) = self {
Some(&v)
} else {
None
}
}
}
};
}
macro_rules! try_into {
($variant:ident, $type:ty) => {
impl TryFrom<TypedValue> for $type {
type Error = TableGenError;
fn try_from(value: TypedValue) -> Result<Self, Self::Error> {
if let TypedValue::$variant(v) = value {
Ok(v)
} else {
Err(Self::Error::IncorrectValueType(value))
}
}
}
};
}
try_into!(Bit, i8);
try_into!(Bits, Vec<i8>);
try_into!(Int, i64);
try_into!(List, ListValue);
try_into!(Dag, DagValue);
try_into!(Record, Record);
impl TryFrom<TypedValue> for String {
type Error = TableGenError;
fn try_from(value: TypedValue) -> Result<Self, Self::Error> {
if let TypedValue::String(v) | TypedValue::Code(v) = value {
Ok(v)
} else {
Err(Self::Error::IncorrectValueType(value))
}
}
}
impl TypedValue {
as_inner!(bit, Bit, i8);
as_inner!(bits, Bits, Vec<i8>);
as_inner!(code, Code, String);
as_inner!(int, Int, i64);
as_inner!(string, String, String);
as_inner!(list, List, ListValue);
as_inner!(dag, Dag, DagValue);
as_inner!(def, Record, Record);
#[allow(non_upper_case_globals)]
pub unsafe fn from_typed_init(init: TableGenTypedInitRef) -> error::Result<Self> {
let t = tableGenInitRecType(init);
use TableGenRecTyKind::*;
match t {
TableGenBitRecTyKind => {
let mut bit = -1;
tableGenBitInitGetValue(init, &mut bit);
if bit == 0 || bit == 1 {
Ok(TypedValue::Bit(bit))
} else {
Err(TableGenError::InvalidBitRange)
}
}
TableGenBitsRecTyKind => {
let mut bits: Vec<_> = Vec::new();
let mut len: usize = 0;
let cbits = tableGenBitsInitGetValue(init, &mut len);
let mut bits_ptr = cbits;
for _ in 0..len {
bits.push(*bits_ptr);
bits_ptr = bits_ptr.offset(1);
}
tableGenBitArrayFree(cbits);
if bits.is_empty() {
Err(TableGenError::NullPointer.into())
} else {
Ok(TypedValue::Bits(bits))
}
}
TableGenDagRecTyKind => Ok(TypedValue::Dag(DagValue::from_raw(init))),
TableGenIntRecTyKind => {
let mut int: i64 = 0;
tableGenIntInitGetValue(init, &mut int);
Ok(TypedValue::Int(int))
}
TableGenListRecTyKind => Ok(TypedValue::List(ListValue::from_raw(init))),
TableGenRecordRecTyKind => Ok(TypedValue::Record(Record::from_raw(
tableGenDefInitGetValue(init),
))),
TableGenStringRecTyKind => {
let cstr = tableGenStringInitGetValueNewString(init);
Ok(TypedValue::String(
CStr::from_ptr(cstr).to_string_lossy().into_owned(),
))
}
_ => Ok(Self::Invalid),
}
}
}
#[derive(Debug)]
pub struct DagValue {
raw: TableGenTypedInitRef,
}
impl DagValue {
pub fn from_raw(val: TableGenTypedInitRef) -> DagValue {
DagValue { raw: val }
}
pub fn values_iter(&self) -> DagIterator {
DagIterator::from_dag(self)
}
pub fn num_args(&self) -> usize {
unsafe { tableGenDagRecordNumArgs(self.raw) }
}
pub fn get_name(&self, index: usize) -> Option<String> {
let value = unsafe { tableGenDagRecordArgName(self.raw, index) };
if !value.is_null() {
Some(unsafe { CStr::from_ptr(value).to_string_lossy().into_owned() })
} else {
None
}
}
pub fn get(&self, index: usize) -> Option<TypedValue> {
let value = unsafe { tableGenDagRecordGet(self.raw, index) };
if !value.is_null() {
unsafe { TypedValue::from_typed_init(value).ok() }
} else {
None
}
}
}
#[derive(Clone)]
pub struct DagIterator<'d> {
dag: &'d DagValue,
index: usize,
}
impl<'d> DagIterator<'d> {
fn from_dag(dag: &'d DagValue) -> DagIterator<'d> {
DagIterator { dag, index: 0 }
}
}
impl<'d> Iterator for DagIterator<'d> {
type Item = (String, TypedValue);
fn next(&mut self) -> Option<Self::Item> {
let next = self.dag.get(self.index);
let name = self.dag.get_name(self.index);
self.index += 1;
if next.is_some() && name.is_some() {
Some((name.unwrap(), next.unwrap()))
} else {
None
}
}
}
#[derive(Debug)]
pub struct ListValue {
raw: TableGenTypedInitRef,
}
impl ListValue {
pub fn from_raw(val: TableGenTypedInitRef) -> ListValue {
ListValue { raw: val }
}
pub fn values_iter(&self) -> ListIterator {
ListIterator::from_raw(self.raw)
}
}
#[derive(Clone)]
pub struct ListIterator {
raw: TableGenTypedInitRef,
index: usize,
}
impl ListIterator {
fn from_raw(raw: TableGenTypedInitRef) -> ListIterator {
ListIterator { raw, index: 0 }
}
}
impl Iterator for ListIterator {
type Item = TypedValue;
fn next(&mut self) -> Option<TypedValue> {
let next = unsafe { tableGenListRecordGet(self.raw, self.index) };
self.index += 1;
if !next.is_null() {
unsafe { TypedValue::from_typed_init(next).ok() }
} else {
None
}
}
}