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 hash<H: Hasher>(&self, state: &mut H) {
177 self.as_str().hash(state);
178 }
179
180 #[inline]
181 fn eq(&self, data: &&str) -> bool {
182 self.as_str() == *data
183 }
184}
185
186impl From<Name> for String {
187 #[inline]
188 fn from(name: Name) -> Self {
189 name.0.into()
190 }
191}
192
193impl From<Name> for CharStr {
194 #[inline]
195 fn from(name: Name) -> Self {
196 name.0
197 }
198}
199
200#[cfg(feature = "salsa")]
201impl salsa::Lookup<compact_str::CompactString> for Name {
202 #[inline]
203 fn into_owned(self) -> compact_str::CompactString {
204 compact_str::CompactString::new(self.as_str())
205 }
206}
207
208#[cfg(feature = "salsa")]
209impl salsa::Lookup<compact_str::CompactString> for &Name {
210 #[inline]
211 fn into_owned(self) -> compact_str::CompactString {
212 compact_str::CompactString::new(self.as_str())
213 }
214}
215
216#[cfg(feature = "salsa")]
217impl salsa::HashEqLike<Name> for compact_str::CompactString {
218 #[inline]
219 fn hash<H: Hasher>(&self, state: &mut H) {
220 Hash::hash(self, state);
221 }
222
223 #[inline]
224 fn eq(&self, data: &Name) -> bool {
225 self.as_str() == data.as_str()
226 }
227}
228
229#[cfg(feature = "salsa")]
230impl salsa::HashEqLike<&Name> for compact_str::CompactString {
231 #[inline]
232 fn hash<H: Hasher>(&self, state: &mut H) {
233 Hash::hash(self, state);
234 }
235
236 #[inline]
237 fn eq(&self, data: &&Name) -> bool {
238 self.as_str() == data.as_str()
239 }
240}
241
242impl From<CharString> for Name {
243 #[inline]
244 fn from(name: CharString) -> Self {
245 Self(name.freeze())
246 }
247}
248
249impl FromIterator<char> for Name {
250 fn from_iter<I: IntoIterator<Item = char>>(iter: I) -> Self {
251 Self(iter.into_iter().collect())
252 }
253}
254
255impl std::fmt::Display for Name {
256 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
257 f.write_str(self.as_str())
258 }
259}
260
261impl PartialEq<str> for Name {
262 #[inline]
263 fn eq(&self, other: &str) -> bool {
264 self.as_str() == other
265 }
266}
267
268impl PartialEq<Name> for str {
269 #[inline]
270 fn eq(&self, other: &Name) -> bool {
271 other == self
272 }
273}
274
275impl PartialEq<&str> for Name {
276 #[inline]
277 fn eq(&self, other: &&str) -> bool {
278 self.as_str() == *other
279 }
280}
281
282impl PartialEq<Name> for &str {
283 #[inline]
284 fn eq(&self, other: &Name) -> bool {
285 other == self
286 }
287}
288
289impl PartialEq<String> for Name {
290 fn eq(&self, other: &String) -> bool {
291 self == other.as_str()
292 }
293}
294
295impl PartialEq<Name> for String {
296 #[inline]
297 fn eq(&self, other: &Name) -> bool {
298 other == self
299 }
300}
301
302impl PartialEq<&String> for Name {
303 #[inline]
304 fn eq(&self, other: &&String) -> bool {
305 self.as_str() == *other
306 }
307}
308
309impl PartialEq<Name> for &String {
310 #[inline]
311 fn eq(&self, other: &Name) -> bool {
312 other == self
313 }
314}
315
316#[derive(Debug, Clone, PartialEq, Eq, Hash)]
318pub struct QualifiedName<'a>(SegmentsVec<'a>);
319
320impl<'a> QualifiedName<'a> {
321 #[inline]
330 pub fn from_dotted_name(name: &'a str) -> Self {
331 if let Some(dot) = name.find('.') {
332 let mut builder = QualifiedNameBuilder::default();
333 builder.push(&name[..dot]);
334 builder.extend(name[dot + 1..].split('.'));
335 builder.build()
336 } else {
337 Self::builtin(name)
338 }
339 }
340
341 #[inline]
343 pub fn user_defined(name: &'a str) -> Self {
344 name.split('.').collect()
345 }
346
347 #[inline]
349 pub fn builtin(name: &'a str) -> Self {
350 debug_assert!(!name.contains('.'));
351 Self(SegmentsVec::from_slice(&["", name]))
352 }
353
354 #[inline]
355 pub fn segments(&self) -> &[&'a str] {
356 self.0.as_slice()
357 }
358
359 fn is_builtin(&self) -> bool {
368 matches!(self.segments(), ["", ..])
369 }
370
371 pub fn is_unresolved_import(&self) -> bool {
374 matches!(self.segments(), [".", ..])
375 }
376
377 pub fn starts_with(&self, other: &QualifiedName<'_>) -> bool {
378 self.segments().starts_with(other.segments())
379 }
380
381 #[must_use]
383 pub fn append_member(self, member: &'a str) -> Self {
384 let mut inner = self.0;
385 inner.push(member);
386 Self(inner)
387 }
388
389 #[must_use]
391 pub fn extend_members<T: IntoIterator<Item = &'a str>>(self, members: T) -> Self {
392 let mut inner = self.0;
393 inner.extend(members);
394 Self(inner)
395 }
396}
397
398impl Display for QualifiedName<'_> {
399 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
400 let segments = self.segments();
401
402 if self.is_unresolved_import() {
403 let mut iter = segments.iter();
404 for segment in iter.by_ref() {
405 if *segment == "." {
406 f.write_char('.')?;
407 } else {
408 f.write_str(segment)?;
409 break;
410 }
411 }
412 for segment in iter {
413 f.write_char('.')?;
414 f.write_str(segment)?;
415 }
416 } else {
417 let segments = if self.is_builtin() {
418 &segments[1..]
419 } else {
420 segments
421 };
422
423 let mut first = true;
424 for segment in segments {
425 if !first {
426 f.write_char('.')?;
427 }
428
429 f.write_str(segment)?;
430 first = false;
431 }
432 }
433
434 Ok(())
435 }
436}
437
438impl<'a> FromIterator<&'a str> for QualifiedName<'a> {
439 fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
440 Self(SegmentsVec::from_iter(iter))
441 }
442}
443
444#[derive(Debug, Clone, Default)]
445pub struct QualifiedNameBuilder<'a> {
446 segments: SegmentsVec<'a>,
447}
448
449impl<'a> QualifiedNameBuilder<'a> {
450 pub fn with_capacity(capacity: usize) -> Self {
451 Self {
452 segments: SegmentsVec::with_capacity(capacity),
453 }
454 }
455
456 #[inline]
457 pub(crate) fn is_empty(&self) -> bool {
458 self.segments.is_empty()
459 }
460
461 #[inline]
462 pub fn push(&mut self, segment: &'a str) {
463 self.segments.push(segment);
464 }
465
466 #[inline]
467 pub(crate) fn pop(&mut self) {
468 self.segments.pop();
469 }
470
471 #[inline]
472 pub fn extend(&mut self, segments: impl IntoIterator<Item = &'a str>) {
473 self.segments.extend(segments);
474 }
475
476 #[inline]
477 pub(crate) fn extend_from_slice(&mut self, segments: &[&'a str]) {
478 self.segments.extend_from_slice(segments);
479 }
480
481 pub fn build(self) -> QualifiedName<'a> {
482 QualifiedName(self.segments)
483 }
484}
485
486#[derive(Debug, Clone, PartialEq, Eq, Hash)]
487pub struct UnqualifiedName<'a>(SegmentsVec<'a>);
488
489impl<'a> UnqualifiedName<'a> {
490 pub fn from_expr(expr: &'a Expr) -> Option<Self> {
492 let attr1 = match expr {
495 Expr::Attribute(attr1) => attr1,
496 Expr::Name(ExprName { id, .. }) => return Some(Self::from_slice(&[id.as_str()])),
498 _ => return None,
499 };
500
501 let attr2 = match attr1.value.as_ref() {
502 Expr::Attribute(attr2) => attr2,
503 Expr::Name(ExprName { id, .. }) => {
505 return Some(Self::from_slice(&[id.as_str(), attr1.attr.as_str()]));
506 }
507 _ => return None,
508 };
509
510 let attr3 = match attr2.value.as_ref() {
511 Expr::Attribute(attr3) => attr3,
512 Expr::Name(ExprName { id, .. }) => {
514 return Some(Self::from_slice(&[
515 id.as_str(),
516 attr2.attr.as_str(),
517 attr1.attr.as_str(),
518 ]));
519 }
520 _ => return None,
521 };
522
523 let attr4 = match attr3.value.as_ref() {
524 Expr::Attribute(attr4) => attr4,
525 Expr::Name(ExprName { id, .. }) => {
527 return Some(Self::from_slice(&[
528 id.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 attr5 = match attr4.value.as_ref() {
538 Expr::Attribute(attr5) => attr5,
539 Expr::Name(ExprName { id, .. }) => {
541 return Some(Self::from_slice(&[
542 id.as_str(),
543 attr4.attr.as_str(),
544 attr3.attr.as_str(),
545 attr2.attr.as_str(),
546 attr1.attr.as_str(),
547 ]));
548 }
549 _ => return None,
550 };
551
552 let attr6 = match attr5.value.as_ref() {
553 Expr::Attribute(attr6) => attr6,
554 Expr::Name(ExprName { id, .. }) => {
556 return Some(Self::from_slice(&[
557 id.as_str(),
558 attr5.attr.as_str(),
559 attr4.attr.as_str(),
560 attr3.attr.as_str(),
561 attr2.attr.as_str(),
562 attr1.attr.as_str(),
563 ]));
564 }
565 _ => return None,
566 };
567
568 let attr7 = match attr6.value.as_ref() {
569 Expr::Attribute(attr7) => attr7,
570 Expr::Name(ExprName { id, .. }) => {
572 return Some(Self::from_slice(&[
573 id.as_str(),
574 attr6.attr.as_str(),
575 attr5.attr.as_str(),
576 attr4.attr.as_str(),
577 attr3.attr.as_str(),
578 attr2.attr.as_str(),
579 attr1.attr.as_str(),
580 ]));
581 }
582 _ => return None,
583 };
584
585 let attr8 = match attr7.value.as_ref() {
586 Expr::Attribute(attr8) => attr8,
587 Expr::Name(ExprName { id, .. }) => {
589 return Some(Self(SegmentsVec::from([
590 id.as_str(),
591 attr7.attr.as_str(),
592 attr6.attr.as_str(),
593 attr5.attr.as_str(),
594 attr4.attr.as_str(),
595 attr3.attr.as_str(),
596 attr2.attr.as_str(),
597 attr1.attr.as_str(),
598 ])));
599 }
600 _ => return None,
601 };
602
603 let mut segments = Vec::with_capacity(SMALL_LEN * 2);
604
605 let mut current = &*attr8.value;
606
607 loop {
608 current = match current {
609 Expr::Attribute(attr) => {
610 segments.push(attr.attr.as_str());
611 &*attr.value
612 }
613 Expr::Name(ExprName { id, .. }) => {
614 segments.push(id.as_str());
615 break;
616 }
617 _ => {
618 return None;
619 }
620 }
621 }
622
623 segments.reverse();
624
625 segments.extend_from_slice(&[
627 attr8.attr.as_str(),
628 attr7.attr.as_str(),
629 attr6.attr.as_str(),
630 attr5.attr.as_str(),
631 attr4.attr.as_str(),
632 attr3.attr.as_str(),
633 attr2.attr.as_str(),
634 attr1.attr.as_str(),
635 ]);
636
637 Some(Self(SegmentsVec::from(segments)))
638 }
639
640 #[inline]
641 fn from_slice(segments: &[&'a str]) -> Self {
642 Self(SegmentsVec::from_slice(segments))
643 }
644
645 pub fn segments(&self) -> &[&'a str] {
646 self.0.as_slice()
647 }
648}
649
650impl Display for UnqualifiedName<'_> {
651 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
652 let mut first = true;
653 for segment in self.segments() {
654 if !first {
655 f.write_char('.')?;
656 }
657
658 f.write_str(segment)?;
659 first = false;
660 }
661
662 Ok(())
663 }
664}
665
666impl<'a> FromIterator<&'a str> for UnqualifiedName<'a> {
667 #[inline]
668 fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
669 Self(iter.into_iter().collect())
670 }
671}
672
673#[derive(Clone)]
682enum SegmentsVec<'a> {
683 Stack(SegmentsStack<'a>),
684 Heap(Vec<&'a str>),
685}
686
687impl<'a> SegmentsVec<'a> {
688 fn new() -> Self {
690 Self::Stack(SegmentsStack::default())
691 }
692
693 fn with_capacity(capacity: usize) -> Self {
695 if capacity <= SMALL_LEN {
696 Self::new()
697 } else {
698 Self::Heap(Vec::with_capacity(capacity))
699 }
700 }
701
702 #[cfg(test)]
703 const fn is_spilled(&self) -> bool {
704 matches!(self, SegmentsVec::Heap(_))
705 }
706
707 #[inline]
709 fn from_slice(slice: &[&'a str]) -> Self {
710 match SegmentsStack::try_from(slice) {
711 Ok(stack) => SegmentsVec::Stack(stack),
712 Err(_) => SegmentsVec::Heap(slice.to_vec()),
713 }
714 }
715
716 #[inline]
718 fn as_slice(&self) -> &[&'a str] {
719 match self {
720 Self::Stack(stack) => stack.as_slice(),
721 Self::Heap(heap) => heap.as_slice(),
722 }
723 }
724
725 #[inline]
729 fn push(&mut self, name: &'a str) {
730 match self {
731 SegmentsVec::Stack(stack) => {
732 if let Err(error) = stack.try_push(name) {
733 let mut segments = Vec::with_capacity(stack.len() * 2);
734 segments.extend(stack.iter().copied());
735 segments.push(error.element());
736 *self = SegmentsVec::Heap(segments);
737 }
738 }
739 SegmentsVec::Heap(heap) => {
740 heap.push(name);
741 }
742 }
743 }
744
745 #[inline]
749 fn pop(&mut self) -> Option<&'a str> {
750 match self {
751 SegmentsVec::Stack(stack) => stack.pop(),
752 SegmentsVec::Heap(heap) => heap.pop(),
753 }
754 }
755
756 #[inline]
757 fn extend_from_slice(&mut self, slice: &[&'a str]) {
758 match self {
759 SegmentsVec::Stack(stack) => {
760 if stack.try_extend_from_slice(slice).is_err() {
761 let mut segments = Vec::with_capacity(stack.len() + slice.len());
762 segments.extend(stack.iter().copied());
763 segments.extend_from_slice(slice);
764 *self = SegmentsVec::Heap(segments);
765 }
766 }
767 SegmentsVec::Heap(heap) => heap.extend_from_slice(slice),
768 }
769 }
770}
771
772impl Default for SegmentsVec<'_> {
773 fn default() -> Self {
774 Self::new()
775 }
776}
777
778impl Debug for SegmentsVec<'_> {
779 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
780 f.debug_list().entries(self.as_slice()).finish()
781 }
782}
783
784impl<'a> Deref for SegmentsVec<'a> {
785 type Target = [&'a str];
786 fn deref(&self) -> &Self::Target {
787 self.as_slice()
788 }
789}
790
791impl<'b> PartialEq<SegmentsVec<'b>> for SegmentsVec<'_> {
792 fn eq(&self, other: &SegmentsVec<'b>) -> bool {
793 self.as_slice() == other.as_slice()
794 }
795}
796
797impl Eq for SegmentsVec<'_> {}
798
799impl Hash for SegmentsVec<'_> {
800 fn hash<H: Hasher>(&self, state: &mut H) {
801 self.as_slice().hash(state);
802 }
803}
804
805impl<'a> FromIterator<&'a str> for SegmentsVec<'a> {
806 #[inline]
807 fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
808 let mut segments = SegmentsVec::default();
809 segments.extend(iter);
810 segments
811 }
812}
813
814impl<'a> From<[&'a str; 8]> for SegmentsVec<'a> {
815 #[inline]
816 fn from(segments: [&'a str; 8]) -> Self {
817 SegmentsVec::Stack(SegmentsStack::from(segments))
818 }
819}
820
821impl<'a> From<Vec<&'a str>> for SegmentsVec<'a> {
822 #[inline]
823 fn from(segments: Vec<&'a str>) -> Self {
824 SegmentsVec::Heap(segments)
825 }
826}
827
828impl<'a> Extend<&'a str> for SegmentsVec<'a> {
829 #[inline]
830 fn extend<T: IntoIterator<Item = &'a str>>(&mut self, iter: T) {
831 match self {
832 SegmentsVec::Stack(stack) => {
833 let mut iter = iter.into_iter();
834 let (lower, _) = iter.size_hint();
835
836 if lower > stack.remaining_capacity() {
837 let mut segments = Vec::with_capacity(stack.len() + lower);
838 segments.extend(stack.iter().copied());
839 segments.extend(iter);
840 *self = SegmentsVec::Heap(segments);
841 return;
842 }
843
844 while let Some(name) = iter.next() {
845 if let Err(error) = stack.try_push(name) {
846 let mut segments = Vec::with_capacity(stack.len() * 2);
847 segments.extend(stack.iter().copied());
848 segments.push(error.element());
849 segments.extend(iter);
850 *self = SegmentsVec::Heap(segments);
851 return;
852 }
853 }
854 }
855 SegmentsVec::Heap(heap) => {
856 heap.extend(iter);
857 }
858 }
859 }
860}
861
862const SMALL_LEN: usize = 8;
863type SegmentsStack<'a> = ArrayVec<&'a str, SMALL_LEN>;
864
865#[cfg(test)]
866mod tests {
867 #[cfg(feature = "salsa")]
868 use std::hash::{DefaultHasher, Hash, Hasher};
869
870 #[cfg(feature = "salsa")]
871 use crate::name::Name;
872 use crate::name::SegmentsVec;
873
874 #[cfg(feature = "salsa")]
875 #[test]
876 fn salsa_lookup_name_from_str() {
877 let name = Name::new("member");
878 let lookup = "member";
879
880 let mut name_hasher = DefaultHasher::new();
881 salsa::HashEqLike::<&str>::hash(&name, &mut name_hasher);
882 let mut lookup_hasher = DefaultHasher::new();
883 lookup.hash(&mut lookup_hasher);
884
885 assert_eq!(name_hasher.finish(), lookup_hasher.finish());
886 assert!(salsa::HashEqLike::<&str>::eq(&name, &lookup));
887 assert_eq!(salsa::Lookup::<Name>::into_owned(lookup), name);
888 }
889
890 #[test]
891 fn empty_vec() {
892 let empty = SegmentsVec::new();
893 assert_eq!(empty.as_slice(), &[] as &[&str]);
894 assert!(!empty.is_spilled());
895 }
896
897 #[test]
898 fn from_slice_stack() {
899 let stack = SegmentsVec::from_slice(&["a", "b", "c"]);
900
901 assert_eq!(stack.as_slice(), &["a", "b", "c"]);
902 assert!(!stack.is_spilled());
903 }
904
905 #[test]
906 fn from_slice_stack_capacity() {
907 let stack = SegmentsVec::from_slice(&["a", "b", "c", "d", "e", "f", "g", "h"]);
908
909 assert_eq!(stack.as_slice(), &["a", "b", "c", "d", "e", "f", "g", "h"]);
910 assert!(!stack.is_spilled());
911 }
912
913 #[test]
914 fn from_slice_heap() {
915 let heap = SegmentsVec::from_slice(&["a", "b", "c", "d", "e", "f", "g", "h", "i"]);
916
917 assert_eq!(
918 heap.as_slice(),
919 &["a", "b", "c", "d", "e", "f", "g", "h", "i"]
920 );
921 assert!(heap.is_spilled());
922 }
923
924 #[test]
925 fn push_stack() {
926 let mut stack = SegmentsVec::from_slice(&["a", "b", "c"]);
927 stack.push("d");
928 stack.push("e");
929
930 assert_eq!(stack.as_slice(), &["a", "b", "c", "d", "e"]);
931 assert!(!stack.is_spilled());
932 }
933
934 #[test]
935 fn push_stack_spill() {
936 let mut stack = SegmentsVec::from_slice(&["a", "b", "c", "d", "e", "f", "g"]);
937 stack.push("h");
938
939 assert!(!stack.is_spilled());
940
941 stack.push("i");
942
943 assert_eq!(
944 stack.as_slice(),
945 &["a", "b", "c", "d", "e", "f", "g", "h", "i"]
946 );
947 assert!(stack.is_spilled());
948 }
949
950 #[test]
951 fn pop_stack() {
952 let mut stack = SegmentsVec::from_slice(&["a", "b", "c", "d", "e"]);
953 assert_eq!(stack.pop(), Some("e"));
954 assert_eq!(stack.pop(), Some("d"));
955 assert_eq!(stack.pop(), Some("c"));
956 assert_eq!(stack.pop(), Some("b"));
957 assert_eq!(stack.pop(), Some("a"));
958 assert_eq!(stack.pop(), None);
959
960 assert!(!stack.is_spilled());
961 }
962
963 #[test]
964 fn pop_heap() {
965 let mut heap = SegmentsVec::from_slice(&["a", "b", "c", "d", "e", "f", "g", "h", "i"]);
966
967 assert_eq!(heap.pop(), Some("i"));
968 assert_eq!(heap.pop(), Some("h"));
969 assert_eq!(heap.pop(), Some("g"));
970
971 assert!(heap.is_spilled());
972 }
973
974 #[test]
975 fn extend_from_slice_stack() {
976 let mut stack = SegmentsVec::from_slice(&["a", "b", "c"]);
977 stack.extend_from_slice(&["d", "e", "f"]);
978
979 assert_eq!(stack.as_slice(), &["a", "b", "c", "d", "e", "f"]);
980 assert!(!stack.is_spilled());
981 }
982
983 #[test]
984 fn extend_from_slice_stack_spill() {
985 let mut spilled = SegmentsVec::from_slice(&["a", "b", "c", "d", "e", "f"]);
986 spilled.extend_from_slice(&["g", "h", "i", "j"]);
987
988 assert_eq!(
989 spilled.as_slice(),
990 &["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"]
991 );
992 assert!(spilled.is_spilled());
993 }
994
995 #[test]
996 fn extend_from_slice_heap() {
997 let mut heap = SegmentsVec::from_slice(&["a", "b", "c", "d", "e", "f", "g", "h", "i"]);
998 assert!(heap.is_spilled());
999
1000 heap.extend_from_slice(&["j", "k", "l"]);
1001
1002 assert_eq!(
1003 heap.as_slice(),
1004 &["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"]
1005 );
1006 }
1007
1008 #[test]
1009 fn extend_stack() {
1010 let mut stack = SegmentsVec::from_slice(&["a", "b", "c"]);
1011 stack.extend(["d", "e", "f"]);
1012
1013 assert_eq!(stack.as_slice(), &["a", "b", "c", "d", "e", "f"]);
1014 assert!(!stack.is_spilled());
1015 }
1016
1017 #[test]
1018 fn extend_stack_spilled() {
1019 let mut stack = SegmentsVec::from_slice(&["a", "b", "c", "d", "e", "f"]);
1020 stack.extend(["g", "h", "i", "j"]);
1021
1022 assert_eq!(
1023 stack.as_slice(),
1024 &["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"]
1025 );
1026 assert!(stack.is_spilled());
1027 }
1028
1029 #[test]
1030 fn extend_heap() {
1031 let mut heap = SegmentsVec::from_slice(&["a", "b", "c", "d", "e", "f", "g", "h", "i"]);
1032 assert!(heap.is_spilled());
1033
1034 heap.extend(["j", "k", "l"]);
1035
1036 assert_eq!(
1037 heap.as_slice(),
1038 &["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"]
1039 );
1040 }
1041}