1use std::borrow::Borrow;
9use std::collections::{BTreeMap, hash_map};
10use std::iter::FromIterator;
11use std::rc::Rc;
12use std::sync::LazyLock;
13
14use bstr::BStr;
15use itertools::Itertools as _;
16use rustc_hash::FxHashMap;
17use serde::Deserialize;
18use serde::de::{Deserializer, Error, Visitor};
19
20use super::TotalDisplay;
21use super::Value;
22use super::string::NixString;
23use super::thunk::ThunkSet;
24use crate::CatchableErrorKind;
25use crate::errors::ErrorKind;
26
27static NAME: LazyLock<NixString> = LazyLock::new(|| "name".into());
28static VALUE: LazyLock<NixString> = LazyLock::new(|| "value".into());
29
30#[cfg(test)]
31mod tests;
32
33#[derive(Clone, Debug, Deserialize, Default)]
34pub(super) enum AttrsRep {
35 #[default]
36 Empty,
37
38 Map(FxHashMap<NixString, Value>),
39
40 KV {
44 name: Value,
45 value: Value,
46 },
47}
48
49impl AttrsRep {
50 fn select(&self, key: &BStr) -> Option<&Value> {
51 match self {
52 AttrsRep::Empty => None,
53
54 AttrsRep::KV { name, value } => match &**key {
55 b"name" => Some(name),
56 b"value" => Some(value),
57 _ => None,
58 },
59
60 AttrsRep::Map(map) => map.get(key),
61 }
62 }
63
64 fn contains(&self, key: &BStr) -> bool {
65 match self {
66 AttrsRep::Empty => false,
67 AttrsRep::KV { .. } => key == "name" || key == "value",
68 AttrsRep::Map(map) => map.contains_key(key),
69 }
70 }
71}
72
73#[repr(transparent)]
74#[derive(Clone, Debug, Default)]
75pub struct NixAttrs(pub(super) Rc<AttrsRep>);
76
77impl From<AttrsRep> for NixAttrs {
78 fn from(rep: AttrsRep) -> Self {
79 NixAttrs(Rc::new(rep))
80 }
81}
82
83impl<K, V> FromIterator<(K, V)> for NixAttrs
84where
85 NixString: From<K>,
86 Value: From<V>,
87{
88 fn from_iter<T>(iter: T) -> NixAttrs
89 where
90 T: IntoIterator<Item = (K, V)>,
91 {
92 AttrsRep::Map(
93 iter.into_iter()
94 .map(|(k, v)| (k.into(), v.into()))
95 .collect(),
96 )
97 .into()
98 }
99}
100
101impl From<BTreeMap<NixString, Value>> for NixAttrs {
102 fn from(map: BTreeMap<NixString, Value>) -> Self {
103 AttrsRep::Map(map.into_iter().collect()).into()
104 }
105}
106
107impl From<FxHashMap<NixString, Value>> for NixAttrs {
108 fn from(map: FxHashMap<NixString, Value>) -> Self {
109 AttrsRep::Map(map).into()
110 }
111}
112
113impl TotalDisplay for NixAttrs {
114 fn total_fmt(&self, f: &mut std::fmt::Formatter<'_>, set: &mut ThunkSet) -> std::fmt::Result {
115 if let Some(Value::String(s)) = self.select("type") {
116 if *s == "derivation" {
117 write!(f, "«derivation ")?;
118 if let Some(p) = self.select("drvPath") {
119 p.total_fmt(f, set)?;
120 } else {
121 write!(f, "???")?;
122 }
123 return write!(f, "»");
124 }
125 }
126
127 f.write_str("{ ")?;
128
129 for (name, value) in self.iter_sorted() {
130 write!(f, "{} = ", name.ident_str())?;
131 value.total_fmt(f, set)?;
132 f.write_str("; ")?;
133 }
134
135 f.write_str("}")
136 }
137}
138
139impl<'de> Deserialize<'de> for NixAttrs {
140 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
141 where
142 D: Deserializer<'de>,
143 {
144 struct MapVisitor;
145
146 impl<'de> Visitor<'de> for MapVisitor {
147 type Value = NixAttrs;
148
149 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
150 formatter.write_str("a valid Nix attribute set")
151 }
152
153 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
154 where
155 A: serde::de::MapAccess<'de>,
156 {
157 let mut stack_array = Vec::with_capacity(map.size_hint().unwrap_or(0) * 2);
158
159 while let Some((key, value)) = map.next_entry()? {
160 stack_array.push(key);
161 stack_array.push(value);
162 }
163
164 Ok(NixAttrs::construct(stack_array.len() / 2, stack_array)
165 .map_err(A::Error::custom)?
166 .expect("Catchable values are unreachable here"))
167 }
168 }
169
170 deserializer.deserialize_map(MapVisitor)
171 }
172}
173
174impl NixAttrs {
175 pub fn empty() -> Self {
176 AttrsRep::Empty.into()
177 }
178
179 pub fn ptr_eq(&self, other: &Self) -> bool {
184 Rc::ptr_eq(&self.0, &other.0)
185 }
186
187 pub fn update(self, other: Self) -> Self {
190 match (self.0.as_ref(), other.0.as_ref()) {
192 (AttrsRep::Empty, AttrsRep::Empty) => return self,
193 (AttrsRep::Empty, _) => return other,
194 (_, AttrsRep::Empty) => return self,
195 (AttrsRep::KV { .. }, AttrsRep::KV { .. }) => return other,
196
197 (AttrsRep::Map(_), AttrsRep::Map(_))
201 | (AttrsRep::Map(_), AttrsRep::KV { .. })
202 | (AttrsRep::KV { .. }, AttrsRep::Map(_)) => {}
203 };
204
205 match (Rc::unwrap_or_clone(self.0), Rc::unwrap_or_clone(other.0)) {
207 (AttrsRep::Map(mut m), AttrsRep::KV { name, value }) => {
208 m.insert(NAME.clone(), name);
209 m.insert(VALUE.clone(), value);
210 AttrsRep::Map(m).into()
211 }
212
213 (AttrsRep::KV { name, value }, AttrsRep::Map(mut m)) => {
214 match m.entry(NAME.clone()) {
215 hash_map::Entry::Vacant(e) => {
216 e.insert(name);
217 }
218
219 hash_map::Entry::Occupied(_) => { }
220 };
221
222 match m.entry(VALUE.clone()) {
223 hash_map::Entry::Vacant(e) => {
224 e.insert(value);
225 }
226
227 hash_map::Entry::Occupied(_) => { }
228 };
229
230 AttrsRep::Map(m).into()
231 }
232
233 (AttrsRep::Map(mut m1), AttrsRep::Map(mut m2)) => {
235 let map = if m1.len() >= m2.len() {
236 m1.extend(m2);
237 m1
238 } else {
239 for (key, val) in m1.into_iter() {
240 m2.entry(key).or_insert(val);
241 }
242 m2
243 };
244 AttrsRep::Map(map).into()
245 }
246
247 _ => unreachable!(),
249 }
250 }
251
252 pub fn len(&self) -> usize {
254 match self.0.as_ref() {
255 AttrsRep::Map(map) => map.len(),
256 AttrsRep::Empty => 0,
257 AttrsRep::KV { .. } => 2,
258 }
259 }
260
261 pub fn is_empty(&self) -> bool {
262 match self.0.as_ref() {
263 AttrsRep::Map(map) => map.is_empty(),
264 AttrsRep::Empty => true,
265 AttrsRep::KV { .. } => false,
266 }
267 }
268
269 pub fn select<K>(&self, key: &K) -> Option<&Value>
271 where
272 K: Borrow<BStr> + ?Sized,
273 {
274 self.0.select(key.borrow())
275 }
276
277 pub fn select_required<K>(&self, key: &K) -> Result<&Value, ErrorKind>
280 where
281 K: Borrow<BStr> + ?Sized,
282 {
283 self.select(key)
284 .ok_or_else(|| ErrorKind::AttributeNotFound {
285 name: key.borrow().to_string(),
286 })
287 }
288
289 pub fn contains<'a, K: 'a>(&self, key: K) -> bool
290 where
291 &'a BStr: From<K>,
292 {
293 self.0.contains(key.into())
294 }
295
296 #[allow(clippy::needless_lifetimes)]
298 pub fn iter<'a>(&'a self) -> Iter<KeyValue<'a>> {
299 Iter(match &self.0.as_ref() {
300 AttrsRep::Map(map) => KeyValue::Map(map.iter()),
301 AttrsRep::Empty => KeyValue::Empty,
302
303 AttrsRep::KV { name, value } => KeyValue::KV {
304 name,
305 value,
306 at: IterKV::default(),
307 },
308 })
309 }
310
311 pub fn iter_sorted(&self) -> Iter<KeyValue<'_>> {
314 Iter(match self.0.as_ref() {
315 AttrsRep::Empty => KeyValue::Empty,
316 AttrsRep::Map(map) => {
317 let sorted = map.iter().sorted_by_key(|x| x.0);
318 KeyValue::Sorted(sorted)
319 }
320 AttrsRep::KV { name, value } => KeyValue::KV {
321 name,
322 value,
323 at: IterKV::default(),
324 },
325 })
326 }
327
328 pub fn into_iter_sorted(self) -> OwnedAttrsIterator {
331 let iter = match Rc::<AttrsRep>::try_unwrap(self.0) {
332 Ok(attrs) => match attrs {
333 AttrsRep::Empty => IntoIterRepr::Empty,
334 AttrsRep::Map(map) => {
335 IntoIterRepr::Finite(map.into_iter().sorted_by(|(a, _), (b, _)| a.cmp(b)))
336 }
337 AttrsRep::KV { name, value } => IntoIterRepr::Finite(
338 vec![(NAME.clone(), name), (VALUE.clone(), value)].into_iter(),
339 ),
340 },
341 Err(rc) => match rc.as_ref() {
342 AttrsRep::Empty => IntoIterRepr::Empty,
343 AttrsRep::Map(map) => IntoIterRepr::Finite(
344 map.iter()
345 .map(|(k, v)| (k.clone(), v.clone()))
346 .sorted_by(|(a, _), (b, _)| a.cmp(b)),
347 ),
348 AttrsRep::KV { name, value } => IntoIterRepr::Finite(
349 vec![(NAME.clone(), name.clone()), (VALUE.clone(), value.clone())].into_iter(),
350 ),
351 },
352 };
353 OwnedAttrsIterator(iter)
354 }
355
356 pub fn keys(&self) -> Keys {
358 Keys(match self.0.as_ref() {
359 AttrsRep::Empty => KeysInner::Empty,
360 AttrsRep::KV { .. } => KeysInner::KV(IterKV::default()),
361
362 AttrsRep::Map(m) => KeysInner::Map(m.keys()),
364 })
365 }
366
367 pub fn keys_sorted(&self) -> Keys {
370 Keys(match self.0.as_ref() {
371 AttrsRep::Map(map) => KeysInner::Sorted(map.keys().sorted()),
372 AttrsRep::Empty => KeysInner::Empty,
373 AttrsRep::KV { .. } => KeysInner::KV(IterKV::default()),
374 })
375 }
376
377 pub fn construct(
380 count: usize,
381 mut stack_slice: Vec<Value>,
382 ) -> Result<Result<Self, CatchableErrorKind>, ErrorKind> {
383 debug_assert!(
384 stack_slice.len() == count * 2,
385 "construct_attrs called with count == {}, but slice.len() == {}",
386 count,
387 stack_slice.len(),
388 );
389
390 if count == 0 {
392 return Ok(Ok(AttrsRep::Empty.into()));
393 }
394
395 if count == 2 {
397 if let Some(kv) = attempt_optimise_kv(&mut stack_slice) {
398 return Ok(Ok(kv));
399 }
400 }
401
402 let mut attrs_map = FxHashMap::with_capacity_and_hasher(count, rustc_hash::FxBuildHasher);
403
404 for _ in 0..count {
405 let value = stack_slice.pop().unwrap();
406 let key = stack_slice.pop().unwrap();
407
408 match key {
409 Value::String(ks) => set_attr(&mut attrs_map, ks, value)?,
410
411 Value::Null => {
412 continue;
416 }
417
418 Value::Catchable(err) => return Ok(Err(*err)),
419
420 other => return Err(ErrorKind::InvalidAttributeName(other)),
421 }
422 }
423
424 Ok(Ok(AttrsRep::Map(attrs_map).into()))
425 }
426
427 pub(crate) fn from_kv(name: Value, value: Value) -> Self {
430 AttrsRep::KV { name, value }.into()
431 }
432
433 pub(crate) fn intersect(&self, other: &Self) -> NixAttrs {
436 match (self.0.as_ref(), other.0.as_ref()) {
437 (AttrsRep::Empty, _) | (_, AttrsRep::Empty) => AttrsRep::Empty.into(),
438 (AttrsRep::Map(lhs), AttrsRep::Map(rhs)) => {
439 let mut out = FxHashMap::with_capacity_and_hasher(
440 std::cmp::min(lhs.len(), rhs.len()),
441 rustc_hash::FxBuildHasher,
442 );
443 if lhs.len() < rhs.len() {
444 for key in lhs.keys() {
445 if let Some(val) = rhs.get(key) {
446 out.insert(key.clone(), val.clone());
447 }
448 }
449 } else {
450 for (key, val) in rhs.iter() {
451 if lhs.contains_key(key) {
452 out.insert(key.clone(), val.clone());
453 }
454 }
455 };
456 out.into()
457 }
458 (AttrsRep::Map(map), AttrsRep::KV { name, value }) => {
459 let mut out = FxHashMap::with_capacity_and_hasher(2, rustc_hash::FxBuildHasher);
460 if map.contains_key(NAME.as_bstr()) {
461 out.insert(NAME.clone(), name.clone());
462 }
463 if map.contains_key(VALUE.as_bstr()) {
464 out.insert(VALUE.clone(), value.clone());
465 }
466
467 if out.is_empty() {
468 NixAttrs::empty()
469 } else {
470 out.into()
471 }
472 }
473 (AttrsRep::KV { .. }, AttrsRep::Map(map)) => {
474 let mut out = FxHashMap::with_capacity_and_hasher(2, rustc_hash::FxBuildHasher);
475 if let Some(name) = map.get(NAME.as_bstr()) {
476 out.insert(NAME.clone(), name.clone());
477 }
478 if let Some(value) = map.get(VALUE.as_bstr()) {
479 out.insert(VALUE.clone(), value.clone());
480 }
481
482 if out.is_empty() {
483 NixAttrs::empty()
484 } else {
485 out.into()
486 }
487 }
488 (AttrsRep::KV { .. }, AttrsRep::KV { .. }) => other.clone(),
489 }
490 }
491}
492
493impl IntoIterator for NixAttrs {
494 type Item = (NixString, Value);
495 type IntoIter = OwnedAttrsIterator;
496
497 fn into_iter(self) -> Self::IntoIter {
498 match Rc::unwrap_or_clone(self.0) {
499 AttrsRep::Empty => OwnedAttrsIterator(IntoIterRepr::Empty),
500 AttrsRep::KV { name, value } => OwnedAttrsIterator(IntoIterRepr::Finite(
501 vec![(NAME.clone(), name), (VALUE.clone(), value)].into_iter(),
502 )),
503 AttrsRep::Map(map) => OwnedAttrsIterator(IntoIterRepr::Map(map.into_iter())),
504 }
505 }
506}
507
508fn attempt_optimise_kv(slice: &mut [Value]) -> Option<NixAttrs> {
522 let (name_idx, value_idx) = {
523 match (&slice[2], &slice[0]) {
524 (Value::String(s1), Value::String(s2)) if (*s1 == *NAME && *s2 == *VALUE) => (3, 1),
525 (Value::String(s1), Value::String(s2)) if (*s1 == *VALUE && *s2 == *NAME) => (1, 3),
526
527 _ => return None,
531 }
532 };
533
534 Some(NixAttrs::from_kv(
535 slice[name_idx].clone(),
536 slice[value_idx].clone(),
537 ))
538}
539
540fn set_attr(
543 map: &mut FxHashMap<NixString, Value>,
544 key: NixString,
545 value: Value,
546) -> Result<(), ErrorKind> {
547 match map.entry(key) {
548 hash_map::Entry::Occupied(entry) => Err(ErrorKind::DuplicateAttrsKey {
549 key: entry.key().to_string(),
550 }),
551
552 hash_map::Entry::Vacant(entry) => {
553 entry.insert(value);
554 Ok(())
555 }
556 }
557}
558
559#[derive(Debug, Default)]
562pub enum IterKV {
563 #[default]
564 Name,
565 Value,
566 Done,
567}
568
569impl IterKV {
570 fn next(&mut self) {
571 match *self {
572 Self::Name => *self = Self::Value,
573 Self::Value => *self = Self::Done,
574 Self::Done => {}
575 }
576 }
577}
578
579pub enum KeyValue<'a> {
582 Empty,
583
584 KV {
585 name: &'a Value,
586 value: &'a Value,
587 at: IterKV,
588 },
589
590 Map(hash_map::Iter<'a, NixString, Value>),
591
592 Sorted(std::vec::IntoIter<(&'a NixString, &'a Value)>),
593}
594
595#[repr(transparent)]
599pub struct Iter<T>(T);
600
601impl<'a> Iterator for Iter<KeyValue<'a>> {
602 type Item = (&'a NixString, &'a Value);
603
604 fn next(&mut self) -> Option<Self::Item> {
605 match &mut self.0 {
606 KeyValue::Map(inner) => inner.next(),
607 KeyValue::Empty => None,
608 KeyValue::KV { name, value, at } => match at {
609 IterKV::Name => {
610 at.next();
611 Some((&NAME, name))
612 }
613
614 IterKV::Value => {
615 at.next();
616 Some((&VALUE, value))
617 }
618
619 IterKV::Done => None,
620 },
621 KeyValue::Sorted(inner) => inner.next(),
622 }
623 }
624}
625
626impl ExactSizeIterator for Iter<KeyValue<'_>> {
627 fn len(&self) -> usize {
628 match &self.0 {
629 KeyValue::Empty => 0,
630 KeyValue::KV { .. } => 2,
631 KeyValue::Map(inner) => inner.len(),
632 KeyValue::Sorted(inner) => inner.len(),
633 }
634 }
635}
636
637enum KeysInner<'a> {
638 Empty,
639 KV(IterKV),
640 Map(hash_map::Keys<'a, NixString, Value>),
641 Sorted(std::vec::IntoIter<&'a NixString>),
642}
643
644pub struct Keys<'a>(KeysInner<'a>);
645
646impl<'a> Iterator for Keys<'a> {
647 type Item = &'a NixString;
648
649 fn next(&mut self) -> Option<Self::Item> {
650 match &mut self.0 {
651 KeysInner::Empty => None,
652 KeysInner::KV(at @ IterKV::Name) => {
653 at.next();
654 Some(&NAME)
655 }
656 KeysInner::KV(at @ IterKV::Value) => {
657 at.next();
658 Some(&VALUE)
659 }
660 KeysInner::KV(IterKV::Done) => None,
661 KeysInner::Map(m) => m.next(),
662 KeysInner::Sorted(v) => v.next(),
663 }
664 }
665}
666
667impl<'a> IntoIterator for &'a NixAttrs {
668 type Item = (&'a NixString, &'a Value);
669
670 type IntoIter = Iter<KeyValue<'a>>;
671
672 fn into_iter(self) -> Self::IntoIter {
673 self.iter()
674 }
675}
676
677impl ExactSizeIterator for Keys<'_> {
678 fn len(&self) -> usize {
679 match &self.0 {
680 KeysInner::Empty => 0,
681 KeysInner::KV(_) => 2,
682 KeysInner::Map(m) => m.len(),
683 KeysInner::Sorted(v) => v.len(),
684 }
685 }
686}
687
688pub enum IntoIterRepr {
690 Empty,
691 Finite(std::vec::IntoIter<(NixString, Value)>),
692 Map(hash_map::IntoIter<NixString, Value>),
693}
694
695#[repr(transparent)]
698pub struct OwnedAttrsIterator(IntoIterRepr);
699
700impl Iterator for OwnedAttrsIterator {
701 type Item = (NixString, Value);
702
703 fn next(&mut self) -> Option<Self::Item> {
704 match &mut self.0 {
705 IntoIterRepr::Empty => None,
706 IntoIterRepr::Finite(inner) => inner.next(),
707 IntoIterRepr::Map(m) => m.next(),
708 }
709 }
710}
711
712impl ExactSizeIterator for OwnedAttrsIterator {
713 fn len(&self) -> usize {
714 match &self.0 {
715 IntoIterRepr::Empty => 0,
716 IntoIterRepr::Finite(inner) => inner.len(),
717 IntoIterRepr::Map(inner) => inner.len(),
718 }
719 }
720}
721
722impl DoubleEndedIterator for OwnedAttrsIterator {
723 fn next_back(&mut self) -> Option<Self::Item> {
724 match &mut self.0 {
725 IntoIterRepr::Empty => None,
726 IntoIterRepr::Finite(inner) => inner.next_back(),
727 IntoIterRepr::Map(inner) => inner.next(),
729 }
730 }
731}