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, ByteSlice};
15use codemap::Span;
16use itertools::Itertools as _;
17use rustc_hash::FxHashMap;
18use serde::Deserialize;
19use serde::de::{Deserializer, Error, Visitor};
20
21use super::TotalDisplay;
22use super::Value;
23use super::string::NixString;
24use super::thunk::ThunkSet;
25use crate::CatchableErrorKind;
26use crate::errors::ErrorKind;
27
28static NAME: LazyLock<NixString> = LazyLock::new(|| "name".into());
29static VALUE: LazyLock<NixString> = LazyLock::new(|| "value".into());
30
31#[cfg(test)]
32mod tests;
33
34#[derive(Clone, Debug, Deserialize, Default)]
35pub(super) enum AttrsRep {
36 #[default]
37 Empty,
38
39 Map {
40 attrs: FxHashMap<NixString, Value>,
41
42 #[serde(skip)]
43 pos: Option<Box<FxHashMap<NixString, Span>>>,
44 },
45
46 KV { name: Value, value: Value },
50}
51
52impl AttrsRep {
53 fn select(&self, key: &BStr) -> Option<&Value> {
54 match self {
55 AttrsRep::Empty => None,
56
57 AttrsRep::KV { name, value } => match &**key {
58 b"name" => Some(name),
59 b"value" => Some(value),
60 _ => None,
61 },
62
63 AttrsRep::Map { attrs, .. } => attrs.get(key),
64 }
65 }
66
67 fn contains(&self, key: &BStr) -> bool {
68 match self {
69 AttrsRep::Empty => false,
70 AttrsRep::KV { .. } => key == "name" || key == "value",
71 AttrsRep::Map { attrs, .. } => attrs.contains_key(key),
72 }
73 }
74}
75
76#[repr(transparent)]
77#[derive(Clone, Debug, Default)]
78pub struct NixAttrs(pub(super) Rc<AttrsRep>);
79
80impl From<AttrsRep> for NixAttrs {
81 fn from(rep: AttrsRep) -> Self {
82 NixAttrs(Rc::new(rep))
83 }
84}
85
86impl<K, V> FromIterator<(K, V)> for NixAttrs
87where
88 NixString: From<K>,
89 Value: From<V>,
90{
91 fn from_iter<T>(iter: T) -> NixAttrs
92 where
93 T: IntoIterator<Item = (K, V)>,
94 {
95 AttrsRep::Map {
96 attrs: iter
97 .into_iter()
98 .map(|(k, v)| (k.into(), v.into()))
99 .collect(),
100 pos: None,
101 }
102 .into()
103 }
104}
105
106impl From<BTreeMap<NixString, Value>> for NixAttrs {
107 fn from(map: BTreeMap<NixString, Value>) -> Self {
108 AttrsRep::Map {
109 attrs: map.into_iter().collect(),
110 pos: None,
111 }
112 .into()
113 }
114}
115
116impl From<FxHashMap<NixString, Value>> for NixAttrs {
117 fn from(map: FxHashMap<NixString, Value>) -> Self {
118 AttrsRep::Map {
119 attrs: map,
120 pos: None,
121 }
122 .into()
123 }
124}
125
126impl TotalDisplay for NixAttrs {
127 fn total_fmt(&self, f: &mut std::fmt::Formatter<'_>, set: &mut ThunkSet) -> std::fmt::Result {
128 if self.is_derivation() {
129 write!(f, "«derivation")?;
130 if let Some(Value::Thunk(p)) = self.select("drvPath")
133 && p.is_forced()
134 && let Ok(drv) = p.value().to_contextful_str()
135 {
136 write!(f, " {}", drv.to_str_lossy())?;
137 };
138 return write!(f, "»");
139 }
140
141 f.write_str("{ ")?;
142
143 for (name, value) in self.iter_sorted() {
144 write!(f, "{} = ", name.ident_str())?;
145 value.total_fmt(f, set)?;
146 f.write_str("; ")?;
147 }
148
149 f.write_str("}")
150 }
151}
152
153impl<'de> Deserialize<'de> for NixAttrs {
154 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
155 where
156 D: Deserializer<'de>,
157 {
158 struct MapVisitor;
159
160 impl<'de> Visitor<'de> for MapVisitor {
161 type Value = NixAttrs;
162
163 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
164 formatter.write_str("a valid Nix attribute set")
165 }
166
167 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
168 where
169 A: serde::de::MapAccess<'de>,
170 {
171 let mut stack_array = Vec::with_capacity(map.size_hint().unwrap_or(0) * 2);
172
173 while let Some((key, value)) = map.next_entry()? {
174 stack_array.push(key);
175 stack_array.push(value);
176 }
177
178 Ok(NixAttrs::construct(stack_array.len() / 2, stack_array, &[])
179 .map_err(A::Error::custom)?
180 .expect("Catchable values are unreachable here"))
181 }
182 }
183
184 deserializer.deserialize_map(MapVisitor)
185 }
186}
187
188impl NixAttrs {
189 pub fn empty() -> Self {
190 AttrsRep::Empty.into()
191 }
192
193 pub fn ptr_eq(&self, other: &Self) -> bool {
198 Rc::ptr_eq(&self.0, &other.0)
199 }
200
201 pub fn update(self, other: Self) -> Self {
204 match (self.0.as_ref(), other.0.as_ref()) {
206 (AttrsRep::Empty, AttrsRep::Empty) => return self,
207 (AttrsRep::Empty, _) => return other,
208 (_, AttrsRep::Empty) => return self,
209 (AttrsRep::KV { .. }, AttrsRep::KV { .. }) => return other,
210
211 (AttrsRep::Map { .. }, AttrsRep::Map { .. })
215 | (AttrsRep::Map { .. }, AttrsRep::KV { .. })
216 | (AttrsRep::KV { .. }, AttrsRep::Map { .. }) => {}
217 };
218
219 match (Rc::unwrap_or_clone(self.0), Rc::unwrap_or_clone(other.0)) {
221 (AttrsRep::Map { mut attrs, .. }, AttrsRep::KV { name, value }) => {
222 attrs.insert(NAME.clone(), name);
223 attrs.insert(VALUE.clone(), value);
224 AttrsRep::Map { attrs, pos: None }.into()
225 }
226
227 (AttrsRep::KV { name, value }, AttrsRep::Map { mut attrs, .. }) => {
228 match attrs.entry(NAME.clone()) {
229 hash_map::Entry::Vacant(e) => {
230 e.insert(name);
231 }
232
233 hash_map::Entry::Occupied(_) => { }
234 };
235
236 match attrs.entry(VALUE.clone()) {
237 hash_map::Entry::Vacant(e) => {
238 e.insert(value);
239 }
240
241 hash_map::Entry::Occupied(_) => { }
242 };
243
244 AttrsRep::Map { attrs, pos: None }.into()
245 }
246
247 (AttrsRep::Map { attrs: mut m1, .. }, AttrsRep::Map { attrs: mut m2, .. }) => {
249 let map = if m1.len() >= m2.len() {
250 m1.extend(m2);
251 m1
252 } else {
253 for (key, val) in m1.into_iter() {
254 m2.entry(key).or_insert(val);
255 }
256 m2
257 };
258 AttrsRep::Map {
259 attrs: map,
260 pos: None,
261 }
262 .into()
263 }
264
265 _ => unreachable!(),
267 }
268 }
269
270 pub fn len(&self) -> usize {
272 match self.0.as_ref() {
273 AttrsRep::Map { attrs, .. } => attrs.len(),
274 AttrsRep::Empty => 0,
275 AttrsRep::KV { .. } => 2,
276 }
277 }
278
279 pub fn is_empty(&self) -> bool {
280 match self.0.as_ref() {
281 AttrsRep::Map { attrs, .. } => attrs.is_empty(),
282 AttrsRep::Empty => true,
283 AttrsRep::KV { .. } => false,
284 }
285 }
286
287 pub fn select<K>(&self, key: &K) -> Option<&Value>
289 where
290 K: Borrow<BStr> + ?Sized,
291 {
292 self.0.select(key.borrow())
293 }
294
295 pub fn select_required<K>(&self, key: &K) -> Result<&Value, ErrorKind>
298 where
299 K: Borrow<BStr> + ?Sized,
300 {
301 self.select(key)
302 .ok_or_else(|| ErrorKind::AttributeNotFound {
303 name: key.borrow().to_string(),
304 })
305 }
306
307 pub fn contains<'a, K: 'a>(&self, key: K) -> bool
308 where
309 &'a BStr: From<K>,
310 {
311 self.0.contains(key.into())
312 }
313
314 #[allow(clippy::needless_lifetimes)]
316 pub fn iter<'a>(&'a self) -> Iter<KeyValue<'a>> {
317 Iter(match &self.0.as_ref() {
318 AttrsRep::Map { attrs, .. } => KeyValue::Map(attrs.iter()),
319 AttrsRep::Empty => KeyValue::Empty,
320
321 AttrsRep::KV { name, value } => KeyValue::KV {
322 name,
323 value,
324 at: IterKV::default(),
325 },
326 })
327 }
328
329 pub fn iter_sorted(&self) -> Iter<KeyValue<'_>> {
332 Iter(match self.0.as_ref() {
333 AttrsRep::Empty => KeyValue::Empty,
334 AttrsRep::Map { attrs, .. } => {
335 let sorted = attrs.iter().sorted_by_key(|x| x.0);
336 KeyValue::Sorted(sorted)
337 }
338 AttrsRep::KV { name, value } => KeyValue::KV {
339 name,
340 value,
341 at: IterKV::default(),
342 },
343 })
344 }
345
346 pub fn into_iter_sorted(self) -> OwnedAttrsIterator {
349 let iter = match Rc::<AttrsRep>::try_unwrap(self.0) {
350 Ok(attrs) => match attrs {
351 AttrsRep::Empty => IntoIterRepr::Empty,
352 AttrsRep::Map { attrs, .. } => {
353 IntoIterRepr::Finite(attrs.into_iter().sorted_by(|(a, _), (b, _)| a.cmp(b)))
354 }
355 AttrsRep::KV { name, value } => IntoIterRepr::Finite(
356 vec![(NAME.clone(), name), (VALUE.clone(), value)].into_iter(),
357 ),
358 },
359 Err(rc) => match rc.as_ref() {
360 AttrsRep::Empty => IntoIterRepr::Empty,
361 AttrsRep::Map { attrs, .. } => IntoIterRepr::Finite(
362 attrs
363 .iter()
364 .map(|(k, v)| (k.clone(), v.clone()))
365 .sorted_by(|(a, _), (b, _)| a.cmp(b)),
366 ),
367 AttrsRep::KV { name, value } => IntoIterRepr::Finite(
368 vec![(NAME.clone(), name.clone()), (VALUE.clone(), value.clone())].into_iter(),
369 ),
370 },
371 };
372 OwnedAttrsIterator(iter)
373 }
374
375 pub fn keys(&self) -> Keys<'_> {
377 Keys(match self.0.as_ref() {
378 AttrsRep::Empty => KeysInner::Empty,
379 AttrsRep::KV { .. } => KeysInner::KV(IterKV::default()),
380
381 AttrsRep::Map { attrs, .. } => KeysInner::Map(attrs.keys()),
383 })
384 }
385
386 pub fn keys_sorted(&self) -> Keys<'_> {
389 Keys(match self.0.as_ref() {
390 AttrsRep::Map { attrs, .. } => KeysInner::Sorted(attrs.keys().sorted()),
391 AttrsRep::Empty => KeysInner::Empty,
392 AttrsRep::KV { .. } => KeysInner::KV(IterKV::default()),
393 })
394 }
395
396 pub fn construct(
399 count: usize,
400 mut stack_slice: Vec<Value>,
401 spans: &[Span],
402 ) -> Result<Result<Self, CatchableErrorKind>, ErrorKind> {
403 debug_assert!(
404 stack_slice.len() == count * 2,
405 "construct_attrs called with count == {}, but slice.len() == {}",
406 count,
407 stack_slice.len(),
408 );
409 if count == 0 {
422 return Ok(Ok(AttrsRep::Empty.into()));
423 }
424
425 if count == 2
427 && let Some(kv) = attempt_optimise_kv(&mut stack_slice)
428 {
429 return Ok(Ok(kv));
430 }
431
432 let mut attrs_map = FxHashMap::with_capacity_and_hasher(count, rustc_hash::FxBuildHasher);
433 let mut attrs_pos =
434 FxHashMap::with_capacity_and_hasher(spans.len(), rustc_hash::FxBuildHasher);
435 let mut spans = spans.iter().rev().copied();
436
437 for _ in 0..count {
438 let value = stack_slice.pop().unwrap();
439 let key = stack_slice.pop().unwrap();
440 let span = spans.next();
441
442 match key {
443 Value::String(ks) => set_attr(&mut attrs_map, ks, value, &mut attrs_pos, span)?,
444
445 Value::Null => {
446 continue;
450 }
451
452 Value::Catchable(err) => return Ok(Err(*err)),
453
454 other => return Err(ErrorKind::InvalidAttributeName(other)),
455 }
456 }
457
458 Ok(Ok(AttrsRep::Map {
459 attrs: attrs_map,
460 pos: if attrs_pos.is_empty() {
461 None
462 } else {
463 Some(Box::new(attrs_pos))
464 },
465 }
466 .into()))
467 }
468
469 pub(crate) fn from_kv(name: Value, value: Value) -> Self {
472 AttrsRep::KV { name, value }.into()
473 }
474
475 pub(crate) fn intersect(&self, other: &Self) -> NixAttrs {
478 match (self.0.as_ref(), other.0.as_ref()) {
479 (AttrsRep::Empty, _) | (_, AttrsRep::Empty) => AttrsRep::Empty.into(),
480 (AttrsRep::Map { attrs: lhs, .. }, AttrsRep::Map { attrs: rhs, .. }) => {
481 let mut out = FxHashMap::with_capacity_and_hasher(
482 std::cmp::min(lhs.len(), rhs.len()),
483 rustc_hash::FxBuildHasher,
484 );
485 if lhs.len() < rhs.len() {
486 for key in lhs.keys() {
487 if let Some(val) = rhs.get(key) {
488 out.insert(key.clone(), val.clone());
489 }
490 }
491 } else {
492 for (key, val) in rhs.iter() {
493 if lhs.contains_key(key) {
494 out.insert(key.clone(), val.clone());
495 }
496 }
497 };
498 AttrsRep::Map {
499 attrs: out,
500 pos: None,
501 }
502 .into()
503 }
504 (AttrsRep::Map { attrs, .. }, AttrsRep::KV { name, value }) => {
505 let mut out = FxHashMap::with_capacity_and_hasher(2, rustc_hash::FxBuildHasher);
506 if attrs.contains_key(NAME.as_bstr()) {
507 out.insert(NAME.clone(), name.clone());
508 }
509 if attrs.contains_key(VALUE.as_bstr()) {
510 out.insert(VALUE.clone(), value.clone());
511 }
512
513 if out.is_empty() {
514 NixAttrs::empty()
515 } else {
516 out.into()
517 }
518 }
519 (AttrsRep::KV { .. }, AttrsRep::Map { attrs, .. }) => {
520 let mut out = FxHashMap::with_capacity_and_hasher(2, rustc_hash::FxBuildHasher);
521 if let Some(name) = attrs.get(NAME.as_bstr()) {
522 out.insert(NAME.clone(), name.clone());
523 }
524 if let Some(value) = attrs.get(VALUE.as_bstr()) {
525 out.insert(VALUE.clone(), value.clone());
526 }
527
528 if out.is_empty() {
529 NixAttrs::empty()
530 } else {
531 AttrsRep::Map {
532 attrs: out,
533 pos: None,
534 }
535 .into()
536 }
537 }
538 (AttrsRep::KV { .. }, AttrsRep::KV { .. }) => other.clone(),
539 }
540 }
541
542 pub fn is_derivation(&self) -> bool {
544 let Some(Value::String(kind)) = self.select("type") else {
545 return false;
546 };
547 *kind == "derivation"
548 }
549
550 pub fn get_attr_pos<K>(&self, key: &K) -> Option<Span>
551 where
552 K: Borrow<BStr> + ?Sized,
553 {
554 match self.0.as_ref() {
555 AttrsRep::Map { pos, .. } => pos.as_ref()?.get(key.borrow()).copied(),
556 _ => None,
557 }
558 }
559}
560
561impl IntoIterator for NixAttrs {
562 type Item = (NixString, Value);
563 type IntoIter = OwnedAttrsIterator;
564
565 fn into_iter(self) -> Self::IntoIter {
566 match Rc::unwrap_or_clone(self.0) {
567 AttrsRep::Empty => OwnedAttrsIterator(IntoIterRepr::Empty),
568 AttrsRep::KV { name, value } => OwnedAttrsIterator(IntoIterRepr::Finite(
569 vec![(NAME.clone(), name), (VALUE.clone(), value)].into_iter(),
570 )),
571 AttrsRep::Map { attrs, .. } => OwnedAttrsIterator(IntoIterRepr::Map(attrs.into_iter())),
572 }
573 }
574}
575
576fn attempt_optimise_kv(slice: &mut [Value]) -> Option<NixAttrs> {
590 let (name_idx, value_idx) = {
591 match (&slice[2], &slice[0]) {
592 (Value::String(s1), Value::String(s2)) if (*s1 == *NAME && *s2 == *VALUE) => (3, 1),
593 (Value::String(s1), Value::String(s2)) if (*s1 == *VALUE && *s2 == *NAME) => (1, 3),
594
595 _ => return None,
599 }
600 };
601
602 Some(NixAttrs::from_kv(
603 slice[name_idx].clone(),
604 slice[value_idx].clone(),
605 ))
606}
607
608fn set_attr(
611 map: &mut FxHashMap<NixString, Value>,
612 key: NixString,
613 value: Value,
614 pos: &mut FxHashMap<NixString, Span>,
615 span: Option<Span>,
616) -> Result<(), ErrorKind> {
617 match map.entry(key) {
618 hash_map::Entry::Occupied(entry) => Err(ErrorKind::DuplicateAttrsKey {
619 key: entry.key().to_string(),
620 }),
621
622 hash_map::Entry::Vacant(entry) => {
623 if let Some(span) = span {
624 pos.insert(entry.key().clone(), span);
625 }
626 entry.insert(value);
627 Ok(())
628 }
629 }
630}
631
632#[derive(Debug, Default)]
635pub enum IterKV {
636 #[default]
637 Name,
638 Value,
639 Done,
640}
641
642impl IterKV {
643 fn next(&mut self) {
644 match *self {
645 Self::Name => *self = Self::Value,
646 Self::Value => *self = Self::Done,
647 Self::Done => {}
648 }
649 }
650}
651
652pub enum KeyValue<'a> {
655 Empty,
656
657 KV {
658 name: &'a Value,
659 value: &'a Value,
660 at: IterKV,
661 },
662
663 Map(hash_map::Iter<'a, NixString, Value>),
664
665 Sorted(std::vec::IntoIter<(&'a NixString, &'a Value)>),
666}
667
668#[repr(transparent)]
672pub struct Iter<T>(T);
673
674impl<'a> Iterator for Iter<KeyValue<'a>> {
675 type Item = (&'a NixString, &'a Value);
676
677 fn next(&mut self) -> Option<Self::Item> {
678 match &mut self.0 {
679 KeyValue::Map(inner) => inner.next(),
680 KeyValue::Empty => None,
681 KeyValue::KV { name, value, at } => match at {
682 IterKV::Name => {
683 at.next();
684 Some((&NAME, name))
685 }
686
687 IterKV::Value => {
688 at.next();
689 Some((&VALUE, value))
690 }
691
692 IterKV::Done => None,
693 },
694 KeyValue::Sorted(inner) => inner.next(),
695 }
696 }
697}
698
699impl ExactSizeIterator for Iter<KeyValue<'_>> {
700 fn len(&self) -> usize {
701 match &self.0 {
702 KeyValue::Empty => 0,
703 KeyValue::KV { .. } => 2,
704 KeyValue::Map(inner) => inner.len(),
705 KeyValue::Sorted(inner) => inner.len(),
706 }
707 }
708}
709
710enum KeysInner<'a> {
711 Empty,
712 KV(IterKV),
713 Map(hash_map::Keys<'a, NixString, Value>),
714 Sorted(std::vec::IntoIter<&'a NixString>),
715}
716
717pub struct Keys<'a>(KeysInner<'a>);
718
719impl<'a> Iterator for Keys<'a> {
720 type Item = &'a NixString;
721
722 fn next(&mut self) -> Option<Self::Item> {
723 match &mut self.0 {
724 KeysInner::Empty => None,
725 KeysInner::KV(at @ IterKV::Name) => {
726 at.next();
727 Some(&NAME)
728 }
729 KeysInner::KV(at @ IterKV::Value) => {
730 at.next();
731 Some(&VALUE)
732 }
733 KeysInner::KV(IterKV::Done) => None,
734 KeysInner::Map(m) => m.next(),
735 KeysInner::Sorted(v) => v.next(),
736 }
737 }
738}
739
740impl<'a> IntoIterator for &'a NixAttrs {
741 type Item = (&'a NixString, &'a Value);
742
743 type IntoIter = Iter<KeyValue<'a>>;
744
745 fn into_iter(self) -> Self::IntoIter {
746 self.iter()
747 }
748}
749
750impl ExactSizeIterator for Keys<'_> {
751 fn len(&self) -> usize {
752 match &self.0 {
753 KeysInner::Empty => 0,
754 KeysInner::KV(_) => 2,
755 KeysInner::Map(m) => m.len(),
756 KeysInner::Sorted(v) => v.len(),
757 }
758 }
759}
760
761pub enum IntoIterRepr {
763 Empty,
764 Finite(std::vec::IntoIter<(NixString, Value)>),
765 Map(hash_map::IntoIter<NixString, Value>),
766}
767
768#[repr(transparent)]
771pub struct OwnedAttrsIterator(IntoIterRepr);
772
773impl Iterator for OwnedAttrsIterator {
774 type Item = (NixString, Value);
775
776 fn next(&mut self) -> Option<Self::Item> {
777 match &mut self.0 {
778 IntoIterRepr::Empty => None,
779 IntoIterRepr::Finite(inner) => inner.next(),
780 IntoIterRepr::Map(m) => m.next(),
781 }
782 }
783}
784
785impl ExactSizeIterator for OwnedAttrsIterator {
786 fn len(&self) -> usize {
787 match &self.0 {
788 IntoIterRepr::Empty => 0,
789 IntoIterRepr::Finite(inner) => inner.len(),
790 IntoIterRepr::Map(inner) => inner.len(),
791 }
792 }
793}
794
795impl DoubleEndedIterator for OwnedAttrsIterator {
796 fn next_back(&mut self) -> Option<Self::Item> {
797 match &mut self.0 {
798 IntoIterRepr::Empty => None,
799 IntoIterRepr::Finite(inner) => inner.next_back(),
800 IntoIterRepr::Map(inner) => inner.next(),
802 }
803 }
804}