1use super::{
5 IterStatus, PositionIterInternal, PyDict, PyDictRef, PyGenericAlias, PyTupleRef, PyType,
6 PyTypeRef, builtins_iter,
7};
8use crate::common::lock::LazyLock;
9use crate::{
10 AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject,
11 atomic_func,
12 class::PyClassImpl,
13 common::{ascii, hash::PyHash, lock::PyMutex, rc::PyRc, wtf8::Wtf8Buf},
14 convert::ToPyResult,
15 dict_inner::{self, DictSize},
16 function::{ArgIterable, FuncArgs, OptionalArg, PosArgs, PyArithmeticValue, PyComparisonValue},
17 protocol::{PyIterReturn, PyNumberMethods, PySequenceMethods},
18 recursion::ReprGuard,
19 types::AsNumber,
20 types::{
21 AsSequence, Comparable, Constructor, DefaultConstructor, Hashable, Initializer, IterNext,
22 Iterable, PyComparisonOp, Representable, SelfIter,
23 },
24 utils::collection_repr,
25 vm::VirtualMachine,
26};
27use alloc::fmt;
28use core::borrow::Borrow;
29use core::ops::Deref;
30use rustpython_common::{
31 atomic::{Ordering, PyAtomic, Radium},
32 hash,
33};
34
35pub type SetContentType = dict_inner::Dict<()>;
36
37#[pyclass(module = false, name = "set", unhashable = true, traverse)]
38#[derive(Default)]
39pub struct PySet {
40 pub(super) inner: PySetInner,
41}
42
43impl PySet {
44 #[deprecated(note = "Use `PySet::default().into_ref(ctx)` instead")]
45 pub fn new_ref(ctx: &Context) -> PyRef<Self> {
46 Self::default().into_ref(ctx)
47 }
48
49 pub fn elements(&self) -> Vec<PyObjectRef> {
50 self.inner.elements()
51 }
52
53 fn fold_op(
54 &self,
55 others: impl core::iter::Iterator<Item = ArgIterable>,
56 op: fn(&PySetInner, ArgIterable, &VirtualMachine) -> PyResult<PySetInner>,
57 vm: &VirtualMachine,
58 ) -> PyResult<Self> {
59 Ok(Self {
60 inner: self.inner.fold_op(others, op, vm)?,
61 })
62 }
63
64 fn op(
65 &self,
66 other: AnySet,
67 op: fn(&PySetInner, ArgIterable, &VirtualMachine) -> PyResult<PySetInner>,
68 vm: &VirtualMachine,
69 ) -> PyResult<Self> {
70 Ok(Self {
71 inner: self
72 .inner
73 .fold_op(core::iter::once(other.into_iterable(vm)?), op, vm)?,
74 })
75 }
76}
77
78#[pyclass(module = false, name = "frozenset", unhashable = true)]
79pub struct PyFrozenSet {
80 inner: PySetInner,
81 hash: PyAtomic<PyHash>,
82}
83
84impl Default for PyFrozenSet {
85 fn default() -> Self {
86 Self {
87 inner: PySetInner::default(),
88 hash: hash::SENTINEL.into(),
89 }
90 }
91}
92
93impl PyFrozenSet {
94 pub fn from_iter(
96 vm: &VirtualMachine,
97 it: impl IntoIterator<Item = PyObjectRef>,
98 ) -> PyResult<Self> {
99 let inner = PySetInner::default();
100 for elem in it {
101 inner.add(elem, vm)?;
102 }
103 Ok(Self {
105 inner,
106 ..Default::default()
107 })
108 }
109
110 pub fn elements(&self) -> Vec<PyObjectRef> {
111 self.inner.elements()
112 }
113
114 fn fold_op(
115 &self,
116 others: impl core::iter::Iterator<Item = ArgIterable>,
117 op: fn(&PySetInner, ArgIterable, &VirtualMachine) -> PyResult<PySetInner>,
118 vm: &VirtualMachine,
119 ) -> PyResult<Self> {
120 Ok(Self {
121 inner: self.inner.fold_op(others, op, vm)?,
122 ..Default::default()
123 })
124 }
125
126 fn op(
127 &self,
128 other: AnySet,
129 op: fn(&PySetInner, ArgIterable, &VirtualMachine) -> PyResult<PySetInner>,
130 vm: &VirtualMachine,
131 ) -> PyResult<Self> {
132 Ok(Self {
133 inner: self
134 .inner
135 .fold_op(core::iter::once(other.into_iterable(vm)?), op, vm)?,
136 ..Default::default()
137 })
138 }
139}
140
141impl fmt::Debug for PySet {
142 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
143 f.write_str("set")
145 }
146}
147
148impl fmt::Debug for PyFrozenSet {
149 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150 f.write_str("PyFrozenSet ")?;
152 f.debug_set().entries(self.elements().iter()).finish()
153 }
154}
155
156impl PyPayload for PySet {
157 #[inline]
158 fn class(ctx: &Context) -> &'static Py<PyType> {
159 ctx.types.set_type
160 }
161}
162
163impl PyPayload for PyFrozenSet {
164 #[inline]
165 fn class(ctx: &Context) -> &'static Py<PyType> {
166 ctx.types.frozenset_type
167 }
168}
169
170#[derive(Default, Clone)]
171pub(super) struct PySetInner {
172 content: PyRc<SetContentType>,
173}
174
175unsafe impl crate::object::Traverse for PySetInner {
176 fn traverse(&self, tracer_fn: &mut crate::object::TraverseFn<'_>) {
177 self.content.traverse(tracer_fn)
179 }
180}
181
182impl PySetInner {
183 pub(super) fn from_iter<T>(iter: T, vm: &VirtualMachine) -> PyResult<Self>
184 where
185 T: IntoIterator<Item = PyResult<PyObjectRef>>,
186 {
187 let set = Self::default();
188 for item in iter {
189 set.add(item?, vm)?;
190 }
191 Ok(set)
192 }
193
194 fn fold_op<O>(
195 &self,
196 others: impl core::iter::Iterator<Item = O>,
197 op: fn(&Self, O, &VirtualMachine) -> PyResult<Self>,
198 vm: &VirtualMachine,
199 ) -> PyResult<Self> {
200 let mut res = self.copy();
201 for other in others {
202 res = op(&res, other, vm)?;
203 }
204 Ok(res)
205 }
206
207 fn len(&self) -> usize {
208 self.content.len()
209 }
210
211 fn sizeof(&self) -> usize {
212 self.content.sizeof()
213 }
214
215 fn copy(&self) -> Self {
216 Self {
217 content: PyRc::new((*self.content).clone()),
218 }
219 }
220
221 fn contains(&self, needle: &PyObject, vm: &VirtualMachine) -> PyResult<bool> {
222 self.retry_op_with_frozenset(needle, vm, |needle, vm| self.content.contains(vm, needle))
223 }
224
225 fn compare(&self, other: &Self, op: PyComparisonOp, vm: &VirtualMachine) -> PyResult<bool> {
226 if op == PyComparisonOp::Ne {
227 return self.compare(other, PyComparisonOp::Eq, vm).map(|eq| !eq);
228 }
229 if !op.eval_ord(self.len().cmp(&other.len())) {
230 return Ok(false);
231 }
232
233 let (superset, subset) = match op {
234 PyComparisonOp::Lt | PyComparisonOp::Le => (other, self),
235 _ => (self, other),
236 };
237
238 for key in subset.elements() {
239 if !superset.contains(&key, vm)? {
240 return Ok(false);
241 }
242 }
243 Ok(true)
244 }
245
246 pub(super) fn union(&self, other: ArgIterable, vm: &VirtualMachine) -> PyResult<Self> {
247 let set = self.clone();
248 for item in other.iter(vm)? {
249 set.add(item?, vm)?;
250 }
251
252 Ok(set)
253 }
254
255 pub(super) fn intersection(&self, other: ArgIterable, vm: &VirtualMachine) -> PyResult<Self> {
256 let set = Self::default();
257 for item in other.iter(vm)? {
258 let obj = item?;
259 if self.contains(&obj, vm)? {
260 set.add(obj, vm)?;
261 }
262 }
263 Ok(set)
264 }
265
266 pub(super) fn difference(&self, other: ArgIterable, vm: &VirtualMachine) -> PyResult<Self> {
267 let set = self.copy();
268 for item in other.iter(vm)? {
269 set.content.delete_if_exists(vm, &*item?)?;
270 }
271 Ok(set)
272 }
273
274 pub(super) fn symmetric_difference(
275 &self,
276 other: ArgIterable,
277 vm: &VirtualMachine,
278 ) -> PyResult<Self> {
279 let new_inner = self.clone();
280
281 let other_set = Self::from_iter(other.iter(vm)?, vm)?;
283
284 for item in other_set.elements() {
285 new_inner.content.delete_or_insert(vm, &item, ())?
286 }
287
288 Ok(new_inner)
289 }
290
291 fn issuperset(&self, other: ArgIterable, vm: &VirtualMachine) -> PyResult<bool> {
292 for item in other.iter(vm)? {
293 if !self.contains(&*item?, vm)? {
294 return Ok(false);
295 }
296 }
297 Ok(true)
298 }
299
300 fn issubset(&self, other: ArgIterable, vm: &VirtualMachine) -> PyResult<bool> {
301 let other_set = Self::from_iter(other.iter(vm)?, vm)?;
302 self.compare(&other_set, PyComparisonOp::Le, vm)
303 }
304
305 pub(super) fn isdisjoint(&self, other: ArgIterable, vm: &VirtualMachine) -> PyResult<bool> {
306 for item in other.iter(vm)? {
307 if self.contains(&*item?, vm)? {
308 return Ok(false);
309 }
310 }
311 Ok(true)
312 }
313
314 fn iter(&self) -> PySetIterator {
315 PySetIterator {
316 size: self.content.size(),
317 internal: PyMutex::new(PositionIterInternal::new(self.content.clone(), 0)),
318 }
319 }
320
321 fn repr(&self, class_name: Option<&str>, vm: &VirtualMachine) -> PyResult<Wtf8Buf> {
322 collection_repr(class_name, "{", "}", self.elements().iter(), vm)
323 }
324
325 fn add(&self, item: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
326 self.content.insert(vm, &*item, ())
327 }
328
329 fn remove(&self, item: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
330 self.retry_op_with_frozenset(&item, vm, |item, vm| self.content.delete(vm, item))
331 }
332
333 fn discard(&self, item: &PyObject, vm: &VirtualMachine) -> PyResult<bool> {
334 self.retry_op_with_frozenset(item, vm, |item, vm| self.content.delete_if_exists(vm, item))
335 }
336
337 fn clear(&self) {
338 self.content.clear()
339 }
340
341 fn elements(&self) -> Vec<PyObjectRef> {
342 self.content.keys()
343 }
344
345 fn pop(&self, vm: &VirtualMachine) -> PyResult {
346 if let Some((key, _)) = self.content.pop_back() {
348 Ok(key)
349 } else {
350 let err_msg = vm.ctx.new_str(ascii!("pop from an empty set")).into();
351 Err(vm.new_key_error(err_msg))
352 }
353 }
354
355 fn update(
356 &self,
357 others: impl core::iter::Iterator<Item = ArgIterable>,
358 vm: &VirtualMachine,
359 ) -> PyResult<()> {
360 for iterable in others {
361 for item in iterable.iter(vm)? {
362 self.add(item?, vm)?;
363 }
364 }
365 Ok(())
366 }
367
368 fn update_internal(&self, iterable: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
369 if let Ok(any_set) = AnySet::try_from_object(vm, iterable.to_owned()) {
371 self.merge_set(any_set, vm)
372 } else if let Ok(dict) = iterable.to_owned().downcast_exact::<PyDict>(vm) {
374 self.merge_dict(dict.into_pyref(), vm)
375 } else {
376 for item in iterable.try_into_value::<ArgIterable>(vm)?.iter(vm)? {
378 self.add(item?, vm)?;
379 }
380 Ok(())
381 }
382 }
383
384 fn merge_set(&self, any_set: AnySet, vm: &VirtualMachine) -> PyResult<()> {
385 for item in any_set.as_inner().elements() {
386 self.add(item, vm)?;
387 }
388 Ok(())
389 }
390
391 fn merge_dict(&self, dict: PyDictRef, vm: &VirtualMachine) -> PyResult<()> {
392 for (key, _value) in dict {
393 self.add(key, vm)?;
394 }
395 Ok(())
396 }
397
398 fn intersection_update(
399 &self,
400 others: impl core::iter::Iterator<Item = ArgIterable>,
401 vm: &VirtualMachine,
402 ) -> PyResult<()> {
403 let temp_inner = self.fold_op(others, Self::intersection, vm)?;
404 self.clear();
405 for obj in temp_inner.elements() {
406 self.add(obj, vm)?;
407 }
408 Ok(())
409 }
410
411 fn difference_update(
412 &self,
413 others: impl core::iter::Iterator<Item = ArgIterable>,
414 vm: &VirtualMachine,
415 ) -> PyResult<()> {
416 for iterable in others {
417 let items = iterable.iter(vm)?.collect::<Result<Vec<_>, _>>()?;
418 for item in items {
419 self.content.delete_if_exists(vm, &*item)?;
420 }
421 }
422 Ok(())
423 }
424
425 fn symmetric_difference_update(
426 &self,
427 others: impl core::iter::Iterator<Item = ArgIterable>,
428 vm: &VirtualMachine,
429 ) -> PyResult<()> {
430 for iterable in others {
431 let iterable_set = Self::from_iter(iterable.iter(vm)?, vm)?;
433 for item in iterable_set.elements() {
434 self.content.delete_or_insert(vm, &item, ())?;
435 }
436 }
437 Ok(())
438 }
439
440 fn hash(&self, vm: &VirtualMachine) -> PyResult<PyHash> {
441 const fn _shuffle_bits(h: u64) -> u64 {
446 ((h ^ 89869747) ^ (h.wrapping_shl(16))).wrapping_mul(3644798167)
447 }
448 let mut hash: u64 = (self.len() as u64 + 1).wrapping_mul(1927868237);
450 hash = self.content.try_fold_keys(hash, |h, element| {
453 Ok(h ^ _shuffle_bits(element.hash(vm)? as u64))
454 })?;
455 hash ^= (hash >> 11) ^ (hash >> 25);
457 hash = hash.wrapping_mul(69069).wrapping_add(907133923);
458 if hash == u64::MAX {
460 hash = 590923713;
461 }
462 Ok(hash as PyHash)
463 }
464
465 fn retry_op_with_frozenset<T, F>(
469 &self,
470 item: &PyObject,
471 vm: &VirtualMachine,
472 op: F,
473 ) -> PyResult<T>
474 where
475 F: Fn(&PyObject, &VirtualMachine) -> PyResult<T>,
476 {
477 op(item, vm).or_else(|original_err| {
478 item.downcast_ref::<PySet>()
479 .ok_or(original_err)
481 .and_then(|set| {
482 op(
483 &PyFrozenSet {
484 inner: set.inner.copy(),
485 ..Default::default()
486 }
487 .into_pyobject(vm),
488 vm,
489 )
490 .map_err(|op_err| {
492 if op_err.fast_isinstance(vm.ctx.exceptions.key_error) {
493 vm.new_key_error(item.to_owned())
494 } else {
495 op_err
496 }
497 })
498 })
499 })
500 }
501}
502
503fn extract_set(obj: &PyObject) -> Option<&PySetInner> {
504 match_class!(match obj {
505 ref set @ PySet => Some(&set.inner),
506 ref frozen @ PyFrozenSet => Some(&frozen.inner),
507 _ => None,
508 })
509}
510
511fn reduce_set(
512 zelf: &PyObject,
513 vm: &VirtualMachine,
514) -> PyResult<(PyTypeRef, PyTupleRef, Option<PyDictRef>)> {
515 Ok((
516 zelf.class().to_owned(),
517 vm.new_tuple((extract_set(zelf)
518 .unwrap_or(&PySetInner::default())
519 .elements(),)),
520 zelf.dict(),
521 ))
522}
523
524#[pyclass(
525 with(
526 Constructor,
527 Initializer,
528 AsSequence,
529 Comparable,
530 Iterable,
531 AsNumber,
532 Representable
533 ),
534 flags(BASETYPE, _MATCH_SELF, HAS_WEAKREF)
535)]
536impl PySet {
537 fn __len__(&self) -> usize {
538 self.inner.len()
539 }
540
541 fn __contains__(&self, needle: &PyObject, vm: &VirtualMachine) -> PyResult<bool> {
542 self.inner.contains(needle, vm)
543 }
544
545 #[pymethod]
546 fn __sizeof__(&self) -> usize {
547 core::mem::size_of::<Self>() + self.inner.sizeof()
548 }
549
550 #[pymethod]
551 fn copy(&self) -> Self {
552 Self {
553 inner: self.inner.copy(),
554 }
555 }
556
557 #[pymethod]
558 fn union(&self, others: PosArgs<ArgIterable>, vm: &VirtualMachine) -> PyResult<Self> {
559 self.fold_op(others.into_iter(), PySetInner::union, vm)
560 }
561
562 #[pymethod]
563 fn intersection(&self, others: PosArgs<ArgIterable>, vm: &VirtualMachine) -> PyResult<Self> {
564 self.fold_op(others.into_iter(), PySetInner::intersection, vm)
565 }
566
567 #[pymethod]
568 fn difference(&self, others: PosArgs<ArgIterable>, vm: &VirtualMachine) -> PyResult<Self> {
569 self.fold_op(others.into_iter(), PySetInner::difference, vm)
570 }
571
572 #[pymethod]
573 fn symmetric_difference(
574 &self,
575 others: PosArgs<ArgIterable>,
576 vm: &VirtualMachine,
577 ) -> PyResult<Self> {
578 self.fold_op(others.into_iter(), PySetInner::symmetric_difference, vm)
579 }
580
581 #[pymethod]
582 fn issubset(&self, other: ArgIterable, vm: &VirtualMachine) -> PyResult<bool> {
583 self.inner.issubset(other, vm)
584 }
585
586 #[pymethod]
587 fn issuperset(&self, other: ArgIterable, vm: &VirtualMachine) -> PyResult<bool> {
588 self.inner.issuperset(other, vm)
589 }
590
591 #[pymethod]
592 fn isdisjoint(&self, other: ArgIterable, vm: &VirtualMachine) -> PyResult<bool> {
593 self.inner.isdisjoint(other, vm)
594 }
595
596 fn __or__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyArithmeticValue<Self>> {
597 if let Ok(other) = AnySet::try_from_object(vm, other) {
598 Ok(PyArithmeticValue::Implemented(self.op(
599 other,
600 PySetInner::union,
601 vm,
602 )?))
603 } else {
604 Ok(PyArithmeticValue::NotImplemented)
605 }
606 }
607
608 fn __and__(
609 &self,
610 other: PyObjectRef,
611 vm: &VirtualMachine,
612 ) -> PyResult<PyArithmeticValue<Self>> {
613 if let Ok(other) = AnySet::try_from_object(vm, other) {
614 Ok(PyArithmeticValue::Implemented(self.op(
615 other,
616 PySetInner::intersection,
617 vm,
618 )?))
619 } else {
620 Ok(PyArithmeticValue::NotImplemented)
621 }
622 }
623
624 fn __sub__(
625 &self,
626 other: PyObjectRef,
627 vm: &VirtualMachine,
628 ) -> PyResult<PyArithmeticValue<Self>> {
629 if let Ok(other) = AnySet::try_from_object(vm, other) {
630 Ok(PyArithmeticValue::Implemented(self.op(
631 other,
632 PySetInner::difference,
633 vm,
634 )?))
635 } else {
636 Ok(PyArithmeticValue::NotImplemented)
637 }
638 }
639
640 fn __rsub__(
641 zelf: PyRef<Self>,
642 other: PyObjectRef,
643 vm: &VirtualMachine,
644 ) -> PyResult<PyArithmeticValue<Self>> {
645 if let Ok(other) = AnySet::try_from_object(vm, other) {
646 Ok(PyArithmeticValue::Implemented(Self {
647 inner: other
648 .as_inner()
649 .difference(ArgIterable::try_from_object(vm, zelf.into())?, vm)?,
650 }))
651 } else {
652 Ok(PyArithmeticValue::NotImplemented)
653 }
654 }
655
656 fn __xor__(
657 &self,
658 other: PyObjectRef,
659 vm: &VirtualMachine,
660 ) -> PyResult<PyArithmeticValue<Self>> {
661 if let Ok(other) = AnySet::try_from_object(vm, other) {
662 Ok(PyArithmeticValue::Implemented(self.op(
663 other,
664 PySetInner::symmetric_difference,
665 vm,
666 )?))
667 } else {
668 Ok(PyArithmeticValue::NotImplemented)
669 }
670 }
671
672 #[pymethod]
673 pub fn add(&self, item: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
674 self.inner.add(item, vm)
675 }
676
677 #[pymethod]
678 fn remove(&self, item: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
679 self.inner.remove(item, vm)
680 }
681
682 #[pymethod]
683 fn discard(&self, item: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
684 self.inner.discard(&item, vm).map(|_| ())
685 }
686
687 #[pymethod]
688 fn clear(&self) {
689 self.inner.clear()
690 }
691
692 #[pymethod]
693 fn pop(&self, vm: &VirtualMachine) -> PyResult {
694 self.inner.pop(vm)
695 }
696
697 fn __ior__(zelf: PyRef<Self>, set: AnySet, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
698 zelf.inner.update(set.into_iterable_iter(vm)?, vm)?;
699 Ok(zelf)
700 }
701
702 #[pymethod]
703 fn update(&self, others: PosArgs<PyObjectRef>, vm: &VirtualMachine) -> PyResult<()> {
704 for iterable in others {
705 self.inner.update_internal(iterable, vm)?;
706 }
707 Ok(())
708 }
709
710 #[pymethod]
711 fn intersection_update(
712 &self,
713 others: PosArgs<ArgIterable>,
714 vm: &VirtualMachine,
715 ) -> PyResult<()> {
716 self.inner.intersection_update(others.into_iter(), vm)?;
717 Ok(())
718 }
719
720 fn __iand__(zelf: PyRef<Self>, set: AnySet, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
721 if !set.is(zelf.as_object()) {
722 zelf.inner
723 .intersection_update(core::iter::once(set.into_iterable(vm)?), vm)?;
724 }
725 Ok(zelf)
726 }
727
728 #[pymethod]
729 fn difference_update(&self, others: PosArgs<ArgIterable>, vm: &VirtualMachine) -> PyResult<()> {
730 self.inner.difference_update(others.into_iter(), vm)
731 }
732
733 fn __isub__(zelf: PyRef<Self>, set: AnySet, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
734 if set.is(zelf.as_object()) {
735 zelf.inner.clear();
736 } else {
737 zelf.inner
738 .difference_update(set.into_iterable_iter(vm)?, vm)?;
739 }
740 Ok(zelf)
741 }
742
743 #[pymethod]
744 fn symmetric_difference_update(
745 &self,
746 others: PosArgs<ArgIterable>,
747 vm: &VirtualMachine,
748 ) -> PyResult<()> {
749 self.inner
750 .symmetric_difference_update(others.into_iter(), vm)
751 }
752
753 fn __ixor__(zelf: PyRef<Self>, set: AnySet, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
754 if set.is(zelf.as_object()) {
755 zelf.inner.clear();
756 } else {
757 zelf.inner
758 .symmetric_difference_update(set.into_iterable_iter(vm)?, vm)?;
759 }
760 Ok(zelf)
761 }
762
763 #[pymethod]
764 fn __reduce__(
765 zelf: PyRef<Self>,
766 vm: &VirtualMachine,
767 ) -> PyResult<(PyTypeRef, PyTupleRef, Option<PyDictRef>)> {
768 reduce_set(zelf.as_ref(), vm)
769 }
770
771 #[pyclassmethod]
772 fn __class_getitem__(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyGenericAlias {
773 PyGenericAlias::from_args(cls, args, vm)
774 }
775}
776
777impl DefaultConstructor for PySet {}
778
779impl Initializer for PySet {
780 type Args = OptionalArg<PyObjectRef>;
781
782 fn init(zelf: PyRef<Self>, iterable: Self::Args, vm: &VirtualMachine) -> PyResult<()> {
783 zelf.clear();
784 if let OptionalArg::Present(it) = iterable {
785 zelf.update(PosArgs::new(vec![it]), vm)?;
786 }
787 Ok(())
788 }
789}
790
791impl AsSequence for PySet {
792 fn as_sequence() -> &'static PySequenceMethods {
793 static AS_SEQUENCE: LazyLock<PySequenceMethods> = LazyLock::new(|| PySequenceMethods {
794 length: atomic_func!(|seq, _vm| Ok(PySet::sequence_downcast(seq).__len__())),
795 contains: atomic_func!(
796 |seq, needle, vm| PySet::sequence_downcast(seq).__contains__(needle, vm)
797 ),
798 ..PySequenceMethods::NOT_IMPLEMENTED
799 });
800 &AS_SEQUENCE
801 }
802}
803
804impl Comparable for PySet {
805 fn cmp(
806 zelf: &crate::Py<Self>,
807 other: &PyObject,
808 op: PyComparisonOp,
809 vm: &VirtualMachine,
810 ) -> PyResult<PyComparisonValue> {
811 extract_set(other).map_or(Ok(PyComparisonValue::NotImplemented), |other| {
812 Ok(zelf.inner.compare(other, op, vm)?.into())
813 })
814 }
815}
816
817impl Iterable for PySet {
818 fn iter(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
819 Ok(zelf.inner.iter().into_pyobject(vm))
820 }
821}
822
823impl AsNumber for PySet {
824 fn as_number() -> &'static PyNumberMethods {
825 static AS_NUMBER: PyNumberMethods = PyNumberMethods {
826 subtract: Some(|a, b, vm| {
829 if !AnySet::check(a, vm) || !AnySet::check(b, vm) {
830 return Ok(vm.ctx.not_implemented());
831 }
832 if let Some(a) = a.downcast_ref::<PySet>() {
833 a.__sub__(b.to_owned(), vm).to_pyresult(vm)
834 } else if let Some(a) = a.downcast_ref::<PyFrozenSet>() {
835 a.__sub__(b.to_owned(), vm)
837 .map(|r| {
838 r.map(|s| PySet {
839 inner: s.inner.clone(),
840 })
841 })
842 .to_pyresult(vm)
843 } else {
844 Ok(vm.ctx.not_implemented())
845 }
846 }),
847 and: Some(|a, b, vm| {
848 if !AnySet::check(a, vm) || !AnySet::check(b, vm) {
849 return Ok(vm.ctx.not_implemented());
850 }
851 if let Some(a) = a.downcast_ref::<PySet>() {
852 a.__and__(b.to_owned(), vm).to_pyresult(vm)
853 } else if let Some(a) = a.downcast_ref::<PyFrozenSet>() {
854 a.__and__(b.to_owned(), vm)
855 .map(|r| {
856 r.map(|s| PySet {
857 inner: s.inner.clone(),
858 })
859 })
860 .to_pyresult(vm)
861 } else {
862 Ok(vm.ctx.not_implemented())
863 }
864 }),
865 xor: Some(|a, b, vm| {
866 if !AnySet::check(a, vm) || !AnySet::check(b, vm) {
867 return Ok(vm.ctx.not_implemented());
868 }
869 if let Some(a) = a.downcast_ref::<PySet>() {
870 a.__xor__(b.to_owned(), vm).to_pyresult(vm)
871 } else if let Some(a) = a.downcast_ref::<PyFrozenSet>() {
872 a.__xor__(b.to_owned(), vm)
873 .map(|r| {
874 r.map(|s| PySet {
875 inner: s.inner.clone(),
876 })
877 })
878 .to_pyresult(vm)
879 } else {
880 Ok(vm.ctx.not_implemented())
881 }
882 }),
883 or: Some(|a, b, vm| {
884 if !AnySet::check(a, vm) || !AnySet::check(b, vm) {
885 return Ok(vm.ctx.not_implemented());
886 }
887 if let Some(a) = a.downcast_ref::<PySet>() {
888 a.__or__(b.to_owned(), vm).to_pyresult(vm)
889 } else if let Some(a) = a.downcast_ref::<PyFrozenSet>() {
890 a.__or__(b.to_owned(), vm)
891 .map(|r| {
892 r.map(|s| PySet {
893 inner: s.inner.clone(),
894 })
895 })
896 .to_pyresult(vm)
897 } else {
898 Ok(vm.ctx.not_implemented())
899 }
900 }),
901 inplace_subtract: Some(|a, b, vm| {
902 if let Some(a) = a.downcast_ref::<PySet>() {
903 PySet::__isub__(a.to_owned(), AnySet::try_from_object(vm, b.to_owned())?, vm)
904 .to_pyresult(vm)
905 } else {
906 Ok(vm.ctx.not_implemented())
907 }
908 }),
909 inplace_and: Some(|a, b, vm| {
910 if let Some(a) = a.downcast_ref::<PySet>() {
911 PySet::__iand__(a.to_owned(), AnySet::try_from_object(vm, b.to_owned())?, vm)
912 .to_pyresult(vm)
913 } else {
914 Ok(vm.ctx.not_implemented())
915 }
916 }),
917 inplace_xor: Some(|a, b, vm| {
918 if let Some(a) = a.downcast_ref::<PySet>() {
919 PySet::__ixor__(a.to_owned(), AnySet::try_from_object(vm, b.to_owned())?, vm)
920 .to_pyresult(vm)
921 } else {
922 Ok(vm.ctx.not_implemented())
923 }
924 }),
925 inplace_or: Some(|a, b, vm| {
926 if let Some(a) = a.downcast_ref::<PySet>() {
927 PySet::__ior__(a.to_owned(), AnySet::try_from_object(vm, b.to_owned())?, vm)
928 .to_pyresult(vm)
929 } else {
930 Ok(vm.ctx.not_implemented())
931 }
932 }),
933 ..PyNumberMethods::NOT_IMPLEMENTED
934 };
935 &AS_NUMBER
936 }
937}
938
939impl Representable for PySet {
940 #[inline]
941 fn repr_wtf8(zelf: &crate::Py<Self>, vm: &VirtualMachine) -> PyResult<Wtf8Buf> {
942 let class = zelf.class();
943 let borrowed_name = class.name();
944 let class_name = borrowed_name.deref();
945 if zelf.inner.len() == 0 {
946 return Ok(Wtf8Buf::from(format!("{class_name}()")));
947 }
948 if let Some(_guard) = ReprGuard::enter(vm, zelf.as_object()) {
949 let name = (class_name != "set").then_some(class_name);
950 zelf.inner.repr(name, vm)
951 } else {
952 Ok(Wtf8Buf::from(format!("{class_name}(...)")))
953 }
954 }
955}
956
957impl Constructor for PyFrozenSet {
958 type Args = Vec<PyObjectRef>;
959
960 fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
961 let iterable: OptionalArg<PyObjectRef> = args.bind(vm)?;
962
963 if cls.is(vm.ctx.types.frozenset_type) {
965 if let OptionalArg::Present(ref input) = iterable
967 && let Ok(fs) = input.clone().downcast_exact::<PyFrozenSet>(vm)
968 {
969 return Ok(fs.into_pyref().into());
970 }
971
972 if iterable.is_missing() {
974 return Ok(vm.ctx.empty_frozenset.clone().into());
975 }
976 }
977
978 let elements: Vec<PyObjectRef> = if let OptionalArg::Present(iterable) = iterable {
979 iterable.try_to_value(vm)?
980 } else {
981 vec![]
982 };
983
984 if elements.is_empty() && cls.is(vm.ctx.types.frozenset_type) {
986 return Ok(vm.ctx.empty_frozenset.clone().into());
987 }
988
989 let payload = Self::py_new(&cls, elements, vm)?;
990 payload.into_ref_with_type(vm, cls).map(Into::into)
991 }
992
993 fn py_new(_cls: &Py<PyType>, elements: Self::Args, vm: &VirtualMachine) -> PyResult<Self> {
994 Self::from_iter(vm, elements)
995 }
996}
997
998#[pyclass(
999 flags(BASETYPE, _MATCH_SELF, HAS_WEAKREF),
1000 with(
1001 Constructor,
1002 AsSequence,
1003 Hashable,
1004 Comparable,
1005 Iterable,
1006 AsNumber,
1007 Representable
1008 )
1009)]
1010impl PyFrozenSet {
1011 fn __len__(&self) -> usize {
1012 self.inner.len()
1013 }
1014
1015 fn __contains__(&self, needle: &PyObject, vm: &VirtualMachine) -> PyResult<bool> {
1016 self.inner.contains(needle, vm)
1017 }
1018
1019 #[pymethod]
1020 fn __sizeof__(&self) -> usize {
1021 core::mem::size_of::<Self>() + self.inner.sizeof()
1022 }
1023
1024 #[pymethod]
1025 fn copy(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyRef<Self> {
1026 if zelf.class().is(vm.ctx.types.frozenset_type) {
1027 zelf
1028 } else {
1029 Self {
1030 inner: zelf.inner.copy(),
1031 ..Default::default()
1032 }
1033 .into_ref(&vm.ctx)
1034 }
1035 }
1036
1037 #[pymethod]
1038 fn union(&self, others: PosArgs<ArgIterable>, vm: &VirtualMachine) -> PyResult<Self> {
1039 self.fold_op(others.into_iter(), PySetInner::union, vm)
1040 }
1041
1042 #[pymethod]
1043 fn intersection(&self, others: PosArgs<ArgIterable>, vm: &VirtualMachine) -> PyResult<Self> {
1044 self.fold_op(others.into_iter(), PySetInner::intersection, vm)
1045 }
1046
1047 #[pymethod]
1048 fn difference(&self, others: PosArgs<ArgIterable>, vm: &VirtualMachine) -> PyResult<Self> {
1049 self.fold_op(others.into_iter(), PySetInner::difference, vm)
1050 }
1051
1052 #[pymethod]
1053 fn symmetric_difference(
1054 &self,
1055 others: PosArgs<ArgIterable>,
1056 vm: &VirtualMachine,
1057 ) -> PyResult<Self> {
1058 self.fold_op(others.into_iter(), PySetInner::symmetric_difference, vm)
1059 }
1060
1061 #[pymethod]
1062 fn issubset(&self, other: ArgIterable, vm: &VirtualMachine) -> PyResult<bool> {
1063 self.inner.issubset(other, vm)
1064 }
1065
1066 #[pymethod]
1067 fn issuperset(&self, other: ArgIterable, vm: &VirtualMachine) -> PyResult<bool> {
1068 self.inner.issuperset(other, vm)
1069 }
1070
1071 #[pymethod]
1072 fn isdisjoint(&self, other: ArgIterable, vm: &VirtualMachine) -> PyResult<bool> {
1073 self.inner.isdisjoint(other, vm)
1074 }
1075
1076 fn __or__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyArithmeticValue<Self>> {
1077 if let Ok(set) = AnySet::try_from_object(vm, other) {
1078 Ok(PyArithmeticValue::Implemented(self.op(
1079 set,
1080 PySetInner::union,
1081 vm,
1082 )?))
1083 } else {
1084 Ok(PyArithmeticValue::NotImplemented)
1085 }
1086 }
1087
1088 fn __and__(
1089 &self,
1090 other: PyObjectRef,
1091 vm: &VirtualMachine,
1092 ) -> PyResult<PyArithmeticValue<Self>> {
1093 if let Ok(other) = AnySet::try_from_object(vm, other) {
1094 Ok(PyArithmeticValue::Implemented(self.op(
1095 other,
1096 PySetInner::intersection,
1097 vm,
1098 )?))
1099 } else {
1100 Ok(PyArithmeticValue::NotImplemented)
1101 }
1102 }
1103
1104 fn __sub__(
1105 &self,
1106 other: PyObjectRef,
1107 vm: &VirtualMachine,
1108 ) -> PyResult<PyArithmeticValue<Self>> {
1109 if let Ok(other) = AnySet::try_from_object(vm, other) {
1110 Ok(PyArithmeticValue::Implemented(self.op(
1111 other,
1112 PySetInner::difference,
1113 vm,
1114 )?))
1115 } else {
1116 Ok(PyArithmeticValue::NotImplemented)
1117 }
1118 }
1119
1120 fn __rsub__(
1121 zelf: PyRef<Self>,
1122 other: PyObjectRef,
1123 vm: &VirtualMachine,
1124 ) -> PyResult<PyArithmeticValue<Self>> {
1125 if let Ok(other) = AnySet::try_from_object(vm, other) {
1126 Ok(PyArithmeticValue::Implemented(Self {
1127 inner: other
1128 .as_inner()
1129 .difference(ArgIterable::try_from_object(vm, zelf.into())?, vm)?,
1130 ..Default::default()
1131 }))
1132 } else {
1133 Ok(PyArithmeticValue::NotImplemented)
1134 }
1135 }
1136
1137 fn __xor__(
1138 &self,
1139 other: PyObjectRef,
1140 vm: &VirtualMachine,
1141 ) -> PyResult<PyArithmeticValue<Self>> {
1142 if let Ok(other) = AnySet::try_from_object(vm, other) {
1143 Ok(PyArithmeticValue::Implemented(self.op(
1144 other,
1145 PySetInner::symmetric_difference,
1146 vm,
1147 )?))
1148 } else {
1149 Ok(PyArithmeticValue::NotImplemented)
1150 }
1151 }
1152
1153 #[pymethod]
1154 fn __reduce__(
1155 zelf: PyRef<Self>,
1156 vm: &VirtualMachine,
1157 ) -> PyResult<(PyTypeRef, PyTupleRef, Option<PyDictRef>)> {
1158 reduce_set(zelf.as_ref(), vm)
1159 }
1160
1161 #[pyclassmethod]
1162 fn __class_getitem__(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyGenericAlias {
1163 PyGenericAlias::from_args(cls, args, vm)
1164 }
1165}
1166
1167impl AsSequence for PyFrozenSet {
1168 fn as_sequence() -> &'static PySequenceMethods {
1169 static AS_SEQUENCE: LazyLock<PySequenceMethods> = LazyLock::new(|| PySequenceMethods {
1170 length: atomic_func!(|seq, _vm| Ok(PyFrozenSet::sequence_downcast(seq).__len__())),
1171 contains: atomic_func!(
1172 |seq, needle, vm| PyFrozenSet::sequence_downcast(seq).__contains__(needle, vm)
1173 ),
1174 ..PySequenceMethods::NOT_IMPLEMENTED
1175 });
1176 &AS_SEQUENCE
1177 }
1178}
1179
1180impl Hashable for PyFrozenSet {
1181 #[inline]
1182 fn hash(zelf: &crate::Py<Self>, vm: &VirtualMachine) -> PyResult<PyHash> {
1183 let hash = match zelf.hash.load(Ordering::Relaxed) {
1184 hash::SENTINEL => {
1185 let hash = zelf.inner.hash(vm)?;
1186 match Radium::compare_exchange(
1187 &zelf.hash,
1188 hash::SENTINEL,
1189 hash::fix_sentinel(hash),
1190 Ordering::Relaxed,
1191 Ordering::Relaxed,
1192 ) {
1193 Ok(_) => hash,
1194 Err(prev_stored) => prev_stored,
1195 }
1196 }
1197 hash => hash,
1198 };
1199 Ok(hash)
1200 }
1201}
1202
1203impl Comparable for PyFrozenSet {
1204 fn cmp(
1205 zelf: &crate::Py<Self>,
1206 other: &PyObject,
1207 op: PyComparisonOp,
1208 vm: &VirtualMachine,
1209 ) -> PyResult<PyComparisonValue> {
1210 extract_set(other).map_or(Ok(PyComparisonValue::NotImplemented), |other| {
1211 Ok(zelf.inner.compare(other, op, vm)?.into())
1212 })
1213 }
1214}
1215
1216impl Iterable for PyFrozenSet {
1217 fn iter(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
1218 Ok(zelf.inner.iter().into_pyobject(vm))
1219 }
1220}
1221
1222impl AsNumber for PyFrozenSet {
1223 fn as_number() -> &'static PyNumberMethods {
1224 static AS_NUMBER: PyNumberMethods = PyNumberMethods {
1225 subtract: Some(|a, b, vm| {
1228 if !AnySet::check(a, vm) || !AnySet::check(b, vm) {
1229 return Ok(vm.ctx.not_implemented());
1230 }
1231 if let Some(a) = a.downcast_ref::<PyFrozenSet>() {
1232 a.__sub__(b.to_owned(), vm).to_pyresult(vm)
1233 } else if let Some(a) = a.downcast_ref::<PySet>() {
1234 a.__sub__(b.to_owned(), vm).to_pyresult(vm)
1236 } else {
1237 Ok(vm.ctx.not_implemented())
1238 }
1239 }),
1240 and: Some(|a, b, vm| {
1241 if !AnySet::check(a, vm) || !AnySet::check(b, vm) {
1242 return Ok(vm.ctx.not_implemented());
1243 }
1244 if let Some(a) = a.downcast_ref::<PyFrozenSet>() {
1245 a.__and__(b.to_owned(), vm).to_pyresult(vm)
1246 } else if let Some(a) = a.downcast_ref::<PySet>() {
1247 a.__and__(b.to_owned(), vm).to_pyresult(vm)
1248 } else {
1249 Ok(vm.ctx.not_implemented())
1250 }
1251 }),
1252 xor: Some(|a, b, vm| {
1253 if !AnySet::check(a, vm) || !AnySet::check(b, vm) {
1254 return Ok(vm.ctx.not_implemented());
1255 }
1256 if let Some(a) = a.downcast_ref::<PyFrozenSet>() {
1257 a.__xor__(b.to_owned(), vm).to_pyresult(vm)
1258 } else if let Some(a) = a.downcast_ref::<PySet>() {
1259 a.__xor__(b.to_owned(), vm).to_pyresult(vm)
1260 } else {
1261 Ok(vm.ctx.not_implemented())
1262 }
1263 }),
1264 or: Some(|a, b, vm| {
1265 if !AnySet::check(a, vm) || !AnySet::check(b, vm) {
1266 return Ok(vm.ctx.not_implemented());
1267 }
1268 if let Some(a) = a.downcast_ref::<PyFrozenSet>() {
1269 a.__or__(b.to_owned(), vm).to_pyresult(vm)
1270 } else if let Some(a) = a.downcast_ref::<PySet>() {
1271 a.__or__(b.to_owned(), vm).to_pyresult(vm)
1272 } else {
1273 Ok(vm.ctx.not_implemented())
1274 }
1275 }),
1276 ..PyNumberMethods::NOT_IMPLEMENTED
1277 };
1278 &AS_NUMBER
1279 }
1280}
1281
1282impl Representable for PyFrozenSet {
1283 #[inline]
1284 fn repr_wtf8(zelf: &crate::Py<Self>, vm: &VirtualMachine) -> PyResult<Wtf8Buf> {
1285 let inner = &zelf.inner;
1286 let class = zelf.class();
1287 let class_name = class.name();
1288 if inner.len() == 0 {
1289 return Ok(Wtf8Buf::from(format!("{class_name}()")));
1290 }
1291 if let Some(_guard) = ReprGuard::enter(vm, zelf.as_object()) {
1292 inner.repr(Some(&class_name), vm)
1293 } else {
1294 Ok(Wtf8Buf::from(format!("{class_name}(...)")))
1295 }
1296 }
1297}
1298
1299struct AnySet {
1300 object: PyObjectRef,
1301}
1302
1303impl Borrow<PyObject> for AnySet {
1304 #[inline(always)]
1305 fn borrow(&self) -> &PyObject {
1306 &self.object
1307 }
1308}
1309
1310impl AnySet {
1311 fn check(obj: &PyObject, vm: &VirtualMachine) -> bool {
1314 let ctx = &vm.ctx;
1315 obj.fast_isinstance(ctx.types.set_type) || obj.fast_isinstance(ctx.types.frozenset_type)
1316 }
1317
1318 fn into_iterable(self, vm: &VirtualMachine) -> PyResult<ArgIterable> {
1319 self.object.try_into_value(vm)
1320 }
1321
1322 fn into_iterable_iter(
1323 self,
1324 vm: &VirtualMachine,
1325 ) -> PyResult<impl core::iter::Iterator<Item = ArgIterable>> {
1326 Ok(core::iter::once(self.into_iterable(vm)?))
1327 }
1328
1329 fn as_inner(&self) -> &PySetInner {
1330 match_class!(match self.object.as_object() {
1331 ref set @ PySet => &set.inner,
1332 ref frozen @ PyFrozenSet => &frozen.inner,
1333 _ => unreachable!("AnySet is always PySet or PyFrozenSet"), })
1335 }
1336}
1337
1338impl TryFromObject for AnySet {
1339 fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
1340 let class = obj.class();
1341 if class.fast_issubclass(vm.ctx.types.set_type)
1342 || class.fast_issubclass(vm.ctx.types.frozenset_type)
1343 {
1344 Ok(Self { object: obj })
1345 } else {
1346 Err(vm.new_type_error(format!("{class} is not a subtype of set or frozenset")))
1347 }
1348 }
1349}
1350
1351#[pyclass(module = false, name = "set_iterator")]
1352pub(crate) struct PySetIterator {
1353 size: DictSize,
1354 internal: PyMutex<PositionIterInternal<PyRc<SetContentType>>>,
1355}
1356
1357impl fmt::Debug for PySetIterator {
1358 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1359 f.write_str("set_iterator")
1361 }
1362}
1363
1364impl PyPayload for PySetIterator {
1365 #[inline]
1366 fn class(ctx: &Context) -> &'static Py<PyType> {
1367 ctx.types.set_iterator_type
1368 }
1369}
1370
1371#[pyclass(flags(DISALLOW_INSTANTIATION), with(IterNext, Iterable))]
1372impl PySetIterator {
1373 #[pymethod]
1374 fn __length_hint__(&self) -> usize {
1375 self.internal.lock().length_hint(|_| self.size.entries_size)
1376 }
1377
1378 #[pymethod]
1379 fn __reduce__(
1380 zelf: PyRef<Self>,
1381 vm: &VirtualMachine,
1382 ) -> PyResult<(PyObjectRef, (PyObjectRef,))> {
1383 let internal = zelf.internal.lock();
1384 Ok((
1385 builtins_iter(vm),
1386 (vm.ctx
1387 .new_list(match &internal.status {
1388 IterStatus::Exhausted => vec![],
1389 IterStatus::Active(dict) => {
1390 dict.keys().into_iter().skip(internal.position).collect()
1391 }
1392 })
1393 .into(),),
1394 ))
1395 }
1396}
1397
1398impl SelfIter for PySetIterator {}
1399impl IterNext for PySetIterator {
1400 fn next(zelf: &crate::Py<Self>, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
1401 let mut internal = zelf.internal.lock();
1402 let next = if let IterStatus::Active(dict) = &internal.status {
1403 if dict.has_changed_size(&zelf.size) {
1404 internal.status = IterStatus::Exhausted;
1405 return Err(vm.new_runtime_error("set changed size during iteration"));
1406 }
1407 match dict.next_entry(internal.position) {
1408 Some((position, key, _)) => {
1409 internal.position = position;
1410 PyIterReturn::Return(key)
1411 }
1412 None => {
1413 internal.status = IterStatus::Exhausted;
1414 PyIterReturn::StopIteration(None)
1415 }
1416 }
1417 } else {
1418 PyIterReturn::StopIteration(None)
1419 };
1420 Ok(next)
1421 }
1422}
1423
1424fn vectorcall_set(
1425 zelf_obj: &PyObject,
1426 args: Vec<PyObjectRef>,
1427 nargs: usize,
1428 kwnames: Option<&[PyObjectRef]>,
1429 vm: &VirtualMachine,
1430) -> PyResult {
1431 let zelf: &Py<PyType> = zelf_obj.downcast_ref().unwrap();
1432 let obj = PySet::default().into_ref_with_type(vm, zelf.to_owned())?;
1433 let func_args = FuncArgs::from_vectorcall_owned(args, nargs, kwnames);
1434 PySet::slot_init(obj.clone().into(), func_args, vm)?;
1435 Ok(obj.into())
1436}
1437
1438fn vectorcall_frozenset(
1439 zelf_obj: &PyObject,
1440 args: Vec<PyObjectRef>,
1441 nargs: usize,
1442 kwnames: Option<&[PyObjectRef]>,
1443 vm: &VirtualMachine,
1444) -> PyResult {
1445 let zelf: &Py<PyType> = zelf_obj.downcast_ref().unwrap();
1446 let func_args = FuncArgs::from_vectorcall_owned(args, nargs, kwnames);
1447 (zelf.slots.new.load().unwrap())(zelf.to_owned(), func_args, vm)
1448}
1449
1450pub fn init(context: &'static Context) {
1451 PySet::extend_class(context, context.types.set_type);
1452 context
1453 .types
1454 .set_type
1455 .slots
1456 .vectorcall
1457 .store(Some(vectorcall_set));
1458
1459 PyFrozenSet::extend_class(context, context.types.frozenset_type);
1460 context
1461 .types
1462 .frozenset_type
1463 .slots
1464 .vectorcall
1465 .store(Some(vectorcall_frozenset));
1466
1467 PySetIterator::extend_class(context, context.types.set_iterator_type);
1468}