refactor(tvix/eval): persistent, memory-sharing OrdMap for NixAttrs
This uses the `im::OrdMap` for `NixAttrs` to enable sharing of memory between different iterations of a map. This slightly speeds up eval, but not significantly. Future work might include benchmarking whether using a `HashMap` and only ordering in cases where order is actually required would help. This switches to a fork of `im` that fixes some bugs with its OrdMap implementation. Change-Id: I2f6a5ff471b6d508c1e8a98b13f889f49c0d9537 Reviewed-on: https://cl.tvl.fyi/c/depot/+/7676 Reviewed-by: sterni <sternenseemann@systemli.org> Tested-by: BuildkiteCI
This commit is contained in:
parent
610c44ec1e
commit
91465dc78e
10 changed files with 144 additions and 172 deletions
43
corp/tvixbolt/Cargo.lock
generated
43
corp/tvixbolt/Cargo.lock
generated
|
@ -36,12 +36,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitmaps"
|
name = "bitmaps"
|
||||||
version = "2.1.0"
|
version = "3.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2"
|
checksum = "703642b98a00b3b90513279a8ede3fcfa479c126c5fb46e78f3051522f021403"
|
||||||
dependencies = [
|
|
||||||
"typenum",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "boolinator"
|
name = "boolinator"
|
||||||
|
@ -283,19 +280,27 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "im"
|
name = "imbl"
|
||||||
version = "15.1.0"
|
version = "2.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d0acd33ff0285af998aaf9b57342af478078f53492322fafc47450e09397e0e9"
|
checksum = "c2806b69cd9f4664844027b64465eacb444c67c1db9c778e341adff0c25cdb0d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitmaps",
|
"bitmaps",
|
||||||
|
"imbl-sized-chunks",
|
||||||
"rand_core",
|
"rand_core",
|
||||||
"rand_xoshiro",
|
"rand_xoshiro",
|
||||||
"sized-chunks",
|
|
||||||
"typenum",
|
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "imbl-sized-chunks"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6957ea0b2541c5ca561d3ef4538044af79f8a05a1eb3a3b148936aaceaa1076"
|
||||||
|
dependencies = [
|
||||||
|
"bitmaps",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "1.9.1"
|
version = "1.9.1"
|
||||||
|
@ -570,16 +575,6 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sized-chunks"
|
|
||||||
version = "0.6.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e"
|
|
||||||
dependencies = [
|
|
||||||
"bitmaps",
|
|
||||||
"typenum",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slab"
|
name = "slab"
|
||||||
version = "0.4.7"
|
version = "0.4.7"
|
||||||
|
@ -660,7 +655,7 @@ dependencies = [
|
||||||
"codemap",
|
"codemap",
|
||||||
"codemap-diagnostic",
|
"codemap-diagnostic",
|
||||||
"dirs",
|
"dirs",
|
||||||
"im",
|
"imbl",
|
||||||
"path-clean",
|
"path-clean",
|
||||||
"regex",
|
"regex",
|
||||||
"rnix",
|
"rnix",
|
||||||
|
@ -696,12 +691,6 @@ dependencies = [
|
||||||
"yew-router",
|
"yew-router",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "typenum"
|
|
||||||
version = "1.16.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.4"
|
version = "1.0.4"
|
||||||
|
|
37
tvix/Cargo.lock
generated
37
tvix/Cargo.lock
generated
|
@ -185,12 +185,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitmaps"
|
name = "bitmaps"
|
||||||
version = "2.1.0"
|
version = "3.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2"
|
checksum = "703642b98a00b3b90513279a8ede3fcfa479c126c5fb46e78f3051522f021403"
|
||||||
dependencies = [
|
|
||||||
"typenum",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "blake3"
|
name = "blake3"
|
||||||
|
@ -829,19 +826,27 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "im"
|
name = "imbl"
|
||||||
version = "15.1.0"
|
version = "2.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d0acd33ff0285af998aaf9b57342af478078f53492322fafc47450e09397e0e9"
|
checksum = "c2806b69cd9f4664844027b64465eacb444c67c1db9c778e341adff0c25cdb0d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitmaps",
|
"bitmaps",
|
||||||
|
"imbl-sized-chunks",
|
||||||
"rand_core 0.6.4",
|
"rand_core 0.6.4",
|
||||||
"rand_xoshiro",
|
"rand_xoshiro",
|
||||||
"sized-chunks",
|
|
||||||
"typenum",
|
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "imbl-sized-chunks"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6957ea0b2541c5ca561d3ef4538044af79f8a05a1eb3a3b148936aaceaa1076"
|
||||||
|
dependencies = [
|
||||||
|
"bitmaps",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "1.9.2"
|
version = "1.9.2"
|
||||||
|
@ -1635,16 +1640,6 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sized-chunks"
|
|
||||||
version = "0.6.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e"
|
|
||||||
dependencies = [
|
|
||||||
"bitmaps",
|
|
||||||
"typenum",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slab"
|
name = "slab"
|
||||||
version = "0.4.7"
|
version = "0.4.7"
|
||||||
|
@ -2083,7 +2078,7 @@ dependencies = [
|
||||||
"codemap-diagnostic",
|
"codemap-diagnostic",
|
||||||
"criterion",
|
"criterion",
|
||||||
"dirs",
|
"dirs",
|
||||||
"im",
|
"imbl",
|
||||||
"itertools",
|
"itertools",
|
||||||
"path-clean",
|
"path-clean",
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
|
|
|
@ -656,18 +656,12 @@ rec {
|
||||||
};
|
};
|
||||||
"bitmaps" = rec {
|
"bitmaps" = rec {
|
||||||
crateName = "bitmaps";
|
crateName = "bitmaps";
|
||||||
version = "2.1.0";
|
version = "3.2.0";
|
||||||
edition = "2018";
|
edition = "2021";
|
||||||
sha256 = "18k4mcwxl96yvii5kcljkpb8pg5j4jj1zbsdn26nsx4r83846403";
|
sha256 = "00ql08pm4l9hizkldyy54v0pk96g7zg8x6i72c2vkcq0iawl4dkh";
|
||||||
authors = [
|
authors = [
|
||||||
"Bodil Stokke <bodil@bodil.org>"
|
"Bodil Stokke <bodil@bodil.org>"
|
||||||
];
|
];
|
||||||
dependencies = [
|
|
||||||
{
|
|
||||||
name = "typenum";
|
|
||||||
packageId = "typenum";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
features = {
|
features = {
|
||||||
"default" = [ "std" ];
|
"default" = [ "std" ];
|
||||||
};
|
};
|
||||||
|
@ -2423,19 +2417,24 @@ rec {
|
||||||
];
|
];
|
||||||
|
|
||||||
};
|
};
|
||||||
"im" = rec {
|
"imbl" = rec {
|
||||||
crateName = "im";
|
crateName = "imbl";
|
||||||
version = "15.1.0";
|
version = "2.0.0";
|
||||||
edition = "2018";
|
edition = "2018";
|
||||||
sha256 = "1sg0jy9y0l3lqjpjyclj6kspi027mx177dgrmacgjni8y0zx7b6h";
|
sha256 = "03fvbk1g1pqs6j77g76vq5klqi6bx9jl9di782268ilzrmlnp062";
|
||||||
authors = [
|
authors = [
|
||||||
"Bodil Stokke <bodil@bodil.org>"
|
"Bodil Stokke <bodil@bodil.org>"
|
||||||
|
"Joe Neeman <joeneeman@gmail.com>"
|
||||||
];
|
];
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{
|
{
|
||||||
name = "bitmaps";
|
name = "bitmaps";
|
||||||
packageId = "bitmaps";
|
packageId = "bitmaps";
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
name = "imbl-sized-chunks";
|
||||||
|
packageId = "imbl-sized-chunks";
|
||||||
|
}
|
||||||
{
|
{
|
||||||
name = "rand_core";
|
name = "rand_core";
|
||||||
packageId = "rand_core 0.6.4";
|
packageId = "rand_core 0.6.4";
|
||||||
|
@ -2444,14 +2443,6 @@ rec {
|
||||||
name = "rand_xoshiro";
|
name = "rand_xoshiro";
|
||||||
packageId = "rand_xoshiro";
|
packageId = "rand_xoshiro";
|
||||||
}
|
}
|
||||||
{
|
|
||||||
name = "sized-chunks";
|
|
||||||
packageId = "sized-chunks";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
name = "typenum";
|
|
||||||
packageId = "typenum";
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
buildDependencies = [
|
buildDependencies = [
|
||||||
{
|
{
|
||||||
|
@ -2468,6 +2459,31 @@ rec {
|
||||||
"serde" = [ "dep:serde" ];
|
"serde" = [ "dep:serde" ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
"imbl-sized-chunks" = rec {
|
||||||
|
crateName = "imbl-sized-chunks";
|
||||||
|
version = "0.1.1";
|
||||||
|
edition = "2021";
|
||||||
|
sha256 = "0xhhmb7aldl92hxkmsx10n59zxsa0hw4bvykc6jmq72lnah7x5g6";
|
||||||
|
authors = [
|
||||||
|
"Bodil Stokke <bodil@bodil.org>"
|
||||||
|
"Joe Neeman <joeneeman@gmail.com>"
|
||||||
|
];
|
||||||
|
dependencies = [
|
||||||
|
{
|
||||||
|
name = "bitmaps";
|
||||||
|
packageId = "bitmaps";
|
||||||
|
usesDefaultFeatures = false;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
features = {
|
||||||
|
"arbitrary" = [ "dep:arbitrary" ];
|
||||||
|
"array-ops" = [ "dep:array-ops" ];
|
||||||
|
"default" = [ "std" ];
|
||||||
|
"refpool" = [ "dep:refpool" ];
|
||||||
|
"ringbuffer" = [ "array-ops" ];
|
||||||
|
};
|
||||||
|
resolvedDefaultFeatures = [ "default" "std" ];
|
||||||
|
};
|
||||||
"indexmap" = rec {
|
"indexmap" = rec {
|
||||||
crateName = "indexmap";
|
crateName = "indexmap";
|
||||||
version = "1.9.2";
|
version = "1.9.2";
|
||||||
|
@ -4712,33 +4728,6 @@ rec {
|
||||||
};
|
};
|
||||||
resolvedDefaultFeatures = [ "default" "std" ];
|
resolvedDefaultFeatures = [ "default" "std" ];
|
||||||
};
|
};
|
||||||
"sized-chunks" = rec {
|
|
||||||
crateName = "sized-chunks";
|
|
||||||
version = "0.6.5";
|
|
||||||
edition = "2018";
|
|
||||||
sha256 = "07ix5fsdnpf2xsb0k5rbiwlmsicm2237fcx7blirp9p7pljr5mhn";
|
|
||||||
authors = [
|
|
||||||
"Bodil Stokke <bodil@bodil.org>"
|
|
||||||
];
|
|
||||||
dependencies = [
|
|
||||||
{
|
|
||||||
name = "bitmaps";
|
|
||||||
packageId = "bitmaps";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
name = "typenum";
|
|
||||||
packageId = "typenum";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
features = {
|
|
||||||
"arbitrary" = [ "dep:arbitrary" ];
|
|
||||||
"array-ops" = [ "dep:array-ops" ];
|
|
||||||
"default" = [ "std" ];
|
|
||||||
"refpool" = [ "dep:refpool" ];
|
|
||||||
"ringbuffer" = [ "array-ops" ];
|
|
||||||
};
|
|
||||||
resolvedDefaultFeatures = [ "default" "std" ];
|
|
||||||
};
|
|
||||||
"slab" = rec {
|
"slab" = rec {
|
||||||
crateName = "slab";
|
crateName = "slab";
|
||||||
version = "0.4.7";
|
version = "0.4.7";
|
||||||
|
@ -6185,8 +6174,8 @@ rec {
|
||||||
packageId = "dirs";
|
packageId = "dirs";
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
name = "im";
|
name = "imbl";
|
||||||
packageId = "im";
|
packageId = "imbl";
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
name = "path-clean";
|
name = "path-clean";
|
||||||
|
|
|
@ -14,7 +14,7 @@ builtin-macros = { path = "./builtin-macros", package = "tvix-eval-builtin-macro
|
||||||
codemap = "0.1.3"
|
codemap = "0.1.3"
|
||||||
codemap-diagnostic = "0.1.1"
|
codemap-diagnostic = "0.1.1"
|
||||||
dirs = "4.0.0"
|
dirs = "4.0.0"
|
||||||
im = "15.1"
|
imbl = "2.0"
|
||||||
path-clean = "0.1"
|
path-clean = "0.1"
|
||||||
proptest = { version = "1.0.0", default_features = false, features = ["std", "alloc", "break-dead-code", "tempfile"], optional = true }
|
proptest = { version = "1.0.0", default_features = false, features = ["std", "alloc", "break-dead-code", "tempfile"], optional = true }
|
||||||
regex = "1.6.0"
|
regex = "1.6.0"
|
||||||
|
|
|
@ -187,14 +187,14 @@ mod pure_builtins {
|
||||||
.collect::<Result<Vec<NixList>, ErrorKind>>()?;
|
.collect::<Result<Vec<NixList>, ErrorKind>>()?;
|
||||||
|
|
||||||
Ok(Value::List(NixList::from(
|
Ok(Value::List(NixList::from(
|
||||||
lists.into_iter().flatten().collect::<im::Vector<Value>>(),
|
lists.into_iter().flatten().collect::<imbl::Vector<Value>>(),
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[builtin("concatMap")]
|
#[builtin("concatMap")]
|
||||||
fn builtin_concat_map(vm: &mut VM, f: Value, list: Value) -> Result<Value, ErrorKind> {
|
fn builtin_concat_map(vm: &mut VM, f: Value, list: Value) -> Result<Value, ErrorKind> {
|
||||||
let list = list.to_list()?;
|
let list = list.to_list()?;
|
||||||
let mut res = im::Vector::new();
|
let mut res = imbl::Vector::new();
|
||||||
for val in list {
|
for val in list {
|
||||||
res.extend(vm.call_with(&f, [val])?.force(vm)?.to_list()?);
|
res.extend(vm.call_with(&f, [val])?.force(vm)?.to_list()?);
|
||||||
}
|
}
|
||||||
|
@ -295,7 +295,7 @@ mod pure_builtins {
|
||||||
|
|
||||||
result
|
result
|
||||||
})
|
})
|
||||||
.collect::<Result<im::Vector<Value>, _>>()
|
.collect::<Result<imbl::Vector<Value>, _>>()
|
||||||
.map(|list| Value::List(NixList::from(list)))
|
.map(|list| Value::List(NixList::from(list)))
|
||||||
.map_err(Into::into)
|
.map_err(Into::into)
|
||||||
}
|
}
|
||||||
|
@ -356,7 +356,7 @@ mod pure_builtins {
|
||||||
|
|
||||||
let operator = attrs.select_required("operator")?;
|
let operator = attrs.select_required("operator")?;
|
||||||
|
|
||||||
let mut res = im::Vector::new();
|
let mut res = imbl::Vector::new();
|
||||||
let mut done_keys: Vec<Value> = vec![];
|
let mut done_keys: Vec<Value> = vec![];
|
||||||
|
|
||||||
let mut insert_key = |k: Value, vm: &mut VM| -> Result<bool, ErrorKind> {
|
let mut insert_key = |k: Value, vm: &mut VM| -> Result<bool, ErrorKind> {
|
||||||
|
@ -391,7 +391,7 @@ mod pure_builtins {
|
||||||
let len = length.as_int()?;
|
let len = length.as_int()?;
|
||||||
(0..len)
|
(0..len)
|
||||||
.map(|i| vm.call_with(&generator, [i.into()]))
|
.map(|i| vm.call_with(&generator, [i.into()]))
|
||||||
.collect::<Result<im::Vector<Value>, _>>()
|
.collect::<Result<imbl::Vector<Value>, _>>()
|
||||||
.map(|list| Value::List(NixList::from(list)))
|
.map(|list| Value::List(NixList::from(list)))
|
||||||
.map_err(Into::into)
|
.map_err(Into::into)
|
||||||
}
|
}
|
||||||
|
@ -411,11 +411,11 @@ mod pure_builtins {
|
||||||
|
|
||||||
#[builtin("groupBy")]
|
#[builtin("groupBy")]
|
||||||
fn builtin_group_by(vm: &mut VM, f: Value, list: Value) -> Result<Value, ErrorKind> {
|
fn builtin_group_by(vm: &mut VM, f: Value, list: Value) -> Result<Value, ErrorKind> {
|
||||||
let mut res: BTreeMap<NixString, im::Vector<Value>> = BTreeMap::new();
|
let mut res: BTreeMap<NixString, imbl::Vector<Value>> = BTreeMap::new();
|
||||||
for val in list.to_list()? {
|
for val in list.to_list()? {
|
||||||
let key = vm.call_with(&f, [val.clone()])?.force(vm)?.to_str()?;
|
let key = vm.call_with(&f, [val.clone()])?.force(vm)?.to_str()?;
|
||||||
res.entry(key)
|
res.entry(key)
|
||||||
.or_insert_with(im::Vector::new)
|
.or_insert_with(imbl::Vector::new)
|
||||||
.push_back(val);
|
.push_back(val);
|
||||||
}
|
}
|
||||||
Ok(Value::attrs(NixAttrs::from_iter(
|
Ok(Value::attrs(NixAttrs::from_iter(
|
||||||
|
@ -550,7 +550,7 @@ mod pure_builtins {
|
||||||
|
|
||||||
list.into_iter()
|
list.into_iter()
|
||||||
.map(|val| vm.call_with(&f, [val]))
|
.map(|val| vm.call_with(&f, [val]))
|
||||||
.collect::<Result<im::Vector<Value>, _>>()
|
.collect::<Result<imbl::Vector<Value>, _>>()
|
||||||
.map(|list| Value::List(NixList::from(list)))
|
.map(|list| Value::List(NixList::from(list)))
|
||||||
.map_err(Into::into)
|
.map_err(Into::into)
|
||||||
}
|
}
|
||||||
|
@ -744,7 +744,7 @@ mod pure_builtins {
|
||||||
let re: Regex = Regex::new(re.as_str()).unwrap();
|
let re: Regex = Regex::new(re.as_str()).unwrap();
|
||||||
let mut capture_locations = re.capture_locations();
|
let mut capture_locations = re.capture_locations();
|
||||||
let num_captures = capture_locations.len();
|
let num_captures = capture_locations.len();
|
||||||
let mut ret = im::Vector::new();
|
let mut ret = imbl::Vector::new();
|
||||||
let mut pos = 0;
|
let mut pos = 0;
|
||||||
|
|
||||||
while let Some(thematch) = re.captures_read_at(&mut capture_locations, text, pos) {
|
while let Some(thematch) = re.captures_read_at(&mut capture_locations, text, pos) {
|
||||||
|
@ -755,7 +755,7 @@ mod pure_builtins {
|
||||||
// group in the regex, containing the characters
|
// group in the regex, containing the characters
|
||||||
// matched by that capture group, or null if no match.
|
// matched by that capture group, or null if no match.
|
||||||
// We skip capture 0; it represents the whole match.
|
// We skip capture 0; it represents the whole match.
|
||||||
let v: im::Vector<Value> = (1..num_captures)
|
let v: imbl::Vector<Value> = (1..num_captures)
|
||||||
.map(|i| capture_locations.get(i))
|
.map(|i| capture_locations.get(i))
|
||||||
.map(|o| {
|
.map(|o| {
|
||||||
o.map(|(start, end)| Value::from(&text[start..end]))
|
o.map(|(start, end)| Value::from(&text[start..end]))
|
||||||
|
@ -775,7 +775,7 @@ mod pure_builtins {
|
||||||
#[builtin("sort")]
|
#[builtin("sort")]
|
||||||
fn builtin_sort(vm: &mut VM, comparator: Value, list: Value) -> Result<Value, ErrorKind> {
|
fn builtin_sort(vm: &mut VM, comparator: Value, list: Value) -> Result<Value, ErrorKind> {
|
||||||
// TODO: the bound on the sort function in
|
// TODO: the bound on the sort function in
|
||||||
// `im::Vector::sort_by` is `Fn(...)`, which means that we can
|
// `imbl::Vector::sort_by` is `Fn(...)`, which means that we can
|
||||||
// not use the mutable VM inside of its closure, hence the
|
// not use the mutable VM inside of its closure, hence the
|
||||||
// dance via `Vec`. I think this is just an unnecessarily
|
// dance via `Vec`. I think this is just an unnecessarily
|
||||||
// restrictive bound in `im`, not a functional requirement.
|
// restrictive bound in `im`, not a functional requirement.
|
||||||
|
@ -810,7 +810,7 @@ mod pure_builtins {
|
||||||
});
|
});
|
||||||
|
|
||||||
match error {
|
match error {
|
||||||
#[allow(deprecated)] // im::Vector usage prevented by its API
|
#[allow(deprecated)] // imbl::Vector usage prevented by its API
|
||||||
None => Ok(Value::List(NixList::from_vec(list))),
|
None => Ok(Value::List(NixList::from_vec(list))),
|
||||||
Some(e) => Err(e),
|
Some(e) => Err(e),
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,10 @@
|
||||||
//!
|
//!
|
||||||
//! Due to this, construction and management of attribute sets has
|
//! Due to this, construction and management of attribute sets has
|
||||||
//! some peculiarities that are encapsulated within this module.
|
//! some peculiarities that are encapsulated within this module.
|
||||||
use std::collections::btree_map;
|
|
||||||
use std::collections::BTreeMap;
|
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
|
|
||||||
|
use imbl::{ordmap, OrdMap};
|
||||||
|
|
||||||
use crate::errors::ErrorKind;
|
use crate::errors::ErrorKind;
|
||||||
use crate::vm::VM;
|
use crate::vm::VM;
|
||||||
|
|
||||||
|
@ -23,7 +23,8 @@ mod tests;
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
enum AttrsRep {
|
enum AttrsRep {
|
||||||
Empty,
|
Empty,
|
||||||
Map(BTreeMap<NixString, Value>),
|
|
||||||
|
Im(OrdMap<NixString, Value>),
|
||||||
|
|
||||||
/// Warning: this represents a **two**-attribute attrset, with
|
/// Warning: this represents a **two**-attribute attrset, with
|
||||||
/// attribute names "name" and "value", like `{name="foo";
|
/// attribute names "name" and "value", like `{name="foo";
|
||||||
|
@ -43,20 +44,21 @@ impl Default for AttrsRep {
|
||||||
impl AttrsRep {
|
impl AttrsRep {
|
||||||
/// Retrieve reference to a mutable map inside of an attrs,
|
/// Retrieve reference to a mutable map inside of an attrs,
|
||||||
/// optionally changing the representation if required.
|
/// optionally changing the representation if required.
|
||||||
fn map_mut(&mut self) -> &mut BTreeMap<NixString, Value> {
|
fn map_mut(&mut self) -> &mut OrdMap<NixString, Value> {
|
||||||
match self {
|
match self {
|
||||||
AttrsRep::Map(m) => m,
|
AttrsRep::Im(m) => m,
|
||||||
|
|
||||||
AttrsRep::Empty => {
|
AttrsRep::Empty => {
|
||||||
*self = AttrsRep::Map(BTreeMap::new());
|
*self = AttrsRep::Im(OrdMap::new());
|
||||||
self.map_mut()
|
self.map_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
AttrsRep::KV { name, value } => {
|
AttrsRep::KV { name, value } => {
|
||||||
*self = AttrsRep::Map(BTreeMap::from([
|
*self = AttrsRep::Im(ordmap! {
|
||||||
(NixString::NAME, name.clone()),
|
NixString::NAME => name.clone(),
|
||||||
(NixString::VALUE, value.clone()),
|
NixString::VALUE => value.clone()
|
||||||
]));
|
});
|
||||||
|
|
||||||
self.map_mut()
|
self.map_mut()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,7 +74,7 @@ impl AttrsRep {
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
|
|
||||||
AttrsRep::Map(map) => map.get(&key.into()),
|
AttrsRep::Im(map) => map.get(&key.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +82,7 @@ impl AttrsRep {
|
||||||
match self {
|
match self {
|
||||||
AttrsRep::Empty => false,
|
AttrsRep::Empty => false,
|
||||||
AttrsRep::KV { .. } => key == "name" || key == "value",
|
AttrsRep::KV { .. } => key == "name" || key == "value",
|
||||||
AttrsRep::Map(map) => map.contains_key(&key.into()),
|
AttrsRep::Im(map) => map.contains_key(&key.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,7 +100,7 @@ where
|
||||||
where
|
where
|
||||||
T: IntoIterator<Item = (K, V)>,
|
T: IntoIterator<Item = (K, V)>,
|
||||||
{
|
{
|
||||||
NixAttrs(AttrsRep::Map(
|
NixAttrs(AttrsRep::Im(
|
||||||
iter.into_iter()
|
iter.into_iter()
|
||||||
.map(|(k, v)| (k.into(), v.into()))
|
.map(|(k, v)| (k.into(), v.into()))
|
||||||
.collect(),
|
.collect(),
|
||||||
|
@ -121,7 +123,7 @@ impl TotalDisplay for NixAttrs {
|
||||||
f.write_str("; ")?;
|
f.write_str("; ")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
AttrsRep::Map(map) => {
|
AttrsRep::Im(map) => {
|
||||||
for (name, value) in map {
|
for (name, value) in map {
|
||||||
write!(f, "{} = ", name.ident_str())?;
|
write!(f, "{} = ", name.ident_str())?;
|
||||||
value.total_fmt(f, set)?;
|
value.total_fmt(f, set)?;
|
||||||
|
@ -139,6 +141,7 @@ impl TotalDisplay for NixAttrs {
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "arbitrary")]
|
||||||
mod arbitrary {
|
mod arbitrary {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use proptest::prelude::*;
|
use proptest::prelude::*;
|
||||||
use proptest::prop_oneof;
|
use proptest::prop_oneof;
|
||||||
|
@ -158,7 +161,7 @@ mod arbitrary {
|
||||||
)
|
)
|
||||||
.prop_map(|(name, value)| Self(AttrsRep::KV { name, value })),
|
.prop_map(|(name, value)| Self(AttrsRep::KV { name, value })),
|
||||||
any_with::<BTreeMap<NixString, Value>>(args)
|
any_with::<BTreeMap<NixString, Value>>(args)
|
||||||
.prop_map(|map| Self(AttrsRep::Map(map)))
|
.prop_map(|map| Self::from_iter(map.into_iter()))
|
||||||
]
|
]
|
||||||
.boxed()
|
.boxed()
|
||||||
}
|
}
|
||||||
|
@ -183,44 +186,41 @@ impl NixAttrs {
|
||||||
// Explicitly handle all branches instead of falling
|
// Explicitly handle all branches instead of falling
|
||||||
// through, to ensure that we get at least some compiler
|
// through, to ensure that we get at least some compiler
|
||||||
// errors if variants are modified.
|
// errors if variants are modified.
|
||||||
(AttrsRep::Map(_), AttrsRep::Map(_))
|
(AttrsRep::Im(_), AttrsRep::Im(_))
|
||||||
| (AttrsRep::Map(_), AttrsRep::KV { .. })
|
| (AttrsRep::Im(_), AttrsRep::KV { .. })
|
||||||
| (AttrsRep::KV { .. }, AttrsRep::Map(_)) => {}
|
| (AttrsRep::KV { .. }, AttrsRep::Im(_)) => {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Slightly more advanced, but still optimised updates
|
// Slightly more advanced, but still optimised updates
|
||||||
match (self.0, other.0) {
|
match (self.0, other.0) {
|
||||||
(AttrsRep::Map(mut m), AttrsRep::KV { name, value }) => {
|
(AttrsRep::Im(mut m), AttrsRep::KV { name, value }) => {
|
||||||
m.insert(NixString::NAME, name);
|
m.insert(NixString::NAME, name);
|
||||||
m.insert(NixString::VALUE, value);
|
m.insert(NixString::VALUE, value);
|
||||||
NixAttrs(AttrsRep::Map(m))
|
NixAttrs(AttrsRep::Im(m))
|
||||||
}
|
}
|
||||||
|
|
||||||
(AttrsRep::KV { name, value }, AttrsRep::Map(mut m)) => {
|
(AttrsRep::KV { name, value }, AttrsRep::Im(mut m)) => {
|
||||||
match m.entry(NixString::NAME) {
|
match m.entry(NixString::NAME) {
|
||||||
btree_map::Entry::Vacant(e) => {
|
imbl::ordmap::Entry::Vacant(e) => {
|
||||||
e.insert(name);
|
e.insert(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
btree_map::Entry::Occupied(_) => { /* name from `m` has precedence */ }
|
imbl::ordmap::Entry::Occupied(_) => { /* name from `m` has precedence */ }
|
||||||
};
|
};
|
||||||
|
|
||||||
match m.entry(NixString::VALUE) {
|
match m.entry(NixString::VALUE) {
|
||||||
btree_map::Entry::Vacant(e) => {
|
imbl::ordmap::Entry::Vacant(e) => {
|
||||||
e.insert(value);
|
e.insert(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
btree_map::Entry::Occupied(_) => { /* value from `m` has precedence */ }
|
imbl::ordmap::Entry::Occupied(_) => { /* value from `m` has precedence */ }
|
||||||
};
|
};
|
||||||
|
|
||||||
NixAttrs(AttrsRep::Map(m))
|
NixAttrs(AttrsRep::Im(m))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Plain merge of maps.
|
// Plain merge of maps.
|
||||||
(AttrsRep::Map(mut m1), AttrsRep::Map(mut m2)) => {
|
(AttrsRep::Im(m1), AttrsRep::Im(m2)) => NixAttrs(AttrsRep::Im(m2.union(m1))),
|
||||||
m1.append(&mut m2);
|
|
||||||
NixAttrs(AttrsRep::Map(m1))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cases handled above by the borrowing match:
|
// Cases handled above by the borrowing match:
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
|
@ -230,7 +230,7 @@ impl NixAttrs {
|
||||||
/// Return the number of key-value entries in an attrset.
|
/// Return the number of key-value entries in an attrset.
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
match &self.0 {
|
match &self.0 {
|
||||||
AttrsRep::Map(map) => map.len(),
|
AttrsRep::Im(map) => map.len(),
|
||||||
AttrsRep::Empty => 0,
|
AttrsRep::Empty => 0,
|
||||||
AttrsRep::KV { .. } => 2,
|
AttrsRep::KV { .. } => 2,
|
||||||
}
|
}
|
||||||
|
@ -256,7 +256,7 @@ impl NixAttrs {
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[allow(clippy::needless_lifetimes)]
|
||||||
pub fn iter<'a>(&'a self) -> Iter<KeyValue<'a>> {
|
pub fn iter<'a>(&'a self) -> Iter<KeyValue<'a>> {
|
||||||
Iter(match &self.0 {
|
Iter(match &self.0 {
|
||||||
AttrsRep::Map(map) => KeyValue::Map(map.iter()),
|
AttrsRep::Im(map) => KeyValue::Im(map.iter()),
|
||||||
AttrsRep::Empty => KeyValue::Empty,
|
AttrsRep::Empty => KeyValue::Empty,
|
||||||
|
|
||||||
AttrsRep::KV {
|
AttrsRep::KV {
|
||||||
|
@ -280,7 +280,7 @@ impl NixAttrs {
|
||||||
]
|
]
|
||||||
.into_iter(),
|
.into_iter(),
|
||||||
)),
|
)),
|
||||||
AttrsRep::Map(map) => IntoIter(IntoIterRepr::Map(map.into_iter())),
|
AttrsRep::Im(map) => IntoIter(IntoIterRepr::Im(map.into_iter())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,7 +294,7 @@ impl NixAttrs {
|
||||||
pub fn keys(&self) -> Keys {
|
pub fn keys(&self) -> Keys {
|
||||||
Keys(match &self.0 {
|
Keys(match &self.0 {
|
||||||
AttrsRep::Empty => KeysInner::Empty,
|
AttrsRep::Empty => KeysInner::Empty,
|
||||||
AttrsRep::Map(m) => KeysInner::Map(m.keys()),
|
AttrsRep::Im(m) => KeysInner::Im(m.keys()),
|
||||||
AttrsRep::KV { .. } => KeysInner::KV(IterKV::default()),
|
AttrsRep::KV { .. } => KeysInner::KV(IterKV::default()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -321,7 +321,7 @@ impl NixAttrs {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut attrs = NixAttrs(AttrsRep::Map(BTreeMap::new()));
|
let mut attrs = NixAttrs(AttrsRep::Im(OrdMap::new()));
|
||||||
|
|
||||||
for _ in 0..count {
|
for _ in 0..count {
|
||||||
let value = stack_slice.pop().unwrap();
|
let value = stack_slice.pop().unwrap();
|
||||||
|
@ -363,7 +363,7 @@ impl NixAttrs {
|
||||||
// elements after key construction). In practice this
|
// elements after key construction). In practice this
|
||||||
// probably does not happen, so it's better to just bite
|
// probably does not happen, so it's better to just bite
|
||||||
// the bullet and implement this branch.
|
// the bullet and implement this branch.
|
||||||
(AttrsRep::Empty, AttrsRep::Map(map)) | (AttrsRep::Map(map), AttrsRep::Empty) => {
|
(AttrsRep::Empty, AttrsRep::Im(map)) | (AttrsRep::Im(map), AttrsRep::Empty) => {
|
||||||
Ok(map.is_empty())
|
Ok(map.is_empty())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -382,8 +382,8 @@ impl NixAttrs {
|
||||||
},
|
},
|
||||||
) => Ok(n1.nix_eq(n2, vm)? && v1.nix_eq(v2, vm)?),
|
) => Ok(n1.nix_eq(n2, vm)? && v1.nix_eq(v2, vm)?),
|
||||||
|
|
||||||
(AttrsRep::Map(map), AttrsRep::KV { name, value })
|
(AttrsRep::Im(map), AttrsRep::KV { name, value })
|
||||||
| (AttrsRep::KV { name, value }, AttrsRep::Map(map)) => {
|
| (AttrsRep::KV { name, value }, AttrsRep::Im(map)) => {
|
||||||
if map.len() != 2 {
|
if map.len() != 2 {
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
@ -397,7 +397,7 @@ impl NixAttrs {
|
||||||
Ok(false)
|
Ok(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
(AttrsRep::Map(m1), AttrsRep::Map(m2)) => {
|
(AttrsRep::Im(m1), AttrsRep::Im(m2)) => {
|
||||||
if m1.len() != m2.len() {
|
if m1.len() != m2.len() {
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
@ -462,11 +462,11 @@ fn attempt_optimise_kv(slice: &mut [Value]) -> Option<NixAttrs> {
|
||||||
/// checking against duplicate keys.
|
/// checking against duplicate keys.
|
||||||
fn set_attr(attrs: &mut NixAttrs, key: NixString, value: Value) -> Result<(), ErrorKind> {
|
fn set_attr(attrs: &mut NixAttrs, key: NixString, value: Value) -> Result<(), ErrorKind> {
|
||||||
match attrs.0.map_mut().entry(key) {
|
match attrs.0.map_mut().entry(key) {
|
||||||
btree_map::Entry::Occupied(entry) => Err(ErrorKind::DuplicateAttrsKey {
|
imbl::ordmap::Entry::Occupied(entry) => Err(ErrorKind::DuplicateAttrsKey {
|
||||||
key: entry.key().as_str().to_string(),
|
key: entry.key().as_str().to_string(),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
btree_map::Entry::Vacant(entry) => {
|
imbl::ordmap::Entry::Vacant(entry) => {
|
||||||
entry.insert(value);
|
entry.insert(value);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -495,7 +495,6 @@ impl IterKV {
|
||||||
|
|
||||||
/// Iterator representation over the keys *and* values of an attribute
|
/// Iterator representation over the keys *and* values of an attribute
|
||||||
/// set.
|
/// set.
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum KeyValue<'a> {
|
pub enum KeyValue<'a> {
|
||||||
Empty,
|
Empty,
|
||||||
|
|
||||||
|
@ -505,7 +504,7 @@ pub enum KeyValue<'a> {
|
||||||
at: IterKV,
|
at: IterKV,
|
||||||
},
|
},
|
||||||
|
|
||||||
Map(btree_map::Iter<'a, NixString, Value>),
|
Im(imbl::ordmap::Iter<'a, NixString, Value>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterator over a Nix attribute set.
|
/// Iterator over a Nix attribute set.
|
||||||
|
@ -519,7 +518,7 @@ impl<'a> Iterator for Iter<KeyValue<'a>> {
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
match &mut self.0 {
|
match &mut self.0 {
|
||||||
KeyValue::Map(inner) => inner.next(),
|
KeyValue::Im(inner) => inner.next(),
|
||||||
KeyValue::Empty => None,
|
KeyValue::Empty => None,
|
||||||
|
|
||||||
KeyValue::KV { name, value, at } => match at {
|
KeyValue::KV { name, value, at } => match at {
|
||||||
|
@ -544,7 +543,7 @@ impl<'a> ExactSizeIterator for Iter<KeyValue<'a>> {
|
||||||
match &self.0 {
|
match &self.0 {
|
||||||
KeyValue::Empty => 0,
|
KeyValue::Empty => 0,
|
||||||
KeyValue::KV { .. } => 2,
|
KeyValue::KV { .. } => 2,
|
||||||
KeyValue::Map(inner) => inner.len(),
|
KeyValue::Im(inner) => inner.len(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -552,7 +551,7 @@ impl<'a> ExactSizeIterator for Iter<KeyValue<'a>> {
|
||||||
enum KeysInner<'a> {
|
enum KeysInner<'a> {
|
||||||
Empty,
|
Empty,
|
||||||
KV(IterKV),
|
KV(IterKV),
|
||||||
Map(btree_map::Keys<'a, NixString, Value>),
|
Im(imbl::ordmap::Keys<'a, NixString, Value>),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Keys<'a>(KeysInner<'a>);
|
pub struct Keys<'a>(KeysInner<'a>);
|
||||||
|
@ -572,7 +571,7 @@ impl<'a> Iterator for Keys<'a> {
|
||||||
Some(NixString::VALUE_REF)
|
Some(NixString::VALUE_REF)
|
||||||
}
|
}
|
||||||
KeysInner::KV(IterKV::Done) => None,
|
KeysInner::KV(IterKV::Done) => None,
|
||||||
KeysInner::Map(m) => m.next(),
|
KeysInner::Im(m) => m.next(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -592,7 +591,7 @@ impl<'a> ExactSizeIterator for Keys<'a> {
|
||||||
match &self.0 {
|
match &self.0 {
|
||||||
KeysInner::Empty => 0,
|
KeysInner::Empty => 0,
|
||||||
KeysInner::KV(_) => 2,
|
KeysInner::KV(_) => 2,
|
||||||
KeysInner::Map(m) => m.len(),
|
KeysInner::Im(m) => m.len(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -601,7 +600,7 @@ impl<'a> ExactSizeIterator for Keys<'a> {
|
||||||
pub enum IntoIterRepr {
|
pub enum IntoIterRepr {
|
||||||
Empty,
|
Empty,
|
||||||
Finite(std::vec::IntoIter<(NixString, Value)>),
|
Finite(std::vec::IntoIter<(NixString, Value)>),
|
||||||
Map(std::collections::btree_map::IntoIter<NixString, Value>),
|
Im(imbl::ordmap::ConsumingIter<(NixString, Value)>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
|
@ -613,8 +612,8 @@ impl Iterator for IntoIter {
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
match &mut self.0 {
|
match &mut self.0 {
|
||||||
IntoIterRepr::Empty => None,
|
IntoIterRepr::Empty => None,
|
||||||
IntoIterRepr::Map(inner) => inner.next(),
|
|
||||||
IntoIterRepr::Finite(inner) => inner.next(),
|
IntoIterRepr::Finite(inner) => inner.next(),
|
||||||
|
IntoIterRepr::Im(inner) => inner.next(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -623,8 +622,8 @@ impl ExactSizeIterator for IntoIter {
|
||||||
fn len(&self) -> usize {
|
fn len(&self) -> usize {
|
||||||
match &self.0 {
|
match &self.0 {
|
||||||
IntoIterRepr::Empty => 0,
|
IntoIterRepr::Empty => 0,
|
||||||
IntoIterRepr::Map(inner) => inner.len(),
|
|
||||||
IntoIterRepr::Finite(inner) => inner.len(),
|
IntoIterRepr::Finite(inner) => inner.len(),
|
||||||
|
IntoIterRepr::Im(inner) => inner.len(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ fn test_simple_attrs() {
|
||||||
.expect("simple attr construction should succeed");
|
.expect("simple attr construction should succeed");
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
matches!(attrs, NixAttrs(AttrsRep::Map(_))),
|
matches!(attrs, NixAttrs(AttrsRep::Im(_))),
|
||||||
"simple attribute set should use map representation",
|
"simple attribute set should use map representation",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//! This module implements Nix lists.
|
//! This module implements Nix lists.
|
||||||
use std::ops::Index;
|
use std::ops::Index;
|
||||||
|
|
||||||
use im::{vector, Vector};
|
use imbl::{vector, Vector};
|
||||||
|
|
||||||
use crate::errors::ErrorKind;
|
use crate::errors::ErrorKind;
|
||||||
use crate::vm::VM;
|
use crate::vm::VM;
|
||||||
|
@ -119,7 +119,7 @@ impl NixList {
|
||||||
|
|
||||||
impl IntoIterator for NixList {
|
impl IntoIterator for NixList {
|
||||||
type Item = Value;
|
type Item = Value;
|
||||||
type IntoIter = im::vector::ConsumingIter<Value>;
|
type IntoIter = imbl::vector::ConsumingIter<Value>;
|
||||||
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
self.0.into_iter()
|
self.0.into_iter()
|
||||||
|
@ -128,7 +128,7 @@ impl IntoIterator for NixList {
|
||||||
|
|
||||||
impl<'a> IntoIterator for &'a NixList {
|
impl<'a> IntoIterator for &'a NixList {
|
||||||
type Item = &'a Value;
|
type Item = &'a Value;
|
||||||
type IntoIter = im::vector::Iter<'a, Value>;
|
type IntoIter = imbl::vector::Iter<'a, Value>;
|
||||||
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
self.0.iter()
|
self.0.iter()
|
||||||
|
|
|
@ -601,7 +601,7 @@ fn type_error(expected: &'static str, actual: &Value) -> ErrorKind {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use im::vector;
|
use imbl::vector;
|
||||||
|
|
||||||
mod nix_eq {
|
mod nix_eq {
|
||||||
use crate::observer::NoOpObserver;
|
use crate::observer::NoOpObserver;
|
||||||
|
|
Loading…
Reference in a new issue