rustpython_vm/function/
number.rs

1use super::argument::OptionalArg;
2use crate::{builtins::PyIntRef, AsObject, PyObjectRef, PyResult, TryFromObject, VirtualMachine};
3use malachite_bigint::BigInt;
4use num_complex::Complex64;
5use num_traits::PrimInt;
6use std::ops::Deref;
7
8/// A Python complex-like object.
9///
10/// `ArgIntoComplex` implements `FromArgs` so that a built-in function can accept
11/// any object that can be transformed into a complex.
12///
13/// If the object is not a Python complex object but has a `__complex__()`
14/// method, this method will first be called to convert the object into a float.
15/// If `__complex__()` is not defined then it falls back to `__float__()`. If
16/// `__float__()` is not defined it falls back to `__index__()`.
17#[derive(Debug, PartialEq)]
18#[repr(transparent)]
19pub struct ArgIntoComplex {
20    value: Complex64,
21}
22
23impl From<ArgIntoComplex> for Complex64 {
24    fn from(arg: ArgIntoComplex) -> Self {
25        arg.value
26    }
27}
28
29impl Deref for ArgIntoComplex {
30    type Target = Complex64;
31
32    fn deref(&self) -> &Self::Target {
33        &self.value
34    }
35}
36
37impl TryFromObject for ArgIntoComplex {
38    // Equivalent to PyComplex_AsCComplex
39    fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
40        // We do not care if it was already a complex.
41        let (value, _) = obj.try_complex(vm)?.ok_or_else(|| {
42            vm.new_type_error(format!("must be real number, not {}", obj.class().name()))
43        })?;
44        Ok(ArgIntoComplex { value })
45    }
46}
47
48/// A Python float-like object.
49///
50/// `ArgIntoFloat` implements `FromArgs` so that a built-in function can accept
51/// any object that can be transformed into a float.
52///
53/// If the object is not a Python floating point object but has a `__float__()`
54/// method, this method will first be called to convert the object into a float.
55/// If `__float__()` is not defined then it falls back to `__index__()`.
56#[derive(Debug, PartialEq)]
57#[repr(transparent)]
58pub struct ArgIntoFloat {
59    value: f64,
60}
61
62impl ArgIntoFloat {
63    pub fn vec_into_f64(v: Vec<Self>) -> Vec<f64> {
64        // TODO: Vec::into_raw_parts once stabilized
65        let mut v = std::mem::ManuallyDrop::new(v);
66        let (p, l, c) = (v.as_mut_ptr(), v.len(), v.capacity());
67        // SAFETY: IntoPyFloat is repr(transparent) over f64
68        unsafe { Vec::from_raw_parts(p.cast(), l, c) }
69    }
70}
71
72impl From<ArgIntoFloat> for f64 {
73    fn from(arg: ArgIntoFloat) -> Self {
74        arg.value
75    }
76}
77
78impl Deref for ArgIntoFloat {
79    type Target = f64;
80    fn deref(&self) -> &Self::Target {
81        &self.value
82    }
83}
84
85impl TryFromObject for ArgIntoFloat {
86    // Equivalent to PyFloat_AsDouble.
87    fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
88        let value = obj.try_float(vm)?.to_f64();
89        Ok(ArgIntoFloat { value })
90    }
91}
92
93/// A Python bool-like object.
94///
95/// `ArgIntoBool` implements `FromArgs` so that a built-in function can accept
96/// any object that can be transformed into a boolean.
97///
98/// By default an object is considered true unless its class defines either a
99/// `__bool__()` method that returns False or a `__len__()` method that returns
100/// zero, when called with the object.
101#[derive(Debug, Default, PartialEq, Eq)]
102pub struct ArgIntoBool {
103    value: bool,
104}
105
106impl ArgIntoBool {
107    pub const TRUE: Self = Self { value: true };
108    pub const FALSE: Self = Self { value: false };
109}
110
111impl From<ArgIntoBool> for bool {
112    fn from(arg: ArgIntoBool) -> Self {
113        arg.value
114    }
115}
116
117impl Deref for ArgIntoBool {
118    type Target = bool;
119    fn deref(&self) -> &Self::Target {
120        &self.value
121    }
122}
123
124impl TryFromObject for ArgIntoBool {
125    fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
126        Ok(Self {
127            value: obj.try_to_bool(vm)?,
128        })
129    }
130}
131
132// Implement ArgIndex to separate between "true" int and int generated by index
133#[derive(Debug, Traverse)]
134#[repr(transparent)]
135pub struct ArgIndex {
136    value: PyIntRef,
137}
138
139impl From<ArgIndex> for PyIntRef {
140    fn from(arg: ArgIndex) -> Self {
141        arg.value
142    }
143}
144
145impl Deref for ArgIndex {
146    type Target = PyIntRef;
147
148    fn deref(&self) -> &Self::Target {
149        &self.value
150    }
151}
152
153impl TryFromObject for ArgIndex {
154    fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
155        Ok(Self {
156            value: obj.try_index(vm)?,
157        })
158    }
159}
160
161#[derive(Debug)]
162#[repr(transparent)]
163pub struct ArgPrimitiveIndex<T> {
164    pub value: T,
165}
166
167impl<T> OptionalArg<ArgPrimitiveIndex<T>> {
168    pub fn into_primitive(self) -> OptionalArg<T> {
169        self.map(|x| x.value)
170    }
171}
172
173impl<T> Deref for ArgPrimitiveIndex<T> {
174    type Target = T;
175
176    fn deref(&self) -> &Self::Target {
177        &self.value
178    }
179}
180
181impl<T> TryFromObject for ArgPrimitiveIndex<T>
182where
183    T: PrimInt + for<'a> TryFrom<&'a BigInt>,
184{
185    fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
186        Ok(Self {
187            value: obj.try_index(vm)?.try_to_primitive(vm)?,
188        })
189    }
190}
191
192pub type ArgSize = ArgPrimitiveIndex<isize>;
193
194impl From<ArgSize> for isize {
195    fn from(arg: ArgSize) -> Self {
196        arg.value
197    }
198}
Morty Proxy This is a proxified and sanitized view of the page, visit original site.