940251b87f
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>
127 lines
2.9 KiB
Rust
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]
|
|
}
|
|
}
|