1use std::borrow::Borrow;
3use std::collections::hash_map;
4use std::hash::Hash;
5use std::iter::FromIterator;
6use std::rc::Rc;
7
8use itertools::Itertools as _;
9use rustc_hash::FxHashMap;
10use serde::de::{Deserializer, Error, Visitor};
11use serde::Deserialize;
12
13use super::string::NixString;
14use super::thunk::ThunkSet;
15use super::TotalDisplay;
16use super::Value;
17use crate::errors::ErrorKind;
18use crate::CatchableErrorKind;
19
20#[cfg(test)]
21mod tests;
22
23type AttrsRep = FxHashMap<NixString, Value>;
24
25#[repr(transparent)]
26#[derive(Clone, Debug, Default)]
27pub struct NixAttrs(Rc<AttrsRep>);
28
29impl From<AttrsRep> for NixAttrs {
30 fn from(rep: AttrsRep) -> Self {
31 NixAttrs(Rc::new(rep))
32 }
33}
34
35impl<K, V> FromIterator<(K, V)> for NixAttrs
36where
37 NixString: From<K>,
38 Value: From<V>,
39{
40 fn from_iter<T>(iter: T) -> NixAttrs
41 where
42 T: IntoIterator<Item = (K, V)>,
43 {
44 iter.into_iter()
45 .map(|(k, v)| (k.into(), v.into()))
46 .collect::<AttrsRep>()
47 .into()
48 }
49}
50
51impl TotalDisplay for NixAttrs {
52 fn total_fmt(&self, f: &mut std::fmt::Formatter<'_>, set: &mut ThunkSet) -> std::fmt::Result {
53 if let Some(Value::String(s)) = self.select_str("type") {
54 if *s == "derivation" {
55 write!(f, "«derivation ")?;
56 if let Some(p) = self.select_str("drvPath") {
57 p.total_fmt(f, set)?;
58 } else {
59 write!(f, "???")?;
60 }
61 return write!(f, "»");
62 }
63 }
64
65 f.write_str("{ ")?;
66
67 for (name, value) in self.iter_sorted() {
68 write!(f, "{} = ", name.ident_str())?;
69 value.total_fmt(f, set)?;
70 f.write_str("; ")?;
71 }
72
73 f.write_str("}")
74 }
75}
76
77impl<'de> Deserialize<'de> for NixAttrs {
78 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
79 where
80 D: Deserializer<'de>,
81 {
82 struct MapVisitor;
83
84 impl<'de> Visitor<'de> for MapVisitor {
85 type Value = NixAttrs;
86
87 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
88 formatter.write_str("a valid Nix attribute set")
89 }
90
91 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
92 where
93 A: serde::de::MapAccess<'de>,
94 {
95 let mut stack_array = Vec::with_capacity(map.size_hint().unwrap_or(0) * 2);
96
97 while let Some((key, value)) = map.next_entry()? {
98 stack_array.push(key);
99 stack_array.push(value);
100 }
101
102 Ok(NixAttrs::construct(stack_array.len() / 2, stack_array)
103 .map_err(A::Error::custom)?
104 .expect("Catchable values are unreachable here"))
105 }
106 }
107
108 deserializer.deserialize_map(MapVisitor)
109 }
110}
111
112impl NixAttrs {
113 pub fn empty() -> Self {
114 AttrsRep::default().into()
115 }
116
117 pub fn ptr_eq(&self, other: &Self) -> bool {
120 Rc::ptr_eq(&self.0, &other.0)
121 }
122
123 pub fn update(self, other: Self) -> Self {
126 let mut out = Rc::unwrap_or_clone(self.0);
127 for (key, value) in other {
128 out.insert(key, value);
129 }
130
131 out.into()
132 }
133
134 pub fn len(&self) -> usize {
136 self.0.len()
137 }
138
139 pub fn is_empty(&self) -> bool {
140 self.0.is_empty()
141 }
142
143 pub fn select<Q>(&self, key: &Q) -> Option<&Value>
145 where
146 NixString: Borrow<Q>,
147 Q: Hash + Eq + ?Sized,
148 {
149 self.0.get(key)
150 }
151
152 pub fn select_str(&self, key: &str) -> Option<&Value> {
157 self.select(key.as_bytes())
158 }
159
160 pub fn select_required(&self, key: &str) -> Result<&Value, ErrorKind> {
163 self.0
164 .get(key.as_bytes())
165 .ok_or_else(|| ErrorKind::AttributeNotFound {
166 name: key.to_string(),
167 })
168 }
169
170 pub fn contains<Q>(&self, key: &Q) -> bool
171 where
172 NixString: Borrow<Q>,
173 Q: Hash + Eq + ?Sized,
174 {
175 self.0.contains_key(key)
176 }
177
178 #[allow(clippy::needless_lifetimes)]
180 pub fn iter<'a>(&'a self) -> Iter<KeyValue<'a>> {
181 Iter(KeyValue::Map(self.0.iter()))
182 }
183
184 pub fn iter_sorted(&self) -> Iter<KeyValue<'_>> {
187 let sorted = self.0.iter().sorted_by_key(|x| x.0);
188 Iter(KeyValue::Sorted(sorted))
189 }
190
191 pub fn into_iter_sorted(self) -> OwnedAttrsIterator {
194 OwnedAttrsIterator(IntoIterRepr::Finite(
195 self.0
196 .as_ref()
197 .iter()
198 .map(|(k, v)| (k.clone(), v.clone()))
199 .sorted_by(|(a, _), (b, _)| a.cmp(b)),
200 ))
201 }
202
203 pub fn keys(&self) -> Keys<'_> {
205 Keys(KeysInner::Map(self.0.keys()))
206 }
207
208 pub fn keys_sorted(&self) -> Keys<'_> {
211 Keys(KeysInner::Sorted(self.0.keys().sorted()))
212 }
213
214 pub fn construct(
217 count: usize,
218 mut stack_slice: Vec<Value>,
219 ) -> Result<Result<Self, CatchableErrorKind>, ErrorKind> {
220 debug_assert!(
221 stack_slice.len() == count * 2,
222 "construct_attrs called with count == {}, but slice.len() == {}",
223 count,
224 stack_slice.len(),
225 );
226
227 let mut attrs_map = FxHashMap::with_capacity_and_hasher(count, rustc_hash::FxBuildHasher);
228
229 for _ in 0..count {
230 let value = stack_slice.pop().unwrap();
231 let key = stack_slice.pop().unwrap();
232
233 match key {
234 Value::String(ks) => set_attr(&mut attrs_map, ks, value)?,
235
236 Value::Null => {
237 continue;
241 }
242
243 Value::Catchable(err) => return Ok(Err(*err)),
244
245 other => return Err(ErrorKind::InvalidAttributeName(other)),
246 }
247 }
248
249 Ok(Ok(attrs_map.into()))
250 }
251
252 pub(crate) fn intersect(&self, other: &Self) -> NixAttrs {
255 let lhs = &self.0;
256 let rhs = &other.0;
257
258 let mut out = FxHashMap::with_capacity_and_hasher(
259 std::cmp::min(lhs.len(), rhs.len()),
260 rustc_hash::FxBuildHasher,
261 );
262
263 if lhs.len() < rhs.len() {
264 for key in lhs.keys() {
265 if let Some(val) = rhs.get(key) {
266 out.insert(key.clone(), val.clone());
267 }
268 }
269 } else {
270 for (key, val) in rhs.iter() {
271 if lhs.contains_key(key) {
272 out.insert(key.clone(), val.clone());
273 }
274 }
275 };
276
277 out.into()
278 }
279}
280
281impl IntoIterator for NixAttrs {
282 type Item = (NixString, Value);
283 type IntoIter = OwnedAttrsIterator;
284
285 fn into_iter(self) -> Self::IntoIter {
286 OwnedAttrsIterator(IntoIterRepr::Map(Rc::unwrap_or_clone(self.0).into_iter()))
287 }
288}
289
290fn set_attr(map: &mut AttrsRep, key: NixString, value: Value) -> Result<(), ErrorKind> {
293 match map.entry(key) {
294 hash_map::Entry::Occupied(entry) => Err(ErrorKind::DuplicateAttrsKey {
295 key: entry.key().to_string(),
296 }),
297
298 hash_map::Entry::Vacant(entry) => {
299 entry.insert(value);
300 Ok(())
301 }
302 }
303}
304
305pub enum KeyValue<'a> {
308 Map(hash_map::Iter<'a, NixString, Value>),
309 Sorted(std::vec::IntoIter<(&'a NixString, &'a Value)>),
310}
311
312#[repr(transparent)]
316pub struct Iter<T>(T);
317
318impl<'a> Iterator for Iter<KeyValue<'a>> {
319 type Item = (&'a NixString, &'a Value);
320
321 fn next(&mut self) -> Option<Self::Item> {
322 match &mut self.0 {
323 KeyValue::Map(inner) => inner.next(),
324 KeyValue::Sorted(inner) => inner.next(),
325 }
326 }
327}
328
329impl ExactSizeIterator for Iter<KeyValue<'_>> {
330 fn len(&self) -> usize {
331 match &self.0 {
332 KeyValue::Map(inner) => inner.len(),
333 KeyValue::Sorted(inner) => inner.len(),
334 }
335 }
336}
337
338enum KeysInner<'a> {
339 Map(hash_map::Keys<'a, NixString, Value>),
340 Sorted(std::vec::IntoIter<&'a NixString>),
341}
342
343pub struct Keys<'a>(KeysInner<'a>);
344
345impl<'a> Iterator for Keys<'a> {
346 type Item = &'a NixString;
347
348 fn next(&mut self) -> Option<Self::Item> {
349 match &mut self.0 {
350 KeysInner::Map(m) => m.next(),
351 KeysInner::Sorted(v) => v.next(),
352 }
353 }
354}
355
356impl<'a> IntoIterator for &'a NixAttrs {
357 type Item = (&'a NixString, &'a Value);
358
359 type IntoIter = Iter<KeyValue<'a>>;
360
361 fn into_iter(self) -> Self::IntoIter {
362 self.iter()
363 }
364}
365
366impl ExactSizeIterator for Keys<'_> {
367 fn len(&self) -> usize {
368 match &self.0 {
369 KeysInner::Map(m) => m.len(),
370 KeysInner::Sorted(v) => v.len(),
371 }
372 }
373}
374
375pub enum IntoIterRepr {
377 Finite(std::vec::IntoIter<(NixString, Value)>),
378 Map(hash_map::IntoIter<NixString, Value>),
379}
380
381#[repr(transparent)]
384pub struct OwnedAttrsIterator(IntoIterRepr);
385
386impl Iterator for OwnedAttrsIterator {
387 type Item = (NixString, Value);
388
389 fn next(&mut self) -> Option<Self::Item> {
390 match &mut self.0 {
391 IntoIterRepr::Finite(inner) => inner.next(),
392 IntoIterRepr::Map(m) => m.next(),
393 }
394 }
395}
396
397impl ExactSizeIterator for OwnedAttrsIterator {
398 fn len(&self) -> usize {
399 match &self.0 {
400 IntoIterRepr::Finite(inner) => inner.len(),
401 IntoIterRepr::Map(inner) => inner.len(),
402 }
403 }
404}
405
406impl DoubleEndedIterator for OwnedAttrsIterator {
407 fn next_back(&mut self) -> Option<Self::Item> {
408 match &mut self.0 {
409 IntoIterRepr::Finite(inner) => inner.next_back(),
410 IntoIterRepr::Map(inner) => inner.next(),
412 }
413 }
414}