pub struct NixAttrs(/* private fields */);Expand description
A Nix attribute set with lazy overlay support.
Internally uses either a concrete compact AttrsMap or a lazy overlay chain.
The // operator creates O(1) overlay nodes instead of O(m log n) merges.
Attribute access walks the chain right-to-left in O(depth).
Full iteration (attrNames, attrValues) flattens on demand.
The second tuple field is an OPTIONAL source-position table (None for
the vast majority of attrsets — merges, overlays, builtin-built, dynamic
keys). eval_attrset attaches it for a literal with static keys so
builtins.unsafeGetAttrPos can report a key’s file/line/column (the
attrTag declarations — options.json dock root). It is behind Rc, so
a clone is a refcount bump; None costs one pointer-sized word.
Implementations§
Source§impl NixAttrs
impl NixAttrs
pub fn new() -> Self
pub fn with_capacity(_capacity: usize) -> Self
Sourcepub fn set_positions(&mut self, pos: Rc<AttrPositions>)
pub fn set_positions(&mut self, pos: Rc<AttrPositions>)
Attach a source-position table (the static keys’ byte offsets of the
literal that built this attrset). Called by eval_attrset; consumed
by builtins.unsafeGetAttrPos. Never affects any observed value.
Sourcepub fn positions(&self) -> Option<&Rc<AttrPositions>>
pub fn positions(&self) -> Option<&Rc<AttrPositions>>
The source-position table, if this attrset carries one (a literal with
static keys). None for merges/overlays/builtin-built/dynamic-key
attrsets.
Sourcepub fn pos_for(&self, key: &str) -> Option<ResolvedPos>
pub fn pos_for(&self, key: &str) -> Option<ResolvedPos>
Resolve the source position of key in this attrset — the file/line/
column builtins.unsafeGetAttrPos returns. None when the attrset
has no position table, the key is absent from it, or the source has
no file (a <string>-eval’d literal).
Sourcepub fn get(&self, key: &str) -> Option<&Value>
pub fn get(&self, key: &str) -> Option<&Value>
Look up an attribute by name. Walks overlay chain right-to-left.
Sourcepub fn get_sym(&self, sym: &Symbol) -> Option<&Value>
pub fn get_sym(&self, sym: &Symbol) -> Option<&Value>
Look up by pre-interned Symbol.
Fast path: if the overlay’s flat cache has been populated (by any
prior full iteration — attrNames, attrValues, // merge that
needed key enumeration, etc.), read directly from it in O(1). This
matters in real Nix workloads where an attrset is first iterated
(module eval, with desugaring) and then hit many times by dotted
access — CppNix has no such structure and pays O(1) always; we want
to match that whenever the cache is warm.
Slow path: walk the overlay chain right-to-left in O(depth). Not populating the cache on cold lookups is deliberate — the cache costs O(n) to build and the chain is usually short (1–3 overlays).
Sourcepub fn insert(&mut self, key: String, value: Value)
pub fn insert(&mut self, key: String, value: Value)
Insert or overwrite an attribute. Flattens overlay if needed.
pub fn contains_key(&self, key: &str) -> bool
pub fn contains_key_sym(&self, sym: &Symbol) -> bool
pub fn keys(&self) -> impl Iterator<Item = String>
pub fn iter(&self) -> impl Iterator<Item = (String, &Value)>
pub fn iter_unsorted(&self) -> impl Iterator<Item = (String, &Value)>
Sourcepub fn iter_syms(&self) -> impl Iterator<Item = (Symbol, &Value)>
pub fn iter_syms(&self) -> impl Iterator<Item = (Symbol, &Value)>
Sym-keyed unsorted iteration — ZERO interner traffic, zero allocation.
This exists because live-sampling the cid marquee eval (2026-07-21,
release-profiling binary) showed the interner round-trip as the #1 CPU
sink — 27–39% of the eval thread, sustained: iter_unsorted above
materializes a fresh heap String per key via resolve AND collects
the whole map into a Vec on every call, and callers like
intersectAttrs then re-intern each of those Strings straight back to
the Symbol they started as (contains_key(&str) → intern), with a
third intern inside insert. Sym→String→hash+memcmp→Sym, three times
per key per call, at nixpkgs scale.
Symbol is Copy(u32) and as_flat() hands back a real borrow (the
Overlay case populates its cache), so this iterator borrows instead of
collecting. Byte-neutral by the same argument already sealed for the
unsorted-iteration change: the observable order of any result attrset
is re-derived at observation time via sorted_entries.
Sourcepub fn insert_sym(&mut self, sym: Symbol, value: Value)
pub fn insert_sym(&mut self, sym: Symbol, value: Value)
Sym-keyed insert — the zero-intern sibling of insert, for callers
that already hold the Symbol (every iter_syms consumer).
pub fn values(&self) -> impl Iterator<Item = &Value>
pub fn remove(&mut self, key: &str) -> Option<Value>
pub fn len(&self) -> usize
pub fn is_empty(&self) -> bool
Trait Implementations§
Source§impl IntoIterator for NixAttrs
impl IntoIterator for NixAttrs
Auto Trait Implementations§
impl !Freeze for NixAttrs
impl !RefUnwindSafe for NixAttrs
impl !Send for NixAttrs
impl !Sync for NixAttrs
impl !UnwindSafe for NixAttrs
impl Unpin for NixAttrs
impl UnsafeUnpin for NixAttrs
Blanket Implementations§
Source§impl<T> ArchivePointee for T
impl<T> ArchivePointee for T
Source§type ArchivedMetadata = ()
type ArchivedMetadata = ()
Source§fn pointer_metadata(
_: &<T as ArchivePointee>::ArchivedMetadata,
) -> <T as Pointee>::Metadata
fn pointer_metadata( _: &<T as ArchivePointee>::ArchivedMetadata, ) -> <T as Pointee>::Metadata
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> LayoutRaw for T
impl<T> LayoutRaw for T
Source§fn layout_raw(_: <T as Pointee>::Metadata) -> Result<Layout, LayoutError>
fn layout_raw(_: <T as Pointee>::Metadata) -> Result<Layout, LayoutError>
Source§impl<T, N1, N2> Niching<NichedOption<T, N1>> for N2
impl<T, N1, N2> Niching<NichedOption<T, N1>> for N2
Source§unsafe fn is_niched(niched: *const NichedOption<T, N1>) -> bool
unsafe fn is_niched(niched: *const NichedOption<T, N1>) -> bool
Source§fn resolve_niched(out: Place<NichedOption<T, N1>>)
fn resolve_niched(out: Place<NichedOption<T, N1>>)
out indicating that a T is niched.