rustpython_vm/function/
protocol.rs1use super::IntoFuncArgs;
2use crate::{
3 AsObject, PyObject, PyObjectRef, PyPayload, PyResult, TryFromObject, VirtualMachine,
4 builtins::{PyDictRef, iter::PySequenceIterator},
5 convert::ToPyObject,
6 object::{Traverse, TraverseFn},
7 protocol::{PyIter, PyIterIter, PyMapping},
8 types::GenericMethod,
9};
10use core::{borrow::Borrow, marker::PhantomData};
11
12#[derive(Clone, Traverse)]
13pub struct ArgCallable {
14 obj: PyObjectRef,
15 #[pytraverse(skip)]
16 call: GenericMethod,
17}
18
19impl ArgCallable {
20 #[inline(always)]
21 pub fn invoke(&self, args: impl IntoFuncArgs, vm: &VirtualMachine) -> PyResult {
22 let args = args.into_args(vm);
23 (self.call)(&self.obj, args, vm)
24 }
25}
26
27impl core::fmt::Debug for ArgCallable {
28 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
29 f.debug_struct("ArgCallable")
30 .field("obj", &self.obj)
31 .field("call", &format!("{:08x}", self.call as usize))
32 .finish()
33 }
34}
35
36impl Borrow<PyObject> for ArgCallable {
37 #[inline(always)]
38 fn borrow(&self) -> &PyObject {
39 &self.obj
40 }
41}
42
43impl AsRef<PyObject> for ArgCallable {
44 #[inline(always)]
45 fn as_ref(&self) -> &PyObject {
46 &self.obj
47 }
48}
49
50impl From<ArgCallable> for PyObjectRef {
51 #[inline(always)]
52 fn from(value: ArgCallable) -> Self {
53 value.obj
54 }
55}
56
57impl TryFromObject for ArgCallable {
58 fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
59 let Some(callable) = obj.to_callable() else {
60 return Err(vm.new_type_error(format!(
61 "'{}' object is not callable",
62 obj.class().slot_name()
63 )));
64 };
65 let call = callable.call;
66 Ok(Self { obj, call })
67 }
68}
69
70pub struct ArgIterable<T = PyObjectRef> {
78 iterable: PyObjectRef,
79 iter_fn: Option<crate::types::IterFunc>,
80 _item: PhantomData<T>,
81}
82
83unsafe impl<T: Traverse> Traverse for ArgIterable<T> {
84 fn traverse(&self, tracer_fn: &mut TraverseFn<'_>) {
85 self.iterable.traverse(tracer_fn)
86 }
87}
88
89impl<T> ArgIterable<T> {
90 #[must_use]
91 pub(crate) fn as_object(&self) -> &PyObject {
92 &self.iterable
93 }
94
95 fn get_iter(&self, vm: &VirtualMachine) -> PyResult<PyIter> {
100 Ok(PyIter::new(match self.iter_fn {
101 Some(f) => f(self.iterable.clone(), vm)?,
102 None => PySequenceIterator::new(self.iterable.clone(), vm)?.into_pyobject(vm),
103 }))
104 }
105
106 pub fn iter<'a>(&self, vm: &'a VirtualMachine) -> PyResult<PyIterIter<'a, T>> {
112 Ok(self.get_iter(vm)?.into_iter(vm))
113 }
114
115 pub fn iter_sized<'a>(&self, vm: &'a VirtualMachine) -> PyResult<PyIterIter<'a, T>> {
118 self.get_iter(vm)?.into_iter_sized(vm)
119 }
120}
121
122impl<T> TryFromObject for ArgIterable<T>
123where
124 T: TryFromObject,
125{
126 fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
127 let cls = obj.class();
128 let iter_fn = cls.slots.iter.load();
129 if iter_fn.is_none() && !cls.has_attr(identifier!(vm, __getitem__)) {
130 return Err(vm.new_type_error(format!("'{}' object is not iterable", cls.slot_name())));
131 }
132 Ok(Self {
133 iterable: obj,
134 iter_fn,
135 _item: PhantomData,
136 })
137 }
138}
139
140#[derive(Debug, Clone, Traverse)]
141pub struct ArgMapping {
142 obj: PyObjectRef,
143}
144
145impl ArgMapping {
146 #[inline]
147 #[must_use]
148 pub const fn new(obj: PyObjectRef) -> Self {
149 Self { obj }
150 }
151
152 #[inline(always)]
153 #[must_use]
154 pub fn from_dict_exact(dict: PyDictRef) -> Self {
155 Self { obj: dict.into() }
156 }
157
158 #[inline(always)]
159 #[must_use]
160 pub fn obj(&self) -> &PyObject {
161 &self.obj
162 }
163
164 #[inline(always)]
165 #[must_use]
166 pub fn mapping(&self) -> PyMapping<'_> {
167 self.obj.mapping_unchecked()
168 }
169}
170
171impl Borrow<PyObject> for ArgMapping {
172 #[inline(always)]
173 fn borrow(&self) -> &PyObject {
174 &self.obj
175 }
176}
177
178impl AsRef<PyObject> for ArgMapping {
179 #[inline(always)]
180 fn as_ref(&self) -> &PyObject {
181 &self.obj
182 }
183}
184
185impl From<ArgMapping> for PyObjectRef {
186 #[inline(always)]
187 fn from(value: ArgMapping) -> Self {
188 value.obj
189 }
190}
191
192impl ToPyObject for ArgMapping {
193 #[inline(always)]
194 fn to_pyobject(self, _vm: &VirtualMachine) -> PyObjectRef {
195 self.obj
196 }
197}
198
199impl TryFromObject for ArgMapping {
200 fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
201 let _mapping = obj.try_mapping(vm)?;
202 Ok(Self { obj })
203 }
204}
205
206#[derive(Clone)]
208pub struct ArgSequence<T = PyObjectRef>(Vec<T>);
209
210unsafe impl<T: Traverse> Traverse for ArgSequence<T> {
211 fn traverse(&self, tracer_fn: &mut TraverseFn<'_>) {
212 self.0.traverse(tracer_fn);
213 }
214}
215
216impl<T> ArgSequence<T> {
217 #[inline(always)]
218 #[must_use]
219 pub fn into_vec(self) -> Vec<T> {
220 self.0
221 }
222 #[inline(always)]
223 #[must_use]
224 pub fn as_slice(&self) -> &[T] {
225 &self.0
226 }
227}
228
229impl<T> core::ops::Deref for ArgSequence<T> {
230 type Target = [T];
231 #[inline(always)]
232 fn deref(&self) -> &[T] {
233 self.as_slice()
234 }
235}
236
237impl<'a, T> IntoIterator for &'a ArgSequence<T> {
238 type Item = &'a T;
239 type IntoIter = core::slice::Iter<'a, T>;
240 fn into_iter(self) -> Self::IntoIter {
241 self.iter()
242 }
243}
244impl<T> IntoIterator for ArgSequence<T> {
245 type Item = T;
246 type IntoIter = alloc::vec::IntoIter<T>;
247 fn into_iter(self) -> Self::IntoIter {
248 self.0.into_iter()
249 }
250}
251
252impl<T: TryFromObject> TryFromObject for ArgSequence<T> {
253 fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
254 obj.try_to_value(vm).map(Self)
255 }
256}