use std::borrow::Cow;
use serde_json::Value;
use crate::renderer::stack_frame::Val;
#[derive(Debug, PartialEq)]
pub enum ForLoopKind {
Value,
KeyValue,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ForLoopState {
Normal,
Break,
Continue,
}
#[derive(Debug)]
pub enum ForLoopValues<'a> {
Array(Val<'a>),
Object(Vec<(String, Val<'a>)>),
}
impl<'a> ForLoopValues<'a> {
pub fn current_key(&self, i: usize) -> String {
match *self {
ForLoopValues::Array(_) => unreachable!("No key in array list"),
ForLoopValues::Object(ref values) => {
values.get(i).expect("Failed getting current key").0.clone()
}
}
}
pub fn current_value(&self, i: usize) -> Val<'a> {
match *self {
ForLoopValues::Array(ref values) => match *values {
Cow::Borrowed(v) => {
Cow::Borrowed(v.as_array().expect("Is array").get(i).expect("Value"))
}
Cow::Owned(_) => {
Cow::Owned(values.as_array().expect("Is array").get(i).expect("Value").clone())
}
},
ForLoopValues::Object(ref values) => values.get(i).expect("Value").1.clone(),
}
}
}
#[derive(Debug)]
pub struct ForLoop<'a> {
pub key_name: Option<String>,
pub value_name: String,
pub current: usize,
pub values: ForLoopValues<'a>,
pub kind: ForLoopKind,
pub state: ForLoopState,
}
impl<'a> ForLoop<'a> {
pub fn from_array(value_name: &str, values: Val<'a>) -> Self {
ForLoop {
key_name: None,
value_name: value_name.to_string(),
current: 0,
values: ForLoopValues::Array(values),
kind: ForLoopKind::Value,
state: ForLoopState::Normal,
}
}
pub fn from_object(key_name: &str, value_name: &str, object: &'a Value) -> Self {
let object_values = object.as_object().unwrap();
let mut values = Vec::with_capacity(object_values.len());
for (k, v) in object_values {
values.push((k.to_string(), Cow::Borrowed(v)));
}
ForLoop {
key_name: Some(key_name.to_string()),
value_name: value_name.to_string(),
current: 0,
values: ForLoopValues::Object(values),
kind: ForLoopKind::KeyValue,
state: ForLoopState::Normal,
}
}
pub fn from_object_owned(key_name: &str, value_name: &str, object: Value) -> Self {
let object_values = match object {
Value::Object(c) => c,
_ => unreachable!(
"Tried to create a Forloop from an object owned but it wasn't an object"
),
};
let mut values = Vec::with_capacity(object_values.len());
for (k, v) in object_values {
values.push((k.to_string(), Cow::Owned(v)));
}
ForLoop {
key_name: Some(key_name.to_string()),
value_name: value_name.to_string(),
current: 0,
values: ForLoopValues::Object(values),
kind: ForLoopKind::KeyValue,
state: ForLoopState::Normal,
}
}
#[inline]
pub fn increment(&mut self) {
self.current += 1;
self.state = ForLoopState::Normal;
}
pub fn is_key_value(&self) -> bool {
self.kind == ForLoopKind::KeyValue
}
#[inline]
pub fn break_loop(&mut self) {
self.state = ForLoopState::Break;
}
#[inline]
pub fn continue_loop(&mut self) {
self.state = ForLoopState::Continue;
}
#[inline]
pub fn get_current_value(&self) -> Val<'a> {
self.values.current_value(self.current)
}
#[inline]
pub fn get_current_key(&self) -> String {
self.values.current_key(self.current)
}
pub fn is_key(&self, name: &str) -> bool {
if self.kind == ForLoopKind::Value {
return false;
}
if let Some(ref key_name) = self.key_name {
return key_name == name;
}
false
}
pub fn len(&self) -> usize {
match self.values {
ForLoopValues::Array(ref values) => values.as_array().expect("Value is array").len(),
ForLoopValues::Object(ref values) => values.len(),
}
}
}