1use std::borrow::{Borrow, Cow};
2use std::fmt::{Debug, Display, Formatter, Write};
3use std::hash::{Hash, Hasher};
4use std::ops::Deref;
5
6use arrayvec::ArrayVec;
7use char_str::{CharStr, CharString};
8
9use crate::Expr;
10use crate::generated::ExprName;
11
12#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
37#[cfg_attr(feature = "salsa", derive(salsa::SalsaValue))]
38#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
39#[cfg_attr(feature = "cache", derive(ruff_macros::CacheKey))]
40#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
41#[cfg_attr(
42 feature = "schemars",
43 derive(schemars::JsonSchema),
44 schemars(with = "String")
45)]
46pub struct Name(CharStr);
47
48impl Name {
49 #[inline]
50 pub fn empty() -> Self {
51 Self(CharStr::new())
52 }
53
54 #[inline]
55 pub fn new(name: impl AsRef<str>) -> Self {
56 Self(CharStr::from(name.as_ref()))
57 }
58
59 #[inline]
61 pub fn new_inline(name: impl AsRef<str>) -> Option<Self> {
62 CharStr::new_inline(name.as_ref()).map(Self)
63 }
64
65 #[inline]
67 pub fn new_heap(name: impl AsRef<str>) -> Self {
68 Self(CharStr::new_heap(name.as_ref()))
69 }
70
71 #[inline]
72 pub const fn new_static(name: &'static str) -> Self {
73 Self(CharStr::from_static_str(name))
74 }
75
76 #[inline]
80 pub fn concat<T: AsRef<str>>(slices: &[T]) -> Self {
81 Self(CharStr::concat(slices))
82 }
83
84 #[inline]
91 pub fn join<T: AsRef<str>>(slices: &[T], separator: &str) -> Self {
92 Self(CharStr::join(slices, separator))
93 }
94
95 #[inline]
96 pub fn as_str(&self) -> &str {
97 self.0.as_str()
98 }
99}
100
101impl Debug for Name {
102 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
103 write!(f, "Name({:?})", self.as_str())
104 }
105}
106
107impl AsRef<str> for Name {
108 #[inline]
109 fn as_ref(&self) -> &str {
110 self.as_str()
111 }
112}
113
114impl Deref for Name {
115 type Target = str;
116
117 #[inline]
118 fn deref(&self) -> &Self::Target {
119 self.as_str()
120 }
121}
122
123impl Borrow<str> for Name {
124 #[inline]
125 fn borrow(&self) -> &str {
126 self.as_str()
127 }
128}
129
130impl<'a> From<&'a str> for Name {
131 #[inline]
132 fn from(s: &'a str) -> Self {
133 Name::new(s)
134 }
135}
136
137impl From<String> for Name {
138 #[inline]
139 fn from(s: String) -> Self {
140 Name(s.into())
141 }
142}
143
144impl<'a> From<&'a String> for Name {
145 #[inline]
146 fn from(s: &'a String) -> Self {
147 Name::new(s)
148 }
149}
150
151impl<'a> From<Cow<'a, str>> for Name {
152 #[inline]
153 fn from(cow: Cow<'a, str>) -> Self {
154 Name(cow.into())
155 }
156}
157
158impl From<Box<str>> for Name {
159 #[inline]
160 fn from(b: Box<str>) -> Self {
161 Name(b.into())
162 }
163}
164
165#[cfg(feature = "salsa")]
166impl salsa::Lookup<Name> for &str {
167 #[inline]
168 fn into_owned(self) -> Name {
169 Name::new(self)
170 }
171}
172
173#[cfg(feature = "salsa")]
174impl salsa::HashEqLike<&str> for Name {
175 #[inline]
176 fn eq(&self, data: &&str) -> bool {
177 self == *data
178 }
179}
180
181impl From<Name> for String {
182 #[inline]
183 fn from(name: Name) -> Self {
184 name.0.into()
185 }
186}
187
188impl From<Name> for CharStr {
189 #[inline]
190 fn from(name: Name) -> Self {
191 name.0
192 }
193}
194
195#[cfg(feature = "salsa")]
196impl salsa::Lookup<compact_str::CompactString> for Name {
197 #[inline]
198 fn into_owned(self) -> compact_str::CompactString {
199 compact_str::CompactString::new(self.as_str())
200 }
201}
202
203#[cfg(feature = "salsa")]
204impl salsa::Lookup<compact_str::CompactString> for &Name {
205 #[inline]
206 fn into_owned(self) -> compact_str::CompactString {
207 compact_str::CompactString::new(self.as_str())
208 }
209}
210
211#[cfg(feature = "salsa")]
212impl salsa::HashEqLike<Name> for compact_str::CompactString {
213 #[inline]
214 fn eq(&self, data: &Name) -> bool {
215 self.as_str() == data.as_str()
216 }
217}
218
219#[cfg(feature = "salsa")]
220impl salsa::HashEqLike<&Name> for compact_str::CompactString {
221 #[inline]
222 fn eq(&self, data: &&Name) -> bool {
223 self.as_str() == data.as_str()
224 }
225}
226
227impl From<CharString> for Name {
228 #[inline]
229 fn from(name: CharString) -> Self {
230 Self(name.freeze())
231 }
232}
233
234impl FromIterator<char> for Name {
235 fn from_iter<I: IntoIterator<Item = char>>(iter: I) -> Self {
236 Self(iter.into_iter().collect())
237 }
238}
239
240impl std::fmt::Display for Name {
241 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
242 f.write_str(self.as_str())
243 }
244}
245
246impl PartialEq<str> for Name {
247 #[inline]
248 fn eq(&self, other: &str) -> bool {
249 self.0 == other
250 }
251}
252
253impl PartialEq<Name> for str {
254 #[inline]
255 fn eq(&self, other: &Name) -> bool {
256 other == self
257 }
258}
259
260impl PartialEq<&str> for Name {
261 #[inline]
262 fn eq(&self, other: &&str) -> bool {
263 self.0 == *other
264 }
265}
266
267impl PartialEq<Name> for &str {
268 #[inline]
269 fn eq(&self, other: &Name) -> bool {
270 other == self
271 }
272}
273
274impl PartialEq<String> for Name {
275 fn eq(&self, other: &String) -> bool {
276 self == other.as_str()
277 }
278}
279
280impl PartialEq<Name> for String {
281 #[inline]
282 fn eq(&self, other: &Name) -> bool {
283 other == self
284 }
285}
286
287impl PartialEq<&String> for Name {
288 #[inline]
289 fn eq(&self, other: &&String) -> bool {
290 self == other.as_str()
291 }
292}
293
294impl PartialEq<Name> for &String {
295 #[inline]
296 fn eq(&self, other: &Name) -> bool {
297 other == self
298 }
299}
300
301#[derive(Debug, Clone, PartialEq, Eq, Hash)]
303pub struct QualifiedName<'a>(SegmentsVec<'a>);
304
305impl<'a> QualifiedName<'a> {
306 #[inline]
315 pub fn from_dotted_name(name: &'a str) -> Self {
316 if let Some(dot) = name.find('.') {
317 let mut builder = QualifiedNameBuilder::default();
318 builder.push(&name[..dot]);
319 builder.extend(name[dot + 1..].split('.'));
320 builder.build()
321 } else {
322 Self::builtin(name)
323 }
324 }
325
326 #[inline]
328 pub fn user_defined(name: &'a str) -> Self {
329 name.split('.').collect()
330 }
331
332 #[inline]
334 pub fn builtin(name: &'a str) -> Self {
335 debug_assert!(!name.contains('.'));
336 Self(SegmentsVec::from_slice(&["", name]))
337 }
338
339 #[inline]
340 pub fn segments(&self) -> &[&'a str] {
341 self.0.as_slice()
342 }
343
344 fn is_builtin(&self) -> bool {
353 matches!(self.segments(), ["", ..])
354 }
355
356 pub fn is_unresolved_import(&self) -> bool {
359 matches!(self.segments(), [".", ..])
360 }
361
362 pub fn starts_with(&self, other: &QualifiedName<'_>) -> bool {
363 self.segments().starts_with(other.segments())
364 }
365
366 #[must_use]
368 pub fn append_member(self, member: &'a str) -> Self {
369 let mut inner = self.0;
370 inner.push(member);
371 Self(inner)
372 }
373
374 #[must_use]
376 pub fn extend_members<T: IntoIterator<Item = &'a str>>(self, members: T) -> Self {
377 let mut inner = self.0;
378 inner.extend(members);
379 Self(inner)
380 }
381}
382
383impl Display for QualifiedName<'_> {
384 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
385 let segments = self.segments();
386
387 if self.is_unresolved_import() {
388 let mut iter = segments.iter();
389 for segment in iter.by_ref() {
390 if *segment == "." {
391 f.write_char('.')?;
392 } else {
393 f.write_str(segment)?;
394 break;
395 }
396 }
397 for segment in iter {
398 f.write_char('.')?;
399 f.write_str(segment)?;
400 }
401 } else {
402 let segments = if self.is_builtin() {
403 &segments[1..]
404 } else {
405 segments
406 };
407
408 let mut first = true;
409 for segment in segments {
410 if !first {
411 f.write_char('.')?;
412 }
413
414 f.write_str(segment)?;
415 first = false;
416 }
417 }
418
419 Ok(())
420 }
421}
422
423impl<'a> FromIterator<&'a str> for QualifiedName<'a> {
424 fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
425 Self(SegmentsVec::from_iter(iter))
426 }
427}
428
429#[derive(Debug, Clone, Default)]
430pub struct QualifiedNameBuilder<'a> {
431 segments: SegmentsVec<'a>,
432}
433
434impl<'a> QualifiedNameBuilder<'a> {
435 pub fn with_capacity(capacity: usize) -> Self {
436 Self {
437 segments: SegmentsVec::with_capacity(capacity),
438 }
439 }
440
441 #[inline]
442 pub(crate) fn is_empty(&self) -> bool {
443 self.segments.is_empty()
444 }
445
446 #[inline]
447 pub fn push(&mut self, segment: &'a str) {
448 self.segments.push(segment);
449 }
450
451 #[inline]
452 pub(crate) fn pop(&mut self) {
453 self.segments.pop();
454 }
455
456 #[inline]
457 pub fn extend(&mut self, segments: impl IntoIterator<Item = &'a str>) {
458 self.segments.extend(segments);
459 }
460
461 #[inline]
462 pub(crate) fn extend_from_slice(&mut self, segments: &[&'a str]) {
463 self.segments.extend_from_slice(segments);
464 }
465
466 pub fn build(self) -> QualifiedName<'a> {
467 QualifiedName(self.segments)
468 }
469}
470
471#[derive(Debug, Clone, PartialEq, Eq, Hash)]
472pub struct UnqualifiedName<'a>(SegmentsVec<'a>);
473
474impl<'a> UnqualifiedName<'a> {
475 pub fn from_expr(expr: &'a Expr) -> Option<Self> {
477 let attr1 = match expr {
480 Expr::Attribute(attr1) => attr1,
481 Expr::Name(ExprName { id, .. }) => return Some(Self::from_slice(&[id.as_str()])),
483 _ => return None,
484 };
485
486 let attr2 = match attr1.value.as_ref() {
487 Expr::Attribute(attr2) => attr2,
488 Expr::Name(ExprName { id, .. }) => {
490 return Some(Self::from_slice(&[id.as_str(), attr1.attr.as_str()]));
491 }
492 _ => return None,
493 };
494
495 let attr3 = match attr2.value.as_ref() {
496 Expr::Attribute(attr3) => attr3,
497 Expr::Name(ExprName { id, .. }) => {
499 return Some(Self::from_slice(&[
500 id.as_str(),
501 attr2.attr.as_str(),
502 attr1.attr.as_str(),
503 ]));
504 }
505 _ => return None,
506 };
507
508 let attr4 = match attr3.value.as_ref() {
509 Expr::Attribute(attr4) => attr4,
510 Expr::Name(ExprName { id, .. }) => {
512 return Some(Self::from_slice(&[
513 id.as_str(),
514 attr3.attr.as_str(),
515 attr2.attr.as_str(),
516 attr1.attr.as_str(),
517 ]));
518 }
519 _ => return None,
520 };
521
522 let attr5 = match attr4.value.as_ref() {
523 Expr::Attribute(attr5) => attr5,
524 Expr::Name(ExprName { id, .. }) => {
526 return Some(Self::from_slice(&[
527 id.as_str(),
528 attr4.attr.as_str(),
529 attr3.attr.as_str(),
530 attr2.attr.as_str(),
531 attr1.attr.as_str(),
532 ]));
533 }
534 _ => return None,
535 };
536
537 let attr6 = match attr5.value.as_ref() {
538 Expr::Attribute(attr6) => attr6,
539 Expr::Name(ExprName { id, .. }) => {
541 return Some(Self::from_slice(&[
542 id.as_str(),
543 attr5.attr.as_str(),
544 attr4.attr.as_str(),
545 attr3.attr.as_str(),
546 attr2.attr.as_str(),
547 attr1.attr.as_str(),
548 ]));
549 }
550 _ => return None,
551 };
552
553 let attr7 = match attr6.value.as_ref() {
554 Expr::Attribute(attr7) => attr7,
555 Expr::Name(ExprName { id, .. }) => {
557 return Some(Self::from_slice(&[
558 id.as_str(),
559 attr6.attr.as_str(),
560 attr5.attr.as_str(),
561 attr4.attr.as_str(),
562 attr3.attr.as_str(),
563 attr2.attr.as_str(),
564 attr1.attr.as_str(),
565 ]));
566 }
567 _ => return None,
568 };
569
570 let attr8 = match attr7.value.as_ref() {
571 Expr::Attribute(attr8) => attr8,
572 Expr::Name(ExprName { id, .. }) => {
574 return Some(Self(SegmentsVec::from([
575 id.as_str(),
576 attr7.attr.as_str(),
577 attr6.attr.as_str(),
578 attr5.attr.as_str(),
579 attr4.attr.as_str(),
580 attr3.attr.as_str(),
581 attr2.attr.as_str(),
582 attr1.attr.as_str(),
583 ])));
584 }
585 _ => return None,
586 };
587
588 let mut segments = Vec::with_capacity(SMALL_LEN * 2);
589
590 let mut current = &*attr8.value;
591
592 loop {
593 current = match current {
594 Expr::Attribute(attr) => {
595 segments.push(attr.attr.as_str());
596 &*attr.value
597 }
598 Expr::Name(ExprName { id, .. }) => {
599 segments.push(id.as_str());
600 break;
601 }
602 _ => {
603 return None;
604 }
605 }
606 }
607
608 segments.reverse();
609
610 segments.extend_from_slice(&[
612 attr8.attr.as_str(),
613 attr7.attr.as_str(),
614 attr6.attr.as_str(),
615 attr5.attr.as_str(),
616 attr4.attr.as_str(),
617 attr3.attr.as_str(),
618 attr2.attr.as_str(),
619 attr1.attr.as_str(),
620 ]);
621
622 Some(Self(SegmentsVec::from(segments)))
623 }
624
625 #[inline]
626 fn from_slice(segments: &[&'a str]) -> Self {
627 Self(SegmentsVec::from_slice(segments))
628 }
629
630 pub fn segments(&self) -> &[&'a str] {
631 self.0.as_slice()
632 }
633}
634
635impl Display for UnqualifiedName<'_> {
636 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
637 let mut first = true;
638 for segment in self.segments() {
639 if !first {
640 f.write_char('.')?;
641 }
642
643 f.write_str(segment)?;
644 first = false;
645 }
646
647 Ok(())
648 }
649}
650
651impl<'a> FromIterator<&'a str> for UnqualifiedName<'a> {
652 #[inline]
653 fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
654 Self(iter.into_iter().collect())
655 }
656}
657
658#[derive(Clone)]
667enum SegmentsVec<'a> {
668 Stack(SegmentsStack<'a>),
669 Heap(Vec<&'a str>),
670}
671
672impl<'a> SegmentsVec<'a> {
673 fn new() -> Self {
675 Self::Stack(SegmentsStack::default())
676 }
677
678 fn with_capacity(capacity: usize) -> Self {
680 if capacity <= SMALL_LEN {
681 Self::new()
682 } else {
683 Self::Heap(Vec::with_capacity(capacity))
684 }
685 }
686
687 #[cfg(test)]
688 const fn is_spilled(&self) -> bool {
689 matches!(self, SegmentsVec::Heap(_))
690 }
691
692 #[inline]
694 fn from_slice(slice: &[&'a str]) -> Self {
695 match SegmentsStack::try_from(slice) {
696 Ok(stack) => SegmentsVec::Stack(stack),
697 Err(_) => SegmentsVec::Heap(slice.to_vec()),
698 }
699 }
700
701 #[inline]
703 fn as_slice(&self) -> &[&'a str] {
704 match self {
705 Self::Stack(stack) => stack.as_slice(),
706 Self::Heap(heap) => heap.as_slice(),
707 }
708 }
709
710 #[inline]
714 fn push(&mut self, name: &'a str) {
715 match self {
716 SegmentsVec::Stack(stack) => {
717 if let Err(error) = stack.try_push(name) {
718 let mut segments = Vec::with_capacity(stack.len() * 2);
719 segments.extend(stack.iter().copied());
720 segments.push(error.element());
721 *self = SegmentsVec::Heap(segments);
722 }
723 }
724 SegmentsVec::Heap(heap) => {
725 heap.push(name);
726 }
727 }
728 }
729
730 #[inline]
734 fn pop(&mut self) -> Option<&'a str> {
735 match self {
736 SegmentsVec::Stack(stack) => stack.pop(),
737 SegmentsVec::Heap(heap) => heap.pop(),
738 }
739 }
740
741 #[inline]
742 fn extend_from_slice(&mut self, slice: &[&'a str]) {
743 match self {
744 SegmentsVec::Stack(stack) => {
745 if stack.try_extend_from_slice(slice).is_err() {
746 let mut segments = Vec::with_capacity(stack.len() + slice.len());
747 segments.extend(stack.iter().copied());
748 segments.extend_from_slice(slice);
749 *self = SegmentsVec::Heap(segments);
750 }
751 }
752 SegmentsVec::Heap(heap) => heap.extend_from_slice(slice),
753 }
754 }
755}
756
757impl Default for SegmentsVec<'_> {
758 fn default() -> Self {
759 Self::new()
760 }
761}
762
763impl Debug for SegmentsVec<'_> {
764 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
765 f.debug_list().entries(self.as_slice()).finish()
766 }
767}
768
769impl<'a> Deref for SegmentsVec<'a> {
770 type Target = [&'a str];
771 fn deref(&self) -> &Self::Target {
772 self.as_slice()
773 }
774}
775
776impl<'b> PartialEq<SegmentsVec<'b>> for SegmentsVec<'_> {
777 fn eq(&self, other: &SegmentsVec<'b>) -> bool {
778 self.as_slice() == other.as_slice()
779 }
780}
781
782impl Eq for SegmentsVec<'_> {}
783
784impl Hash for SegmentsVec<'_> {
785 fn hash<H: Hasher>(&self, state: &mut H) {
786 self.as_slice().hash(state);
787 }
788}
789
790impl<'a> FromIterator<&'a str> for SegmentsVec<'a> {
791 #[inline]
792 fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
793 let mut segments = SegmentsVec::default();
794 segments.extend(iter);
795 segments
796 }
797}
798
799impl<'a> From<[&'a str; 8]> for SegmentsVec<'a> {
800 #[inline]
801 fn from(segments: [&'a str; 8]) -> Self {
802 SegmentsVec::Stack(SegmentsStack::from(segments))
803 }
804}
805
806impl<'a> From<Vec<&'a str>> for SegmentsVec<'a> {
807 #[inline]
808 fn from(segments: Vec<&'a str>) -> Self {
809 SegmentsVec::Heap(segments)
810 }
811}
812
813impl<'a> Extend<&'a str> for SegmentsVec<'a> {
814 #[inline]
815 fn extend<T: IntoIterator<Item = &'a str>>(&mut self, iter: T) {
816 match self {
817 SegmentsVec::Stack(stack) => {
818 let mut iter = iter.into_iter();
819 let (lower, _) = iter.size_hint();
820
821 if lower > stack.remaining_capacity() {
822 let mut segments = Vec::with_capacity(stack.len() + lower);
823 segments.extend(stack.iter().copied());
824 segments.extend(iter);
825 *self = SegmentsVec::Heap(segments);
826 return;
827 }
828
829 while let Some(name) = iter.next() {
830 if let Err(error) = stack.try_push(name) {
831 let mut segments = Vec::with_capacity(stack.len() * 2);
832 segments.extend(stack.iter().copied());
833 segments.push(error.element());
834 segments.extend(iter);
835 *self = SegmentsVec::Heap(segments);
836 return;
837 }
838 }
839 }
840 SegmentsVec::Heap(heap) => {
841 heap.extend(iter);
842 }
843 }
844 }
845}
846
847const SMALL_LEN: usize = 8;
848type SegmentsStack<'a> = ArrayVec<&'a str, SMALL_LEN>;
849
850#[cfg(test)]
851mod tests {
852 #[cfg(feature = "salsa")]
853 use std::hash::{DefaultHasher, Hash, Hasher};
854
855 #[cfg(feature = "salsa")]
856 use crate::name::Name;
857 use crate::name::SegmentsVec;
858
859 #[cfg(feature = "salsa")]
860 #[test]
861 fn salsa_lookup_name_from_str() {
862 let name = Name::new("member");
863 let lookup = "member";
864
865 let mut name_hasher = DefaultHasher::new();
866 name.hash(&mut name_hasher);
867 let mut lookup_hasher = DefaultHasher::new();
868 lookup.hash(&mut lookup_hasher);
869
870 assert_eq!(name_hasher.finish(), lookup_hasher.finish());
871 assert!(salsa::HashEqLike::<&str>::eq(&name, &lookup));
872 assert_eq!(salsa::Lookup::<Name>::into_owned(lookup), name);
873 }
874
875 #[test]
876 fn empty_vec() {
877 let empty = SegmentsVec::new();
878 assert_eq!(empty.as_slice(), &[] as &[&str]);
879 assert!(!empty.is_spilled());
880 }
881
882 #[test]
883 fn from_slice_stack() {
884 let stack = SegmentsVec::from_slice(&["a", "b", "c"]);
885
886 assert_eq!(stack.as_slice(), &["a", "b", "c"]);
887 assert!(!stack.is_spilled());
888 }
889
890 #[test]
891 fn from_slice_stack_capacity() {
892 let stack = SegmentsVec::from_slice(&["a", "b", "c", "d", "e", "f", "g", "h"]);
893
894 assert_eq!(stack.as_slice(), &["a", "b", "c", "d", "e", "f", "g", "h"]);
895 assert!(!stack.is_spilled());
896 }
897
898 #[test]
899 fn from_slice_heap() {
900 let heap = SegmentsVec::from_slice(&["a", "b", "c", "d", "e", "f", "g", "h", "i"]);
901
902 assert_eq!(
903 heap.as_slice(),
904 &["a", "b", "c", "d", "e", "f", "g", "h", "i"]
905 );
906 assert!(heap.is_spilled());
907 }
908
909 #[test]
910 fn push_stack() {
911 let mut stack = SegmentsVec::from_slice(&["a", "b", "c"]);
912 stack.push("d");
913 stack.push("e");
914
915 assert_eq!(stack.as_slice(), &["a", "b", "c", "d", "e"]);
916 assert!(!stack.is_spilled());
917 }
918
919 #[test]
920 fn push_stack_spill() {
921 let mut stack = SegmentsVec::from_slice(&["a", "b", "c", "d", "e", "f", "g"]);
922 stack.push("h");
923
924 assert!(!stack.is_spilled());
925
926 stack.push("i");
927
928 assert_eq!(
929 stack.as_slice(),
930 &["a", "b", "c", "d", "e", "f", "g", "h", "i"]
931 );
932 assert!(stack.is_spilled());
933 }
934
935 #[test]
936 fn pop_stack() {
937 let mut stack = SegmentsVec::from_slice(&["a", "b", "c", "d", "e"]);
938 assert_eq!(stack.pop(), Some("e"));
939 assert_eq!(stack.pop(), Some("d"));
940 assert_eq!(stack.pop(), Some("c"));
941 assert_eq!(stack.pop(), Some("b"));
942 assert_eq!(stack.pop(), Some("a"));
943 assert_eq!(stack.pop(), None);
944
945 assert!(!stack.is_spilled());
946 }
947
948 #[test]
949 fn pop_heap() {
950 let mut heap = SegmentsVec::from_slice(&["a", "b", "c", "d", "e", "f", "g", "h", "i"]);
951
952 assert_eq!(heap.pop(), Some("i"));
953 assert_eq!(heap.pop(), Some("h"));
954 assert_eq!(heap.pop(), Some("g"));
955
956 assert!(heap.is_spilled());
957 }
958
959 #[test]
960 fn extend_from_slice_stack() {
961 let mut stack = SegmentsVec::from_slice(&["a", "b", "c"]);
962 stack.extend_from_slice(&["d", "e", "f"]);
963
964 assert_eq!(stack.as_slice(), &["a", "b", "c", "d", "e", "f"]);
965 assert!(!stack.is_spilled());
966 }
967
968 #[test]
969 fn extend_from_slice_stack_spill() {
970 let mut spilled = SegmentsVec::from_slice(&["a", "b", "c", "d", "e", "f"]);
971 spilled.extend_from_slice(&["g", "h", "i", "j"]);
972
973 assert_eq!(
974 spilled.as_slice(),
975 &["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"]
976 );
977 assert!(spilled.is_spilled());
978 }
979
980 #[test]
981 fn extend_from_slice_heap() {
982 let mut heap = SegmentsVec::from_slice(&["a", "b", "c", "d", "e", "f", "g", "h", "i"]);
983 assert!(heap.is_spilled());
984
985 heap.extend_from_slice(&["j", "k", "l"]);
986
987 assert_eq!(
988 heap.as_slice(),
989 &["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"]
990 );
991 }
992
993 #[test]
994 fn extend_stack() {
995 let mut stack = SegmentsVec::from_slice(&["a", "b", "c"]);
996 stack.extend(["d", "e", "f"]);
997
998 assert_eq!(stack.as_slice(), &["a", "b", "c", "d", "e", "f"]);
999 assert!(!stack.is_spilled());
1000 }
1001
1002 #[test]
1003 fn extend_stack_spilled() {
1004 let mut stack = SegmentsVec::from_slice(&["a", "b", "c", "d", "e", "f"]);
1005 stack.extend(["g", "h", "i", "j"]);
1006
1007 assert_eq!(
1008 stack.as_slice(),
1009 &["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"]
1010 );
1011 assert!(stack.is_spilled());
1012 }
1013
1014 #[test]
1015 fn extend_heap() {
1016 let mut heap = SegmentsVec::from_slice(&["a", "b", "c", "d", "e", "f", "g", "h", "i"]);
1017 assert!(heap.is_spilled());
1018
1019 heap.extend(["j", "k", "l"]);
1020
1021 assert_eq!(
1022 heap.as_slice(),
1023 &["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"]
1024 );
1025 }
1026}