rustpython_vm/function/
protocol.rs1use super::IntoFuncArgs;
2use crate::{
3 builtins::{iter::PySequenceIterator, PyDict, PyDictRef},
4 convert::ToPyObject,
5 identifier,
6 object::{Traverse, TraverseFn},
7 protocol::{PyIter, PyIterIter, PyMapping, PyMappingMethods},
8 types::{AsMapping, GenericMethod},
9 AsObject, PyObject, PyObjectRef, PyPayload, PyResult, TryFromObject, VirtualMachine,
10};
11use std::{borrow::Borrow, marker::PhantomData, ops::Deref};
12
13#[derive(Clone, Traverse)]
14pub struct ArgCallable {
15 obj: PyObjectRef,
16 #[pytraverse(skip)]
17 call: GenericMethod,
18}
19
20impl ArgCallable {
21 #[inline(always)]
22 pub fn invoke(&self, args: impl IntoFuncArgs, vm: &VirtualMachine) -> PyResult {
23 let args = args.into_args(vm);
24 (self.call)(&self.obj, args, vm)
25 }
26}
27
28impl std::fmt::Debug for ArgCallable {
29 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30 f.debug_struct("ArgCallable")
31 .field("obj", &self.obj)
32 .field("call", &format!("{:08x}", self.call as usize))
33 .finish()
34 }
35}
36
37impl Borrow<PyObject> for ArgCallable {
38 #[inline(always)]
39 fn borrow(&self) -> &PyObject {
40 &self.obj
41 }
42}
43
44impl AsRef<PyObject> for ArgCallable {
45 #[inline(always)]
46 fn as_ref(&self) -> &PyObject {
47 &self.obj
48 }
49}
50
51impl From<ArgCallable> for PyObjectRef {
52 #[inline(always)]
53 fn from(value: ArgCallable) -> PyObjectRef {
54 value.obj
55 }
56}
57
58impl TryFromObject for ArgCallable {
59 fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
60 let Some(callable) = obj.to_callable() else {
61 return Err(
62 vm.new_type_error(format!("'{}' object is not callable", obj.class().name()))
63 );
64 };
65 let call = callable.call;
66 Ok(ArgCallable { obj, call })
67 }
68}
69
70pub struct ArgIterable<T = PyObjectRef> {
78 iterable: PyObjectRef,
79 iterfn: 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 pub fn iter<'a>(&self, vm: &'a VirtualMachine) -> PyResult<PyIterIter<'a, T>> {
95 let iter = PyIter::new(match self.iterfn {
96 Some(f) => f(self.iterable.clone(), vm)?,
97 None => PySequenceIterator::new(self.iterable.clone(), vm)?.into_pyobject(vm),
98 });
99 iter.into_iter(vm)
100 }
101}
102
103impl<T> TryFromObject for ArgIterable<T>
104where
105 T: TryFromObject,
106{
107 fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
108 let iterfn = {
109 let cls = obj.class();
110 let iterfn = cls.mro_find_map(|x| x.slots.iter.load());
111 if iterfn.is_none() && !cls.has_attr(identifier!(vm, __getitem__)) {
112 return Err(vm.new_type_error(format!("'{}' object is not iterable", cls.name())));
113 }
114 iterfn
115 };
116 Ok(Self {
117 iterable: obj,
118 iterfn,
119 _item: PhantomData,
120 })
121 }
122}
123
124#[derive(Debug, Clone, Traverse)]
125pub struct ArgMapping {
126 obj: PyObjectRef,
127 #[pytraverse(skip)]
128 methods: &'static PyMappingMethods,
129}
130
131impl ArgMapping {
132 #[inline]
133 pub fn with_methods(obj: PyObjectRef, methods: &'static PyMappingMethods) -> Self {
134 Self { obj, methods }
135 }
136
137 #[inline(always)]
138 pub fn from_dict_exact(dict: PyDictRef) -> Self {
139 Self {
140 obj: dict.into(),
141 methods: PyDict::as_mapping(),
142 }
143 }
144
145 #[inline(always)]
146 pub fn mapping(&self) -> PyMapping {
147 PyMapping {
148 obj: &self.obj,
149 methods: self.methods,
150 }
151 }
152}
153
154impl Borrow<PyObject> for ArgMapping {
155 #[inline(always)]
156 fn borrow(&self) -> &PyObject {
157 &self.obj
158 }
159}
160
161impl AsRef<PyObject> for ArgMapping {
162 #[inline(always)]
163 fn as_ref(&self) -> &PyObject {
164 &self.obj
165 }
166}
167
168impl Deref for ArgMapping {
169 type Target = PyObject;
170 #[inline(always)]
171 fn deref(&self) -> &PyObject {
172 &self.obj
173 }
174}
175
176impl From<ArgMapping> for PyObjectRef {
177 #[inline(always)]
178 fn from(value: ArgMapping) -> PyObjectRef {
179 value.obj
180 }
181}
182
183impl ToPyObject for ArgMapping {
184 #[inline(always)]
185 fn to_pyobject(self, _vm: &VirtualMachine) -> PyObjectRef {
186 self.obj
187 }
188}
189
190impl TryFromObject for ArgMapping {
191 fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
192 let mapping = PyMapping::try_protocol(&obj, vm)?;
193 let methods = mapping.methods;
194 Ok(Self { obj, methods })
195 }
196}
197
198#[derive(Clone)]
200pub struct ArgSequence<T = PyObjectRef>(Vec<T>);
201
202unsafe impl<T: Traverse> Traverse for ArgSequence<T> {
203 fn traverse(&self, tracer_fn: &mut TraverseFn) {
204 self.0.traverse(tracer_fn);
205 }
206}
207
208impl<T> ArgSequence<T> {
209 #[inline(always)]
210 pub fn into_vec(self) -> Vec<T> {
211 self.0
212 }
213 #[inline(always)]
214 pub fn as_slice(&self) -> &[T] {
215 &self.0
216 }
217}
218
219impl<T> std::ops::Deref for ArgSequence<T> {
220 type Target = [T];
221 #[inline(always)]
222 fn deref(&self) -> &[T] {
223 self.as_slice()
224 }
225}
226
227impl<T: TryFromObject> TryFromObject for ArgSequence<T> {
228 fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
229 obj.try_to_value(vm).map(Self)
230 }
231}