use crate::LoxValue;
use crate::LoxValueType;
use std::vec;
#[non_exhaustive]
pub enum IntoIter {
#[doc(hidden)] Array(vec::IntoIter<LoxValue>),
#[doc(hidden)] String(vec::IntoIter<u8>),
}
const CONT_MASK: u8 = 0b0011_1111;
const fn utf8_first_byte(byte: u8, width: u32) -> u32 {
(byte & (0x7F >> width)) as u32
}
const fn utf8_acc_cont_byte(ch: u32, byte: u8) -> u32 {
(ch << 6) | (byte & CONT_MASK) as u32
}
fn next_code_point<I: Iterator<Item = u8>>(bytes: &mut I) -> Option<u32> {
let x = bytes.next()?;
if x < 128 {
return Some(u32::from(x));
}
let init = utf8_first_byte(x, 2);
let y = bytes.next().unwrap();
let mut ch = utf8_acc_cont_byte(init, y);
if x >= 0xE0 {
let z = bytes.next().unwrap();
let y_z = utf8_acc_cont_byte(u32::from(y & CONT_MASK), z);
ch = init << 12 | y_z;
if x >= 0xF0 {
let w = bytes.next().unwrap();
ch = (init & 7) << 18 | utf8_acc_cont_byte(y_z, w);
}
}
Some(ch)
}
impl Iterator for IntoIter {
type Item = LoxValue;
fn next(&mut self) -> Option<Self::Item> {
match self {
IntoIter::Array(iter) => iter.next(),
IntoIter::String(bytes) => Some(LoxValue::Str(
char::from_u32(next_code_point(bytes)?)
.unwrap()
.to_string()
.into(),
)),
}
}
}
impl IntoIterator for LoxValue {
type Item = Self;
type IntoIter = IntoIter;
fn into_iter(self) -> Self::IntoIter {
match self {
Self::Arr(arr) => IntoIter::Array(arr.read().clone().into_iter()),
Self::Str(string) => IntoIter::String(string.to_string().into_bytes().into_iter()),
_ => panic!("cannot convert {} into iterator", LoxValueType::from(self)),
}
}
}