use std::{cell::RefCell, fmt, rc::Rc};
use somni_expr::{
value::{LoadStore, ValueType},
OperatorError, Type, TypeSet,
};
use somni_parser::parser::TypeSet as ParserTypeSet;
use crate::string_interner::{StringIndex, StringInterner};
type ExprValue = somni_expr::TypedValue<VmTypeSet>;
#[derive(Clone)]
pub struct SomniIter {
inner: Rc<RefCell<std::iter::Peekable<Box<dyn Iterator<Item = ExprValue>>>>>,
}
impl SomniIter {
pub fn new<I>(iter: I) -> Self
where
I: IntoIterator<Item = ExprValue> + 'static,
{
let boxed: Box<dyn Iterator<Item = ExprValue>> = Box::new(iter.into_iter());
Self {
inner: Rc::new(RefCell::new(boxed.peekable())),
}
}
fn has_next(&self) -> bool {
self.inner.borrow_mut().peek().is_some()
}
fn next_value(&self) -> Option<ExprValue> {
self.inner.borrow_mut().next()
}
}
impl fmt::Debug for SomniIter {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("<iter>")
}
}
impl PartialEq for SomniIter {
fn eq(&self, other: &Self) -> bool {
Rc::ptr_eq(&self.inner, &other.inner)
}
}
impl ValueType for SomniIter {
const TYPE: Type = Type::Iter;
type NegateOutput = Self;
}
impl LoadStore<VmTypeSet> for SomniIter {
type Output<'s> = Self;
fn load<'s>(ctx: &'s VmTypeSet, typed: &'s ExprValue) -> Option<Self::Output<'s>> {
if let somni_expr::TypedValue::Iter(handle) = typed {
ctx.get_iterator(*handle)
} else {
None
}
}
fn store(&self, ctx: &mut VmTypeSet) -> ExprValue {
let handle = ctx.store_iterator(self.clone());
somni_expr::TypedValue::Iter(handle)
}
}
#[doc(hidden)]
pub trait MemoryRepr: Sized + Copy + PartialEq {
const BYTES: usize = std::mem::size_of::<Self>();
fn write(&self, to: &mut [u8]);
fn from_bytes(bytes: &[u8]) -> Self;
}
impl MemoryRepr for () {
fn write(&self, _to: &mut [u8]) {}
fn from_bytes(_: &[u8]) -> Self {}
}
impl MemoryRepr for bool {
fn write(&self, to: &mut [u8]) {
to.copy_from_slice(&[*self as u8]);
}
fn from_bytes(bytes: &[u8]) -> Self {
bytes[0] != 0
}
}
impl MemoryRepr for StringIndex {
fn write(&self, to: &mut [u8]) {
to.copy_from_slice(&self.0.to_le_bytes());
}
fn from_bytes(bytes: &[u8]) -> Self {
StringIndex(u64::from_le_bytes(bytes.try_into().unwrap()) as usize)
}
}
macro_rules! mem_repr {
($type:ty) => {
impl MemoryRepr for $type {
fn write(&self, to: &mut [u8]) {
to.copy_from_slice(&self.to_le_bytes());
}
fn from_bytes(bytes: &[u8]) -> Self {
<$type>::from_le_bytes(bytes.try_into().unwrap())
}
}
};
}
mem_repr!(u32);
mem_repr!(u64);
mem_repr!(u128);
mem_repr!(i32);
mem_repr!(i64);
mem_repr!(i128);
mem_repr!(f32);
mem_repr!(f64);
pub(crate) trait TypeExt {
fn vm_size_of(&self) -> usize;
}
impl TypeExt for somni_expr::Type {
fn vm_size_of(&self) -> usize {
match self {
Type::Void => <() as MemoryRepr>::BYTES,
Type::Int | Type::MaybeSignedInt => {
<<VmTypeSet as TypeSet>::Integer as MemoryRepr>::BYTES
}
Type::SignedInt => <<VmTypeSet as TypeSet>::SignedInteger as MemoryRepr>::BYTES,
Type::Float => <<VmTypeSet as TypeSet>::Float as MemoryRepr>::BYTES,
Type::Bool => <bool as MemoryRepr>::BYTES,
Type::String => <<VmTypeSet as TypeSet>::String as MemoryRepr>::BYTES,
Type::Iter => <u64 as MemoryRepr>::BYTES,
}
}
}
#[doc(hidden)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum TypedValue {
Void,
MaybeSignedInt(u64),
Int(u64),
SignedInt(i64),
Float(f64),
Bool(bool),
String(StringIndex),
Iter(usize),
}
impl From<TypedValue> for somni_expr::TypedValue<VmTypeSet> {
fn from(value: TypedValue) -> Self {
match value {
TypedValue::Void => somni_expr::TypedValue::Void,
TypedValue::MaybeSignedInt(inner) => somni_expr::TypedValue::MaybeSignedInt(inner),
TypedValue::Int(inner) => somni_expr::TypedValue::Int(inner),
TypedValue::SignedInt(inner) => somni_expr::TypedValue::SignedInt(inner),
TypedValue::Float(inner) => somni_expr::TypedValue::Float(inner),
TypedValue::Bool(inner) => somni_expr::TypedValue::Bool(inner),
TypedValue::String(inner) => somni_expr::TypedValue::String(inner),
TypedValue::Iter(inner) => somni_expr::TypedValue::Iter(inner),
}
}
}
impl From<somni_expr::TypedValue<VmTypeSet>> for TypedValue {
fn from(value: somni_expr::TypedValue<VmTypeSet>) -> Self {
match value {
somni_expr::TypedValue::Void => TypedValue::Void,
somni_expr::TypedValue::MaybeSignedInt(inner) => TypedValue::MaybeSignedInt(inner),
somni_expr::TypedValue::Int(inner) => TypedValue::Int(inner),
somni_expr::TypedValue::SignedInt(inner) => TypedValue::SignedInt(inner),
somni_expr::TypedValue::Float(inner) => TypedValue::Float(inner),
somni_expr::TypedValue::Bool(inner) => TypedValue::Bool(inner),
somni_expr::TypedValue::String(inner) => TypedValue::String(inner),
somni_expr::TypedValue::Iter(inner) => TypedValue::Iter(inner),
}
}
}
impl TypedValue {
pub fn type_of(&self) -> somni_expr::Type {
match self {
TypedValue::Void => Type::Void,
TypedValue::MaybeSignedInt(_) => Type::MaybeSignedInt,
TypedValue::Int(_) => Type::Int,
TypedValue::SignedInt(_) => Type::SignedInt,
TypedValue::Float(_) => Type::Float,
TypedValue::Bool(_) => Type::Bool,
TypedValue::String(_) => Type::String,
TypedValue::Iter(_) => Type::Iter,
}
}
pub(crate) fn write(&self, to: &mut [u8]) {
match self {
TypedValue::Void => ().write(to),
TypedValue::Int(value) | TypedValue::MaybeSignedInt(value) => value.write(to),
TypedValue::SignedInt(value) => value.write(to),
TypedValue::Float(value) => value.write(to),
TypedValue::Bool(value) => value.write(to),
TypedValue::String(value) => value.write(to),
TypedValue::Iter(value) => (*value as u64).write(to),
}
}
pub(crate) fn from_typed_bytes(ty: Type, value: &[u8]) -> TypedValue {
match ty {
Type::Void => Self::Void,
Type::Int => Self::Int(<_>::from_bytes(value)),
Type::MaybeSignedInt => Self::MaybeSignedInt(<_>::from_bytes(value)),
Type::SignedInt => Self::SignedInt(<_>::from_bytes(value)),
Type::Float => Self::Float(<_>::from_bytes(value)),
Type::Bool => Self::Bool(<_>::from_bytes(value)),
Type::String => Self::String(<_>::from_bytes(value)),
Type::Iter => Self::Iter(u64::from_bytes(value) as usize),
}
}
}
#[derive(Debug, Clone, Default)]
pub struct VmTypeSet {
strings: StringInterner,
iterators: Vec<SomniIter>,
}
impl VmTypeSet {
pub fn new(string_interner: StringInterner) -> Self {
Self {
strings: string_interner,
iterators: Vec::new(),
}
}
pub fn clear_iterators(&mut self) {
self.iterators.clear();
}
pub fn store_iterator(&mut self, iter: SomniIter) -> usize {
let handle = self.iterators.len();
self.iterators.push(iter);
handle
}
pub fn get_iterator(&self, handle: usize) -> Option<SomniIter> {
self.iterators.get(handle).cloned()
}
}
impl ParserTypeSet for VmTypeSet {
type Integer = u64;
type Float = f64;
}
impl TypeSet for VmTypeSet {
type Parser = Self;
type Integer = u64;
type SignedInteger = i64;
type Float = f64;
type String = StringIndex;
type Iterator = usize;
fn to_signed(v: Self::Integer) -> Result<Self::SignedInteger, OperatorError> {
i64::try_from(v).map_err(|_| OperatorError::RuntimeError)
}
fn to_usize(v: Self::Integer) -> Result<usize, OperatorError> {
usize::try_from(v).map_err(|_| OperatorError::RuntimeError)
}
fn int_from_usize(v: usize) -> Self::Integer {
Self::Integer::try_from(v).unwrap()
}
fn load_string<'s>(&'s self, str: &'s Self::String) -> &'s str {
self.strings.lookup(*str)
}
fn store_string(&mut self, str: &str) -> Self::String {
self.strings.intern(str)
}
fn iter_has_next(&self, handle: &Self::Iterator) -> bool {
self.iterators
.get(*handle)
.map(SomniIter::has_next)
.unwrap_or(false)
}
fn iter_next(&self, handle: &Self::Iterator) -> Option<ExprValue> {
self.iterators.get(*handle).and_then(SomniIter::next_value)
}
}