This vector type has served us well for now, but it contains internal refcounts
which are incompatible with upcoming changes related to garbage collection.
The performance impact of this change within all benchmarks I ran was within the
margin of error:
[nix-shell:/tmp/perf]$ hyperfine "./before -E '(import <nixpkgs> {}).firefox.outPath' --log-level ERROR --no-warnings"
Benchmark 1: ./u64 -E '(import <nixpkgs> {}).firefox.outPath' --log-level ERROR --no-warnings
Time (mean ± σ): 7.528 s ± 0.272 s [User: 6.578 s, System: 0.631 s]
Range (min … max): 7.160 s … 8.012 s 10 runs
nix-shell:/tmp/perf]$ hyperfine "./std-vec -E '(import <nixpkgs> {}).firefox.outPath' --log-level ERROR --no-warnings"
Benchmark 1: ./std-vec -E '(import <nixpkgs> {}).firefox.outPath' --log-level ERROR --no-warnings
Time (mean ± σ): 7.515 s ± 0.178 s [User: 6.508 s, System: 0.652 s]
Range (min … max): 7.276 s … 7.861 s 10 runs
Change-Id: Ib95f871956e336a1e5771f6293583854b1efb276
Reviewed-on: https://cl.tvl.fyi/c/depot/+/12197
Reviewed-by: aspen <root@gws.fyi>
Tested-by: BuildkiteCI
95 lines
2 KiB
Rust
95 lines
2 KiB
Rust
//! This module implements Nix lists.
|
|
use std::ops::Index;
|
|
use std::rc::Rc;
|
|
|
|
use serde::Deserialize;
|
|
|
|
use super::thunk::ThunkSet;
|
|
use super::TotalDisplay;
|
|
use super::Value;
|
|
|
|
#[repr(transparent)]
|
|
#[derive(Clone, Debug, Deserialize)]
|
|
pub struct NixList(Rc<Vec<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<Vec<Value>> for NixList {
|
|
fn from(vs: Vec<Value>) -> Self {
|
|
Self(Rc::new(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(Rc::new(stack_slice))
|
|
}
|
|
|
|
pub fn iter(&self) -> std::slice::Iter<Value> {
|
|
self.0.iter()
|
|
}
|
|
|
|
pub fn ptr_eq(&self, other: &Self) -> bool {
|
|
Rc::ptr_eq(&self.0, &other.0)
|
|
}
|
|
|
|
pub fn into_inner(self) -> Vec<Value> {
|
|
Rc::try_unwrap(self.0).unwrap_or_else(|rc| (*rc).clone())
|
|
}
|
|
}
|
|
|
|
impl IntoIterator for NixList {
|
|
type Item = Value;
|
|
type IntoIter = std::vec::IntoIter<Value>;
|
|
|
|
fn into_iter(self) -> Self::IntoIter {
|
|
self.into_inner().into_iter()
|
|
}
|
|
}
|
|
|
|
impl<'a> IntoIterator for &'a NixList {
|
|
type Item = &'a Value;
|
|
type IntoIter = std::slice::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]
|
|
}
|
|
}
|