feat: rec attrset

This commit is contained in:
2025-08-08 12:12:23 +08:00
parent 67cdcfea33
commit a9cfddbf5c
13 changed files with 147 additions and 180 deletions

View File

@@ -5,6 +5,7 @@ use std::fmt::Debug;
use std::rc::Rc;
use derive_more::Constructor;
use hashbrown::hash_map::Entry;
use hashbrown::{HashMap, HashSet};
use itertools::Itertools;
@@ -13,14 +14,13 @@ use nixjit_value::Symbol;
use nixjit_value::{self as p, format_symbol};
use super::Value;
use crate::EvalContext;
/// A wrapper around a `HashMap` representing a Nix attribute set.
///
/// It uses `#[repr(transparent)]` to ensure it has the same memory layout
/// as `HashMap<String, Value>`.
#[repr(transparent)]
#[derive(Constructor, PartialEq)]
#[derive(Clone, Constructor, PartialEq)]
pub struct AttrSet {
data: HashMap<String, Value>,
}
@@ -40,14 +40,6 @@ impl Debug for AttrSet {
}
}
impl Clone for AttrSet {
fn clone(&self) -> Self {
AttrSet {
data: self.data.clone(),
}
}
}
impl From<HashMap<String, Value>> for AttrSet {
fn from(data: HashMap<String, Value>) -> Self {
Self { data }
@@ -80,11 +72,17 @@ impl AttrSet {
///
/// This method currently uses `todo!()` and will panic if the attribute
/// already exists, indicating that duplicate attribute handling is not yet implemented.
pub fn push_attr(&mut self, sym: String, val: Value) {
if self.data.get(&sym).is_some() {
todo!()
pub fn push_attr(&mut self, sym: String, val: Value) -> Result<()> {
match self.data.entry(sym) {
Entry::Occupied(occupied) => Err(Error::EvalError(format!(
"attribute '{}' already defined",
format_symbol(occupied.key())
))),
Entry::Vacant(vacant) => {
vacant.insert(val);
Ok(())
}
}
self.data.insert(sym, val);
}
/// Performs a deep selection of an attribute from a nested set.