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 debug_assert!(
410 spans.len() == count || spans.is_empty(),
411 "construct_attrs called with count == {}, but spans.len() == {}",
412 count,
413 spans.len(),
414 );
415
416 if count == 0 {
418 return Ok(Ok(AttrsRep::Empty.into()));
419 }
420
421 if count == 2
423 && let Some(kv) = attempt_optimise_kv(&mut stack_slice)
424 {
425 return Ok(Ok(kv));
426 }
427
428 let mut attrs_map = FxHashMap::with_capacity_and_hasher(count, rustc_hash::FxBuildHasher);
429 let mut attrs_pos =
430 FxHashMap::with_capacity_and_hasher(spans.len(), rustc_hash::FxBuildHasher);
431 let mut spans = spans.iter().rev().copied();
432
433 for _ in 0..count {
434 let value = stack_slice.pop().unwrap();
435 let key = stack_slice.pop().unwrap();
436 let span = spans.next();
437
438 match key {
439 Value::String(ks) => set_attr(&mut attrs_map, ks, value, &mut attrs_pos, span)?,
440
441 Value::Null => {
442 continue;
446 }
447
448 Value::Catchable(err) => return Ok(Err(*err)),
449
450 other => return Err(ErrorKind::InvalidAttributeName(other)),
451 }
452 }
453
454 Ok(Ok(AttrsRep::Map {
455 attrs: attrs_map,
456 pos: if attrs_pos.is_empty() {
457 None
458 } else {
459 Some(Box::new(attrs_pos))
460 },
461 }
462 .into()))
463 }
464
465 pub(crate) fn from_kv(name: Value, value: Value) -> Self {
468 AttrsRep::KV { name, value }.into()
469 }
470
471 pub(crate) fn intersect(&self, other: &Self) -> NixAttrs {
474 match (self.0.as_ref(), other.0.as_ref()) {
475 (AttrsRep::Empty, _) | (_, AttrsRep::Empty) => AttrsRep::Empty.into(),
476 (AttrsRep::Map { attrs: lhs, .. }, AttrsRep::Map { attrs: rhs, .. }) => {
477 let mut out = FxHashMap::with_capacity_and_hasher(
478 std::cmp::min(lhs.len(), rhs.len()),
479 rustc_hash::FxBuildHasher,
480 );
481 if lhs.len() < rhs.len() {
482 for key in lhs.keys() {
483 if let Some(val) = rhs.get(key) {
484 out.insert(key.clone(), val.clone());
485 }
486 }
487 } else {
488 for (key, val) in rhs.iter() {
489 if lhs.contains_key(key) {
490 out.insert(key.clone(), val.clone());
491 }
492 }
493 };
494 AttrsRep::Map {
495 attrs: out,
496 pos: None,
497 }
498 .into()
499 }
500 (AttrsRep::Map { attrs, .. }, AttrsRep::KV { name, value }) => {
501 let mut out = FxHashMap::with_capacity_and_hasher(2, rustc_hash::FxBuildHasher);
502 if attrs.contains_key(NAME.as_bstr()) {
503 out.insert(NAME.clone(), name.clone());
504 }
505 if attrs.contains_key(VALUE.as_bstr()) {
506 out.insert(VALUE.clone(), value.clone());
507 }
508
509 if out.is_empty() {
510 NixAttrs::empty()
511 } else {
512 out.into()
513 }
514 }
515 (AttrsRep::KV { .. }, AttrsRep::Map { attrs, .. }) => {
516 let mut out = FxHashMap::with_capacity_and_hasher(2, rustc_hash::FxBuildHasher);
517 if let Some(name) = attrs.get(NAME.as_bstr()) {
518 out.insert(NAME.clone(), name.clone());
519 }
520 if let Some(value) = attrs.get(VALUE.as_bstr()) {
521 out.insert(VALUE.clone(), value.clone());
522 }
523
524 if out.is_empty() {
525 NixAttrs::empty()
526 } else {
527 AttrsRep::Map {
528 attrs: out,
529 pos: None,
530 }
531 .into()
532 }
533 }
534 (AttrsRep::KV { .. }, AttrsRep::KV { .. }) => other.clone(),
535 }
536 }
537
538 pub fn is_derivation(&self) -> bool {
540 let Some(Value::String(kind)) = self.select("type") else {
541 return false;
542 };
543 *kind == "derivation"
544 }
545
546 pub fn get_attr_pos<K>(&self, key: &K) -> Option<Span>
547 where
548 K: Borrow<BStr> + ?Sized,
549 {
550 match self.0.as_ref() {
551 AttrsRep::Map { pos, .. } => pos.as_ref()?.get(key.borrow()).copied(),
552 _ => None,
553 }
554 }
555}
556
557impl IntoIterator for NixAttrs {
558 type Item = (NixString, Value);
559 type IntoIter = OwnedAttrsIterator;
560
561 fn into_iter(self) -> Self::IntoIter {
562 match Rc::unwrap_or_clone(self.0) {
563 AttrsRep::Empty => OwnedAttrsIterator(IntoIterRepr::Empty),
564 AttrsRep::KV { name, value } => OwnedAttrsIterator(IntoIterRepr::Finite(
565 vec![(NAME.clone(), name), (VALUE.clone(), value)].into_iter(),
566 )),
567 AttrsRep::Map { attrs, .. } => OwnedAttrsIterator(IntoIterRepr::Map(attrs.into_iter())),
568 }
569 }
570}
571
572fn attempt_optimise_kv(slice: &mut [Value]) -> Option<NixAttrs> {
586 let (name_idx, value_idx) = {
587 match (&slice[2], &slice[0]) {
588 (Value::String(s1), Value::String(s2)) if (*s1 == *NAME && *s2 == *VALUE) => (3, 1),
589 (Value::String(s1), Value::String(s2)) if (*s1 == *VALUE && *s2 == *NAME) => (1, 3),
590
591 _ => return None,
595 }
596 };
597
598 Some(NixAttrs::from_kv(
599 slice[name_idx].clone(),
600 slice[value_idx].clone(),
601 ))
602}
603
604fn set_attr(
607 map: &mut FxHashMap<NixString, Value>,
608 key: NixString,
609 value: Value,
610 pos: &mut FxHashMap<NixString, Span>,
611 span: Option<Span>,
612) -> Result<(), ErrorKind> {
613 match map.entry(key) {
614 hash_map::Entry::Occupied(entry) => Err(ErrorKind::DuplicateAttrsKey {
615 key: entry.key().to_string(),
616 }),
617
618 hash_map::Entry::Vacant(entry) => {
619 if let Some(span) = span {
620 pos.insert(entry.key().clone(), span);
621 }
622 entry.insert(value);
623 Ok(())
624 }
625 }
626}
627
628#[derive(Debug, Default)]
631pub enum IterKV {
632 #[default]
633 Name,
634 Value,
635 Done,
636}
637
638impl IterKV {
639 fn next(&mut self) {
640 match *self {
641 Self::Name => *self = Self::Value,
642 Self::Value => *self = Self::Done,
643 Self::Done => {}
644 }
645 }
646}
647
648pub enum KeyValue<'a> {
651 Empty,
652
653 KV {
654 name: &'a Value,
655 value: &'a Value,
656 at: IterKV,
657 },
658
659 Map(hash_map::Iter<'a, NixString, Value>),
660
661 Sorted(std::vec::IntoIter<(&'a NixString, &'a Value)>),
662}
663
664#[repr(transparent)]
668pub struct Iter<T>(T);
669
670impl<'a> Iterator for Iter<KeyValue<'a>> {
671 type Item = (&'a NixString, &'a Value);
672
673 fn next(&mut self) -> Option<Self::Item> {
674 match &mut self.0 {
675 KeyValue::Map(inner) => inner.next(),
676 KeyValue::Empty => None,
677 KeyValue::KV { name, value, at } => match at {
678 IterKV::Name => {
679 at.next();
680 Some((&NAME, name))
681 }
682
683 IterKV::Value => {
684 at.next();
685 Some((&VALUE, value))
686 }
687
688 IterKV::Done => None,
689 },
690 KeyValue::Sorted(inner) => inner.next(),
691 }
692 }
693}
694
695impl ExactSizeIterator for Iter<KeyValue<'_>> {
696 fn len(&self) -> usize {
697 match &self.0 {
698 KeyValue::Empty => 0,
699 KeyValue::KV { .. } => 2,
700 KeyValue::Map(inner) => inner.len(),
701 KeyValue::Sorted(inner) => inner.len(),
702 }
703 }
704}
705
706enum KeysInner<'a> {
707 Empty,
708 KV(IterKV),
709 Map(hash_map::Keys<'a, NixString, Value>),
710 Sorted(std::vec::IntoIter<&'a NixString>),
711}
712
713pub struct Keys<'a>(KeysInner<'a>);
714
715impl<'a> Iterator for Keys<'a> {
716 type Item = &'a NixString;
717
718 fn next(&mut self) -> Option<Self::Item> {
719 match &mut self.0 {
720 KeysInner::Empty => None,
721 KeysInner::KV(at @ IterKV::Name) => {
722 at.next();
723 Some(&NAME)
724 }
725 KeysInner::KV(at @ IterKV::Value) => {
726 at.next();
727 Some(&VALUE)
728 }
729 KeysInner::KV(IterKV::Done) => None,
730 KeysInner::Map(m) => m.next(),
731 KeysInner::Sorted(v) => v.next(),
732 }
733 }
734}
735
736impl<'a> IntoIterator for &'a NixAttrs {
737 type Item = (&'a NixString, &'a Value);
738
739 type IntoIter = Iter<KeyValue<'a>>;
740
741 fn into_iter(self) -> Self::IntoIter {
742 self.iter()
743 }
744}
745
746impl ExactSizeIterator for Keys<'_> {
747 fn len(&self) -> usize {
748 match &self.0 {
749 KeysInner::Empty => 0,
750 KeysInner::KV(_) => 2,
751 KeysInner::Map(m) => m.len(),
752 KeysInner::Sorted(v) => v.len(),
753 }
754 }
755}
756
757pub enum IntoIterRepr {
759 Empty,
760 Finite(std::vec::IntoIter<(NixString, Value)>),
761 Map(hash_map::IntoIter<NixString, Value>),
762}
763
764#[repr(transparent)]
767pub struct OwnedAttrsIterator(IntoIterRepr);
768
769impl Iterator for OwnedAttrsIterator {
770 type Item = (NixString, Value);
771
772 fn next(&mut self) -> Option<Self::Item> {
773 match &mut self.0 {
774 IntoIterRepr::Empty => None,
775 IntoIterRepr::Finite(inner) => inner.next(),
776 IntoIterRepr::Map(m) => m.next(),
777 }
778 }
779}
780
781impl ExactSizeIterator for OwnedAttrsIterator {
782 fn len(&self) -> usize {
783 match &self.0 {
784 IntoIterRepr::Empty => 0,
785 IntoIterRepr::Finite(inner) => inner.len(),
786 IntoIterRepr::Map(inner) => inner.len(),
787 }
788 }
789}
790
791impl DoubleEndedIterator for OwnedAttrsIterator {
792 fn next_back(&mut self) -> Option<Self::Item> {
793 match &mut self.0 {
794 IntoIterRepr::Empty => None,
795 IntoIterRepr::Finite(inner) => inner.next_back(),
796 IntoIterRepr::Map(inner) => inner.next(),
798 }
799 }
800}