use crate::{Ptr, Result, prelude::*};
use std::ops::{Deref, Range};
#[derive(Clone)]
pub struct KTuple(Inner);
#[derive(Clone)]
enum Inner {
Full(Ptr<Vec<KValue>>),
Slice(TupleSlice16),
SliceLarge(Ptr<TupleSlice>),
}
impl KTuple {
pub fn make_sub_tuple(&self, bounds: Range<usize>) -> Option<Self> {
let slice = match &self.0 {
Inner::Full(data) => TupleSlice::from(data.clone()),
Inner::SliceLarge(slice) => slice.deref().clone(),
Inner::Slice(slice) => TupleSlice::from(slice.clone()),
};
slice.with_bounds(bounds).map(Self::from)
}
pub fn data(&self) -> &[KValue] {
self.deref()
}
pub fn is_hashable(&self) -> bool {
self.iter().all(KValue::is_hashable)
}
pub fn pop_front(&mut self) -> Option<KValue> {
match &mut self.0 {
Inner::Full(data) => {
if let Some(value) = data.first().cloned() {
*self = Self::from(TupleSlice {
data: data.clone(),
bounds: 1..data.len(),
});
Some(value)
} else {
None
}
}
Inner::SliceLarge(slice) => {
if let Some(value) = slice.first().cloned() {
Ptr::make_mut(slice).bounds.start += 1;
Some(value)
} else {
None
}
}
Inner::Slice(slice) => {
if let Some(value) = slice.first().cloned() {
slice.bounds.start += 1;
Some(value)
} else {
None
}
}
}
}
pub fn pop_back(&mut self) -> Option<KValue> {
match &mut self.0 {
Inner::Full(data) => {
if let Some(value) = data.last().cloned() {
*self = Self::from(TupleSlice {
data: data.clone(),
bounds: 0..data.len() - 1,
});
Some(value)
} else {
None
}
}
Inner::SliceLarge(slice) => {
if let Some(value) = slice.last().cloned() {
Ptr::make_mut(slice).bounds.end -= 1;
Some(value)
} else {
None
}
}
Inner::Slice(slice) => {
if let Some(value) = slice.last().cloned() {
slice.bounds.end -= 1;
Some(value)
} else {
None
}
}
}
}
pub fn is_same_instance(&self, other: &Self) -> bool {
let ptr_and_bounds = |tuple: &Self| match &tuple.0 {
Inner::Full(data) => (Ptr::address(data), 0..data.len()),
Inner::Slice(slice) => (
Ptr::address(&slice.data),
slice.bounds.start as usize..slice.bounds.end as usize,
),
Inner::SliceLarge(slice) => (Ptr::address(&slice.data), slice.bounds.clone()),
};
let (ptr_a, bounds_a) = ptr_and_bounds(self);
let (ptr_b, bounds_b) = ptr_and_bounds(other);
ptr_a == ptr_b && bounds_a == bounds_b
}
pub fn display(&self, ctx: &mut DisplayContext) -> Result<()> {
let id = Ptr::address(match &self.0 {
Inner::Full(data) => data,
Inner::SliceLarge(slice) => &slice.data,
Inner::Slice(slice) => &slice.data,
});
ctx.push_container(id);
ctx.append('(');
for (i, value) in self.iter().enumerate() {
if i > 0 {
ctx.append(", ");
}
value.display(ctx)?;
}
ctx.append(')');
ctx.pop_container();
Ok(())
}
}
impl Deref for KTuple {
type Target = [KValue];
fn deref(&self) -> &[KValue] {
match &self.0 {
Inner::Full(data) => data,
Inner::Slice(slice) => slice.deref(),
Inner::SliceLarge(slice) => slice.deref(),
}
}
}
thread_local! {
static EMPTY_TUPLE: Ptr<Vec<KValue>> = Vec::new().into();
}
impl Default for KTuple {
fn default() -> Self {
Self::from(EMPTY_TUPLE.with(|x| x.clone()))
}
}
impl From<Ptr<Vec<KValue>>> for KTuple {
fn from(data: Ptr<Vec<KValue>>) -> Self {
Self(Inner::Full(data))
}
}
impl From<Vec<KValue>> for KTuple {
fn from(data: Vec<KValue>) -> Self {
Self(Inner::Full(data.into()))
}
}
impl From<&[KValue]> for KTuple {
fn from(data: &[KValue]) -> Self {
Self(Inner::Full(data.to_vec().into()))
}
}
impl<const N: usize> From<&[KValue; N]> for KTuple {
fn from(data: &[KValue; N]) -> Self {
Self::from(data.as_slice())
}
}
impl From<TupleSlice> for KTuple {
fn from(slice: TupleSlice) -> Self {
match TupleSlice16::try_from(slice) {
Ok(slice16) => Self::from(slice16),
Err(slice) => Self(Inner::SliceLarge(slice.into())),
}
}
}
impl From<TupleSlice16> for KTuple {
fn from(slice: TupleSlice16) -> Self {
Self(Inner::Slice(slice))
}
}
#[derive(Clone)]
struct TupleSlice {
data: Ptr<Vec<KValue>>,
bounds: Range<usize>,
}
impl TupleSlice {
pub fn with_bounds(&self, bounds: Range<usize>) -> Option<Self> {
let new_bounds = (bounds.start + self.bounds.start)..(bounds.end + self.bounds.start);
if self.data.get(new_bounds.clone()).is_some() {
Some(Self {
data: self.data.clone(),
bounds: new_bounds,
})
} else {
None
}
}
}
impl Deref for TupleSlice {
type Target = [KValue];
fn deref(&self) -> &[KValue] {
unsafe { self.data.get_unchecked(self.bounds.clone()) }
}
}
impl From<Ptr<Vec<KValue>>> for TupleSlice {
fn from(data: Ptr<Vec<KValue>>) -> Self {
let bounds = 0..data.len();
Self { data, bounds }
}
}
impl From<TupleSlice16> for TupleSlice {
fn from(slice: TupleSlice16) -> Self {
Self {
data: slice.data,
bounds: u16_to_usize_range(slice.bounds),
}
}
}
#[derive(Clone)]
struct TupleSlice16 {
data: Ptr<Vec<KValue>>,
bounds: Range<u16>,
_niche_placeholder: ZeroU8,
}
impl Deref for TupleSlice16 {
type Target = [KValue];
fn deref(&self) -> &[KValue] {
unsafe {
self.data
.get_unchecked(u16_to_usize_range(self.bounds.clone()))
}
}
}
impl TryFrom<TupleSlice> for TupleSlice16 {
type Error = TupleSlice;
fn try_from(slice: TupleSlice) -> std::result::Result<Self, Self::Error> {
usize_to_u16_range(slice.bounds.clone())
.map(|bounds| Self {
data: slice.data.clone(),
bounds,
_niche_placeholder: ZeroU8::Zero,
})
.ok_or(slice)
}
}
#[repr(u8)]
#[derive(Clone)]
enum ZeroU8 {
Zero = 0,
}
fn u16_to_usize_range(r: Range<u16>) -> Range<usize> {
r.start as usize..r.end as usize
}
fn usize_to_u16_range(r: Range<usize>) -> Option<Range<u16>> {
match (u16::try_from(r.start), u16::try_from(r.end)) {
(Ok(start), Ok(end)) => Some(start..end),
_ => None,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_tuple_mem_size() {
assert!(std::mem::size_of::<KTuple>() <= 16);
}
#[test]
fn subtuple_of_subtuple() {
let t = KTuple::from(&[KValue::from(0), 1.into(), 2.into()]);
let t2 = t.make_sub_tuple(1..3).unwrap();
assert_eq!(t2.len(), 2);
let t3 = t2.make_sub_tuple(1..2).unwrap();
assert_eq!(t3.len(), 1);
assert!(matches!(t3[0], KValue::Number(n) if usize::from(n) == 2));
}
}