tvl-depot/tvix/eval/src/value/list.rs
Vincent Ambo 940251b87f refactor(tvix/value): use proptest strategies from imbl crate
Instead of going through Vec/BTreeMap for generating our internal
types, use the proptest strategies from imbl.

The one thing I couldn't figure out in the previous implementation is
where the ranges/sizes of generated collections came from. The
strategies in proptest use different types (Range, with an unknown
default value, and SizeRange with 0..100). I've opted to specify
0..100 directly, but we can probably make it configurable.

Change-Id: I749bc4c703fe424099240cab822b1642e5216361
Reviewed-on: https://cl.tvl.fyi/c/depot/+/7791
Autosubmit: tazjin <tazjin@tvl.su>
Tested-by: BuildkiteCI
Reviewed-by: flokli <flokli@flokli.de>
2023-01-17 10:20:38 +00:00

127 lines
2.9 KiB
Rust

//! This module implements Nix lists.
use std::ops::Index;
use imbl::{vector, Vector};
use serde::{Deserialize, Serialize};
use crate::errors::ErrorKind;
use crate::vm::VM;
use super::thunk::ThunkSet;
use super::TotalDisplay;
use super::Value;
#[repr(transparent)]
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct NixList(Vector<Value>);
impl TotalDisplay for NixList {
fn total_fmt(&self, f: &mut std::fmt::Formatter<'_>, set: &mut ThunkSet) -> std::fmt::Result {
f.write_str("[ ")?;
for v in self {
v.total_fmt(f, set)?;
f.write_str(" ")?;
}
f.write_str("]")
}
}
impl From<Vector<Value>> for NixList {
fn from(vs: Vector<Value>) -> Self {
Self(vs)
}
}
impl NixList {
pub fn len(&self) -> usize {
self.0.len()
}
pub fn get(&self, i: usize) -> Option<&Value> {
self.0.get(i)
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn construct(count: usize, stack_slice: Vec<Value>) -> Self {
debug_assert!(
count == stack_slice.len(),
"NixList::construct called with count == {}, but slice.len() == {}",
count,
stack_slice.len(),
);
NixList(Vector::from_iter(stack_slice.into_iter()))
}
pub fn iter(&self) -> vector::Iter<Value> {
self.0.iter()
}
pub fn ptr_eq(&self, other: &Self) -> bool {
self.0.ptr_eq(&other.0)
}
/// Compare `self` against `other` for equality using Nix equality semantics
pub fn nix_eq(&self, other: &Self, vm: &mut VM) -> Result<bool, ErrorKind> {
if self.ptr_eq(other) {
return Ok(true);
}
if self.len() != other.len() {
return Ok(false);
}
for (v1, v2) in self.iter().zip(other.iter()) {
if !v1.nix_eq(v2, vm)? {
return Ok(false);
}
}
Ok(true)
}
/// force each element of the list (shallowly), making it safe to call .get().value()
pub fn force_elements(&self, vm: &mut VM) -> Result<(), ErrorKind> {
self.iter().try_for_each(|v| v.force(vm).map(|_| ()))
}
pub fn into_inner(self) -> Vector<Value> {
self.0
}
#[deprecated(note = "callers should avoid constructing from Vec")]
pub fn from_vec(vs: Vec<Value>) -> Self {
Self(Vector::from_iter(vs.into_iter()))
}
}
impl IntoIterator for NixList {
type Item = Value;
type IntoIter = imbl::vector::ConsumingIter<Value>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<'a> IntoIterator for &'a NixList {
type Item = &'a Value;
type IntoIter = imbl::vector::Iter<'a, Value>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
impl Index<usize> for NixList {
type Output = Value;
fn index(&self, index: usize) -> &Self::Output {
&self.0[index]
}
}