use std::{cell::RefCell, error::Error, fmt::Display, mem, ops::Index, rc::Rc};
use crate::{FromRant, RantFunction, RantFunctionInterface, RantFunctionRef, RantValue, ValueError, lang::{Block, BlockElement, PrintFlag, Sequence}, rng::RantRng, runtime_error};
use smallvec::SmallVec;
use super::{IntoRuntimeResult, RuntimeError, RuntimeErrorType, RuntimeResult, StackFrameFlavor};
pub type SelectorRef = Rc<RefCell<Selector>>;
const MAX_ATTR_FRAMES: usize = 255;
const BLOCK_STACK_INLINE_COUNT: usize = 4;
pub struct Resolver {
rng: Rc<RantRng>,
base_attrs: AttributeFrame,
attr_override_stack: Vec<AttributeFrame>,
block_stack: SmallVec<[BlockState; BLOCK_STACK_INLINE_COUNT]>,
}
pub enum BlockAction {
Element(Rc<Sequence>),
PipedElement { elem_func: RantFunctionRef, pipe_func: RantFunctionRef },
Separator(RantValue),
}
#[derive(Debug)]
pub struct Weights {
weights: Vec<f64>,
sum: f64,
}
impl Weights {
#[inline]
pub fn new(capacity: usize) -> Self {
Self {
weights: Vec::with_capacity(capacity),
sum: 0.0,
}
}
#[inline]
pub fn push(&mut self, weight: f64) {
let weight = if weight <= 0.0 || weight.is_normal() {
weight.max(0.0)
} else {
1.0
};
self.weights.push(weight);
self.sum += weight;
}
#[inline]
pub fn len(&self) -> usize {
self.weights.len()
}
#[inline]
pub fn sum(&self) -> f64 {
self.sum
}
#[inline]
pub fn is_zero(&self) -> bool {
self.sum <= 0.0
}
#[inline]
pub fn is_empty(&self) -> bool {
self.weights.is_empty()
}
#[inline]
pub fn as_slice(&self) -> &[f64] {
self.weights.as_slice()
}
}
impl Index<usize> for Weights {
type Output = f64;
#[inline]
fn index(&self, index: usize) -> &Self::Output {
&self.weights[index]
}
}
#[derive(Debug)]
pub struct BlockState {
elements: Rc<Vec<BlockElement>>,
weights: Option<Weights>,
force_stop: bool,
flag: PrintFlag,
attrs: AttributeFrame,
cur_steps: usize,
total_steps: usize,
prev_step_separated: bool,
}
impl BlockState {
#[inline]
pub fn next_element(&mut self, rng: &RantRng) -> Result<Option<BlockAction>, SelectorError> {
if self.is_done() || self.elements.is_empty() || self.weights.as_ref().map_or(false, |weights| weights.is_zero()) {
return Ok(None)
}
if self.cur_steps == 0 || self.prev_step_separated {
self.prev_step_separated = false;
self.cur_steps += 1;
let next_index = self.attrs.selector.as_ref().map_or_else(
|| {
Ok(if let Some(weights) = &self.weights {
rng.next_usize_weighted(self.elements.len(), weights.as_slice(), weights.sum)
} else {
rng.next_usize(self.elements.len())
})
},
|sel| sel.borrow_mut().select(self.elements.len(), rng)
)?;
let next_elem = Rc::clone(&self.elements[next_index].main);
if let Some(pipe_func) = self.attrs.pipe.as_ref() {
let elem_func = RantFunction {
captured_vars: vec![],
min_arg_count: 0,
vararg_start_index: 0,
params: Rc::new(vec![]),
body: RantFunctionInterface::User(next_elem),
flavor: Some(if self.is_repeater() {
StackFrameFlavor::RepeaterElement
} else {
StackFrameFlavor::BlockElement
})
};
return Ok(Some(BlockAction::PipedElement {
pipe_func: Rc::clone(pipe_func),
elem_func: Rc::new(elem_func),
}))
}
Ok(Some(BlockAction::Element(next_elem)))
} else {
self.prev_step_separated = true;
Ok(Some(BlockAction::Separator(self.attrs.separator.clone())))
}
}
#[inline(always)]
pub fn force_stop(&mut self) {
self.force_stop = true;
}
#[inline]
pub fn step_index(&self) -> usize {
self.cur_steps - 1
}
#[inline]
pub fn step(&self) -> usize {
self.cur_steps
}
#[inline]
pub fn step_count(&self) -> usize {
self.total_steps
}
#[inline]
pub fn is_repeater(&self) -> bool {
matches!(self.attrs.reps, Reps::Repeat(_) | Reps::RepeatForever | Reps::All)
}
#[inline]
pub fn is_piped(&self) -> bool {
self.attrs.pipe.is_some()
}
#[inline(always)]
pub(crate) fn is_done(&self) -> bool {
self.force_stop
|| !self.attrs.condval.unwrap_or(true)
|| (!self.attrs.reps.is_infinite() && self.cur_steps >= self.total_steps)
}
#[inline(always)]
pub fn flag(&self) -> PrintFlag {
self.flag
}
}
#[derive(Debug, Copy, Clone)]
pub enum Reps {
RepeatForever,
All,
Repeat(usize),
Once,
}
impl Reps {
#[inline(always)]
pub fn is_infinite(&self) -> bool {
matches!(self, Reps::RepeatForever)
}
#[inline(always)]
pub fn is_all(&self) -> bool {
matches!(self, Reps::All)
}
#[inline]
pub fn get_rep_count_for(&self, block: &Block) -> usize {
match self {
Reps::RepeatForever => 0,
Reps::Once => 1,
Reps::All => block.len(),
Reps::Repeat(n) => *n,
}
}
}
impl Resolver {
pub fn new(rng: &Rc<RantRng>) -> Self {
Self {
rng: rng.clone(),
base_attrs: Default::default(),
attr_override_stack: vec![Default::default()],
block_stack: Default::default(),
}
}
}
impl Resolver {
#[inline]
pub fn push_block(&mut self, block: &Block, weights: Option<Weights>, flag: PrintFlag) {
let attrs = self.take_attrs();
let state = BlockState {
elements: Rc::clone(&block.elements),
weights,
flag: PrintFlag::prioritize(block.flag, flag),
cur_steps: 0,
total_steps: attrs.reps.get_rep_count_for(block),
attrs,
prev_step_separated: false,
force_stop: false,
};
self.block_stack.push(state);
}
#[inline]
pub fn block_stack_len(&self) -> usize {
self.block_stack.len()
}
#[inline]
pub fn pop_block(&mut self) -> Option<BlockState> {
self.block_stack.pop()
}
#[inline]
pub fn active_block(&self) -> Option<&BlockState> {
self.block_stack.last()
}
#[inline]
pub fn active_block_mut(&mut self) -> Option<&mut BlockState> {
self.block_stack.last_mut()
}
#[inline]
pub fn active_repeater_mut(&mut self) -> Option<&mut BlockState> {
self.block_stack
.iter_mut()
.rev()
.find(|b| b.is_repeater())
}
#[inline]
pub fn active_repeater(&self) -> Option<&BlockState> {
self.block_stack
.iter()
.rev()
.find(|b| b.is_repeater())
}
#[inline]
pub fn take_attrs(&mut self) -> AttributeFrame {
if self.attr_override_stack.is_empty() {
let next_attr = AttributeFrame::propagate(&self.base_attrs);
mem::replace(&mut self.base_attrs, next_attr)
} else {
let last_attr = self.attr_override_stack.last_mut().unwrap();
let next_attr = AttributeFrame::propagate(last_attr);
mem::replace(last_attr, next_attr)
}
}
#[inline]
pub fn reset_attrs(&mut self) {
if self.attr_override_stack.is_empty() {
mem::take(&mut self.base_attrs);
} else {
mem::take(self.attr_override_stack.last_mut().unwrap());
}
}
pub fn push_attrs(&mut self) -> RuntimeResult<()> {
if self.attr_override_stack.len() >= MAX_ATTR_FRAMES {
runtime_error!(RuntimeErrorType::StackOverflow, "attribute frame stack has overflowed")
}
self.attr_override_stack.push(Default::default());
Ok(())
}
pub fn pop_attrs(&mut self) -> Option<AttributeFrame> {
self.attr_override_stack.pop()
}
pub fn count_attrs(&self) -> usize {
self.attr_override_stack.len() + 1
}
#[inline]
pub fn attrs(&self) -> &AttributeFrame {
if self.attr_override_stack.is_empty() {
&self.base_attrs
} else {
self.attr_override_stack.last().unwrap()
}
}
#[inline]
pub fn attrs_mut(&mut self) -> &mut AttributeFrame {
if self.attr_override_stack.is_empty() {
&mut self.base_attrs
} else {
self.attr_override_stack.last_mut().unwrap()
}
}
}
#[derive(Debug)]
pub struct AttributeFrame {
pub condval: Option<bool>,
pub prev_condval: Option<bool>,
pub no_propagate_condval: bool,
pub reps: Reps,
pub separator: RantValue,
pub selector: Option<SelectorRef>,
pub pipe: Option<RantFunctionRef>,
}
impl AttributeFrame {
pub fn propagate(frame: &AttributeFrame) -> Self {
Self {
prev_condval: if frame.no_propagate_condval { None } else { frame.condval },
.. Default::default()
}
}
#[inline]
pub fn make_if(&mut self, cond_val: bool) {
self.condval = Some(cond_val);
self.no_propagate_condval = cond_val;
}
#[inline]
pub fn make_else(&mut self) {
self.condval = Some(self.prev_condval.map(|b| !b).unwrap_or(false));
self.no_propagate_condval = true;
}
#[inline]
pub fn make_else_if(&mut self, cond_val: bool) {
let has_propagated_condval = self.prev_condval.is_none();
self.condval = Some(self.prev_condval.map(|b| !b && cond_val).unwrap_or(false));
self.no_propagate_condval = cond_val || has_propagated_condval;
}
}
impl Default for AttributeFrame {
fn default() -> Self {
Self {
condval: None,
prev_condval: None,
no_propagate_condval: false,
reps: Reps::Once,
separator: RantValue::Empty,
selector: None,
pipe: None,
}
}
}
#[derive(Debug)]
pub struct Selector {
mode: SelectorMode,
index: usize,
count: usize,
parity: bool,
jump_table: Vec<usize>,
}
impl Selector {
#[inline]
pub fn new(mode: SelectorMode) -> Self {
Self {
mode,
index: 0,
count: 0,
parity: false,
jump_table: Default::default(),
}
}
#[inline]
pub fn is_initialized(&self) -> bool {
self.count > 0
}
#[inline]
pub fn init(&mut self, rng: &RantRng, elem_count: usize) -> Result<(), SelectorError> {
if elem_count == 0 {
return Err(SelectorError::InvalidElementCount(0))
}
self.count = elem_count;
match self.mode {
SelectorMode::Random | SelectorMode::One | SelectorMode::NoDouble => {
self.index = rng.next_usize(elem_count);
},
SelectorMode::Forward | SelectorMode::ForwardClamp | SelectorMode::ForwardMirror | SelectorMode::Ping => {
self.index = 0;
},
SelectorMode::Reverse | SelectorMode::ReverseClamp | SelectorMode::ReverseMirror | SelectorMode::Pong => {
self.index = elem_count - 1;
},
SelectorMode::Deck | SelectorMode::DeckLoop | SelectorMode::DeckClamp | SelectorMode::DeckMirror => {
self.shuffle(rng);
},
}
Ok(())
}
#[inline]
fn shuffle(&mut self, rng: &RantRng) {
let jump_table = &mut self.jump_table;
let n = self.count;
if jump_table.is_empty() {
jump_table.reserve(n);
jump_table.extend(0..n);
}
for i in 0..n {
jump_table.swap(i, rng.next_usize(n));
}
}
pub fn select(&mut self, elem_count: usize, rng: &RantRng) -> Result<usize, SelectorError> {
if !self.is_initialized() {
self.init(rng, elem_count)?;
} else if elem_count != self.count {
return Err(SelectorError::ElementCountMismatch {
expected: self.count,
found: elem_count,
})
}
let cur_index = self.index;
match self.mode {
SelectorMode::Random => {
self.index = rng.next_usize(elem_count);
},
SelectorMode::One => {},
SelectorMode::Forward => {
self.index = (cur_index + 1) % elem_count;
},
SelectorMode::ForwardClamp => {
self.index = (cur_index + 1).min(elem_count - 1);
},
SelectorMode::ForwardMirror => {
let prev_parity = self.parity;
if (prev_parity && cur_index == 0) || (!prev_parity && cur_index == elem_count - 1) {
self.parity = !prev_parity;
} else if self.parity {
self.index = cur_index.saturating_sub(1);
} else {
self.index = (cur_index + 1) % elem_count;
}
},
SelectorMode::Reverse => {
self.index = if cur_index == 0 {
elem_count
} else {
cur_index
} - 1;
},
SelectorMode::ReverseClamp => {
self.index = cur_index.saturating_sub(1);
},
SelectorMode::ReverseMirror => {
let prev_parity = self.parity;
if (!prev_parity && cur_index == 0) || (prev_parity && cur_index == elem_count - 1) {
self.parity = !prev_parity;
} else if self.parity {
self.index = (cur_index + 1) % elem_count;
} else {
self.index = cur_index.saturating_sub(1);
}
},
SelectorMode::Deck => {
let jump_index = self.jump_table[cur_index];
if cur_index >= elem_count - 1 {
self.shuffle(rng);
self.index = 0;
} else {
self.index = cur_index + 1;
}
return Ok(jump_index)
},
SelectorMode::DeckMirror => {
let jump_index = self.jump_table[cur_index];
let cur_parity = self.parity;
if (cur_parity && cur_index == 0) || (!cur_parity && cur_index >= elem_count - 1) {
if cur_parity {
self.shuffle(rng);
}
self.parity = !cur_parity;
} else if self.parity {
self.index = cur_index.saturating_sub(1);
} else {
self.index = (cur_index + 1).min(elem_count - 1);
}
return Ok(jump_index)
},
SelectorMode::DeckLoop => {
self.index = (cur_index + 1) % elem_count;
return Ok(self.jump_table[cur_index])
},
SelectorMode::DeckClamp => {
self.index = (cur_index + 1).min(elem_count - 1);
return Ok(self.jump_table[cur_index])
},
SelectorMode::Ping => {
let prev_parity = self.parity;
if (prev_parity && cur_index == 0) || (!prev_parity && cur_index >= elem_count - 1) {
self.parity = !prev_parity;
}
if self.parity {
self.index = cur_index.saturating_sub(1);
} else {
self.index = (cur_index + 1) % elem_count;
}
},
SelectorMode::Pong => {
let prev_parity = self.parity;
if (!prev_parity && cur_index == 0) || (prev_parity && cur_index >= elem_count - 1) {
self.parity = !prev_parity;
}
if self.parity {
self.index = (cur_index + 1) % elem_count;
} else {
self.index = cur_index.saturating_sub(1);
}
},
SelectorMode::NoDouble => {
self.index = if elem_count > 1 {
(cur_index + 1 + rng.next_usize(elem_count - 1)) % elem_count
} else {
0
};
},
}
Ok(cur_index)
}
}
#[derive(Debug)]
pub enum SelectorError {
ElementCountMismatch { expected: usize, found: usize },
InvalidElementCount(usize),
}
impl Error for SelectorError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
None
}
fn cause(&self) -> Option<&dyn Error> {
self.source()
}
}
impl Display for SelectorError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
SelectorError::ElementCountMismatch { expected, found } => write!(f, "selector expected {} elements, but found {}", expected, found),
SelectorError::InvalidElementCount(n) => write!(f, "selector does not support blocks of size {}", n),
}
}
}
impl<T> IntoRuntimeResult<T> for Result<T, SelectorError> {
fn into_runtime_result(self) -> super::RuntimeResult<T> {
self.map_err(|err| RuntimeError {
error_type: super::RuntimeErrorType::SelectorError(err),
description: None,
stack_trace: None,
})
}
}
#[derive(Debug)]
#[repr(u8)]
pub enum SelectorMode {
Random,
One,
Forward,
ForwardClamp,
ForwardMirror,
Reverse,
ReverseClamp,
ReverseMirror,
Deck,
DeckLoop,
DeckClamp,
DeckMirror,
Ping,
Pong,
NoDouble,
}
impl FromRant for SelectorMode {
fn from_rant(val: RantValue) -> Result<Self, ValueError> {
match &val {
RantValue::String(s) => {
Ok(match s.as_str() {
"random" => SelectorMode::Random,
"one" => SelectorMode::One,
"forward" => SelectorMode::Forward,
"forward-clamp" => SelectorMode::ForwardClamp,
"forward-mirror" => SelectorMode::ForwardMirror,
"reverse" => SelectorMode::Reverse,
"reverse-clamp" => SelectorMode::ReverseClamp,
"reverse-mirror" => SelectorMode::ReverseMirror,
"deck" => SelectorMode::Deck,
"deck-loop" => SelectorMode::DeckLoop,
"deck-clamp" => SelectorMode::DeckClamp,
"deck-mirror" => SelectorMode::DeckMirror,
"ping" => SelectorMode::Ping,
"pong" => SelectorMode::Pong,
"no-double" => SelectorMode::NoDouble,
_ => return Err(ValueError::InvalidConversion {
from: val.type_name(),
to: "selector mode",
message: Some(format!("invalid selector mode: '{}'", s))
})
})
},
_ => Err(ValueError::InvalidConversion {
from: val.type_name(),
to: "selector mode",
message: None,
})
}
}
fn is_rant_optional() -> bool {
false
}
}