@@ -4,13 +4,14 @@ use super::objstr;
4
4
use super :: objtype;
5
5
use crate :: obj:: objtype:: PyClassRef ;
6
6
use crate :: pyobject:: {
7
- IntoPyObject , PyContext , PyObjectRef , PyRef , PyResult , PyValue , TypeProtocol ,
7
+ IntoPyObject , PyClassImpl , PyContext , PyObjectRef , PyRef , PyResult , PyValue , TypeProtocol ,
8
8
} ;
9
9
use crate :: vm:: VirtualMachine ;
10
- use num_bigint:: ToBigInt ;
10
+ use num_bigint:: { BigInt , ToBigInt } ;
11
11
use num_rational:: Ratio ;
12
12
use num_traits:: ToPrimitive ;
13
13
14
+ #[ pyclass( name = "float" ) ]
14
15
#[ derive( Debug , Copy , Clone , PartialEq ) ]
15
16
pub struct PyFloat {
16
17
value : f64 ,
@@ -40,7 +41,17 @@ impl From<f64> for PyFloat {
40
41
}
41
42
}
42
43
44
+ fn mod_ ( v1 : f64 , v2 : f64 , vm : & VirtualMachine ) -> PyResult {
45
+ if v2 != 0.0 {
46
+ Ok ( vm. ctx . new_float ( v1 % v2) )
47
+ } else {
48
+ Err ( vm. new_zero_division_error ( "float mod by zero" . to_string ( ) ) )
49
+ }
50
+ }
51
+
52
+ #[ pyimpl]
43
53
impl PyFloat {
54
+ #[ pymethod( name = "__eq__" ) ]
44
55
fn eq ( & self , other : PyObjectRef , vm : & VirtualMachine ) -> PyObjectRef {
45
56
let value = self . value ;
46
57
let result = if objtype:: isinstance ( & other, & vm. ctx . float_type ( ) ) {
@@ -60,6 +71,7 @@ impl PyFloat {
60
71
vm. ctx . new_bool ( result)
61
72
}
62
73
74
+ #[ pymethod( name = "__lt__" ) ]
63
75
fn lt ( & self , i2 : PyObjectRef , vm : & VirtualMachine ) -> PyObjectRef {
64
76
let v1 = self . value ;
65
77
if objtype:: isinstance ( & i2, & vm. ctx . float_type ( ) ) {
@@ -72,6 +84,7 @@ impl PyFloat {
72
84
}
73
85
}
74
86
87
+ #[ pymethod( name = "__le__" ) ]
75
88
fn le ( & self , i2 : PyObjectRef , vm : & VirtualMachine ) -> PyObjectRef {
76
89
let v1 = self . value ;
77
90
if objtype:: isinstance ( & i2, & vm. ctx . float_type ( ) ) {
@@ -84,6 +97,7 @@ impl PyFloat {
84
97
}
85
98
}
86
99
100
+ #[ pymethod( name = "__gt__" ) ]
87
101
fn gt ( & self , i2 : PyObjectRef , vm : & VirtualMachine ) -> PyObjectRef {
88
102
let v1 = self . value ;
89
103
if objtype:: isinstance ( & i2, & vm. ctx . float_type ( ) ) {
@@ -96,6 +110,7 @@ impl PyFloat {
96
110
}
97
111
}
98
112
113
+ #[ pymethod( name = "__ge__" ) ]
99
114
fn ge ( & self , i2 : PyObjectRef , vm : & VirtualMachine ) -> PyObjectRef {
100
115
let v1 = self . value ;
101
116
if objtype:: isinstance ( & i2, & vm. ctx . float_type ( ) ) {
@@ -108,10 +123,12 @@ impl PyFloat {
108
123
}
109
124
}
110
125
126
+ #[ pymethod( name = "__abs__" ) ]
111
127
fn abs ( & self , _vm : & VirtualMachine ) -> f64 {
112
128
self . value . abs ( )
113
129
}
114
130
131
+ #[ pymethod( name = "__add__" ) ]
115
132
fn add ( & self , other : PyObjectRef , vm : & VirtualMachine ) -> PyObjectRef {
116
133
let v1 = self . value ;
117
134
if objtype:: isinstance ( & other, & vm. ctx . float_type ( ) ) {
@@ -124,10 +141,17 @@ impl PyFloat {
124
141
}
125
142
}
126
143
144
+ #[ pymethod( name = "__radd__" ) ]
145
+ fn radd ( & self , other : PyObjectRef , vm : & VirtualMachine ) -> PyObjectRef {
146
+ self . add ( other, vm)
147
+ }
148
+
149
+ #[ pymethod( name = "__bool__" ) ]
127
150
fn bool ( & self , _vm : & VirtualMachine ) -> bool {
128
151
self . value != 0.0
129
152
}
130
153
154
+ #[ pymethod( name = "__divmod__" ) ]
131
155
fn divmod ( & self , other : PyObjectRef , vm : & VirtualMachine ) -> PyResult {
132
156
if objtype:: isinstance ( & other, & vm. ctx . float_type ( ) )
133
157
|| objtype:: isinstance ( & other, & vm. ctx . int_type ( ) )
@@ -140,14 +164,13 @@ impl PyFloat {
140
164
}
141
165
}
142
166
167
+ #[ pymethod( name = "__floordiv__" ) ]
143
168
fn floordiv ( & self , other : PyObjectRef , vm : & VirtualMachine ) -> PyResult {
144
169
let v1 = self . value ;
145
170
let v2 = if objtype:: isinstance ( & other, & vm. ctx . float_type ) {
146
171
get_value ( & other)
147
172
} else if objtype:: isinstance ( & other, & vm. ctx . int_type ) {
148
- objint:: get_value ( & other) . to_f64 ( ) . ok_or_else ( || {
149
- vm. new_overflow_error ( "int too large to convert to float" . to_string ( ) )
150
- } ) ?
173
+ objint:: get_float_value ( & other, vm) ?
151
174
} else {
152
175
return Ok ( vm. ctx . not_implemented ( ) ) ;
153
176
} ;
@@ -163,12 +186,10 @@ impl PyFloat {
163
186
let value = if objtype:: isinstance ( & arg, & vm. ctx . float_type ( ) ) {
164
187
get_value ( & arg)
165
188
} else if objtype:: isinstance ( & arg, & vm. ctx . int_type ( ) ) {
166
- match objint:: get_value ( & arg) . to_f64 ( ) {
167
- Some ( f) => f,
168
- None => {
169
- return Err (
170
- vm. new_overflow_error ( "int too large to convert to float" . to_string ( ) )
171
- ) ;
189
+ match objint:: get_float_value ( & arg, vm) {
190
+ Ok ( f) => f,
191
+ Err ( e) => {
192
+ return Err ( e) ;
172
193
}
173
194
}
174
195
} else if objtype:: isinstance ( & arg, & vm. ctx . str_type ( ) ) {
@@ -199,29 +220,38 @@ impl PyFloat {
199
220
PyFloat { value } . into_ref_with_type ( vm, cls)
200
221
}
201
222
223
+ #[ pymethod( name = "__mod__" ) ]
202
224
fn mod_ ( & self , other : PyObjectRef , vm : & VirtualMachine ) -> PyResult {
203
225
let v1 = self . value ;
204
226
let v2 = if objtype:: isinstance ( & other, & vm. ctx . float_type ) {
205
227
get_value ( & other)
206
228
} else if objtype:: isinstance ( & other, & vm. ctx . int_type ) {
207
- objint:: get_value ( & other) . to_f64 ( ) . ok_or_else ( || {
208
- vm. new_overflow_error ( "int too large to convert to float" . to_string ( ) )
209
- } ) ?
229
+ objint:: get_float_value ( & other, vm) ?
210
230
} else {
211
231
return Ok ( vm. ctx . not_implemented ( ) ) ;
212
232
} ;
213
233
214
- if v2 != 0.0 {
215
- Ok ( vm. ctx . new_float ( v1 % v2) )
234
+ mod_ ( v1, v2, vm)
235
+ }
236
+
237
+ #[ pymethod( name = "__rmod__" ) ]
238
+ fn rmod ( & self , other : PyObjectRef , vm : & VirtualMachine ) -> PyResult {
239
+ let v2 = self . value ;
240
+ let v1 = if objtype:: isinstance ( & other, & vm. ctx . int_type ) {
241
+ objint:: get_float_value ( & other, vm) ?
216
242
} else {
217
- Err ( vm. new_zero_division_error ( "float mod by zero" . to_string ( ) ) )
218
- }
243
+ return Ok ( vm. ctx . not_implemented ( ) ) ;
244
+ } ;
245
+
246
+ mod_ ( v1, v2, vm)
219
247
}
220
248
249
+ #[ pymethod( name = "__neg__" ) ]
221
250
fn neg ( & self , _vm : & VirtualMachine ) -> f64 {
222
251
-self . value
223
252
}
224
253
254
+ #[ pymethod( name = "__pow__" ) ]
225
255
fn pow ( & self , other : PyObjectRef , vm : & VirtualMachine ) -> PyObjectRef {
226
256
let v1 = self . value ;
227
257
if objtype:: isinstance ( & other, & vm. ctx . float_type ( ) ) {
@@ -234,6 +264,7 @@ impl PyFloat {
234
264
}
235
265
}
236
266
267
+ #[ pymethod( name = "__sub__" ) ]
237
268
fn sub ( & self , other : PyObjectRef , vm : & VirtualMachine ) -> PyResult {
238
269
let v1 = self . value ;
239
270
if objtype:: isinstance ( & other, & vm. ctx . float_type ( ) ) {
@@ -247,6 +278,7 @@ impl PyFloat {
247
278
}
248
279
}
249
280
281
+ #[ pymethod( name = "__rsub__" ) ]
250
282
fn rsub ( & self , other : PyObjectRef , vm : & VirtualMachine ) -> PyResult {
251
283
let v1 = self . value ;
252
284
if objtype:: isinstance ( & other, & vm. ctx . float_type ( ) ) {
@@ -260,18 +292,18 @@ impl PyFloat {
260
292
}
261
293
}
262
294
295
+ #[ pymethod( name = "__repr__" ) ]
263
296
fn repr ( & self , _vm : & VirtualMachine ) -> String {
264
297
self . value . to_string ( )
265
298
}
266
299
300
+ #[ pymethod( name = "__truediv__" ) ]
267
301
fn truediv ( & self , other : PyObjectRef , vm : & VirtualMachine ) -> PyResult {
268
302
let v1 = self . value ;
269
303
let v2 = if objtype:: isinstance ( & other, & vm. ctx . float_type ) {
270
304
get_value ( & other)
271
305
} else if objtype:: isinstance ( & other, & vm. ctx . int_type ) {
272
- objint:: get_value ( & other) . to_f64 ( ) . ok_or_else ( || {
273
- vm. new_overflow_error ( "int too large to convert to float" . to_string ( ) )
274
- } ) ?
306
+ objint:: get_float_value ( & other, vm) ?
275
307
} else {
276
308
return Ok ( vm. ctx . not_implemented ( ) ) ;
277
309
} ;
@@ -283,14 +315,13 @@ impl PyFloat {
283
315
}
284
316
}
285
317
318
+ #[ pymethod( name = "__rtruediv__" ) ]
286
319
fn rtruediv ( & self , other : PyObjectRef , vm : & VirtualMachine ) -> PyResult {
287
320
let v1 = self . value ;
288
321
let v2 = if objtype:: isinstance ( & other, & vm. ctx . float_type ) {
289
322
get_value ( & other)
290
323
} else if objtype:: isinstance ( & other, & vm. ctx . int_type ) {
291
- objint:: get_value ( & other) . to_f64 ( ) . ok_or_else ( || {
292
- vm. new_overflow_error ( "int too large to convert to float" . to_string ( ) )
293
- } ) ?
324
+ objint:: get_float_value ( & other, vm) ?
294
325
} else {
295
326
return Ok ( vm. ctx . not_implemented ( ) ) ;
296
327
} ;
@@ -302,6 +333,7 @@ impl PyFloat {
302
333
}
303
334
}
304
335
336
+ #[ pymethod( name = "__mul__" ) ]
305
337
fn mul ( & self , other : PyObjectRef , vm : & VirtualMachine ) -> PyResult {
306
338
let v1 = self . value ;
307
339
if objtype:: isinstance ( & other, & vm. ctx . float_type ) {
@@ -315,15 +347,38 @@ impl PyFloat {
315
347
}
316
348
}
317
349
350
+ #[ pymethod( name = "__rmul__" ) ]
351
+ fn rmul ( & self , other : PyObjectRef , vm : & VirtualMachine ) -> PyResult {
352
+ self . mul ( other, vm)
353
+ }
354
+
355
+ #[ pymethod( name = "__trunc__" ) ]
356
+ fn trunc ( & self , _vm : & VirtualMachine ) -> BigInt {
357
+ self . value . to_bigint ( ) . unwrap ( )
358
+ }
359
+
360
+ #[ pymethod( name = "__int__" ) ]
361
+ fn int ( & self , vm : & VirtualMachine ) -> BigInt {
362
+ self . trunc ( vm)
363
+ }
364
+
365
+ #[ pymethod( name = "__float__" ) ]
366
+ fn float ( zelf : PyRef < Self > , _vm : & VirtualMachine ) -> PyFloatRef {
367
+ zelf
368
+ }
369
+
370
+ #[ pyproperty( name = "real" ) ]
318
371
fn real ( zelf : PyRef < Self > , _vm : & VirtualMachine ) -> PyFloatRef {
319
372
zelf
320
373
}
321
374
375
+ #[ pymethod( name = "is_integer" ) ]
322
376
fn is_integer ( & self , _vm : & VirtualMachine ) -> bool {
323
377
let v = self . value ;
324
378
( v - v. round ( ) ) . abs ( ) < std:: f64:: EPSILON
325
379
}
326
380
381
+ #[ pymethod( name = "as_integer_ratio" ) ]
327
382
fn as_integer_ratio ( & self , vm : & VirtualMachine ) -> PyResult {
328
383
let value = self . value ;
329
384
if value. is_infinite ( ) {
@@ -362,36 +417,10 @@ pub fn make_float(vm: &VirtualMachine, obj: &PyObjectRef) -> PyResult<f64> {
362
417
363
418
#[ rustfmt:: skip] // to avoid line splitting
364
419
pub fn init ( context : & PyContext ) {
365
- let float_type = & context. float_type ;
366
-
420
+ PyFloat :: extend_class ( context, & context. float_type ) ;
367
421
let float_doc = "Convert a string or number to a floating point number, if possible." ;
368
-
369
- extend_class ! ( context, float_type, {
370
- "__eq__" => context. new_rustfunc( PyFloat :: eq) ,
371
- "__lt__" => context. new_rustfunc( PyFloat :: lt) ,
372
- "__le__" => context. new_rustfunc( PyFloat :: le) ,
373
- "__gt__" => context. new_rustfunc( PyFloat :: gt) ,
374
- "__ge__" => context. new_rustfunc( PyFloat :: ge) ,
375
- "__abs__" => context. new_rustfunc( PyFloat :: abs) ,
376
- "__add__" => context. new_rustfunc( PyFloat :: add) ,
377
- "__radd__" => context. new_rustfunc( PyFloat :: add) ,
378
- "__bool__" => context. new_rustfunc( PyFloat :: bool ) ,
379
- "__divmod__" => context. new_rustfunc( PyFloat :: divmod) ,
380
- "__floordiv__" => context. new_rustfunc( PyFloat :: floordiv) ,
422
+ extend_class ! ( context, & context. float_type, {
381
423
"__new__" => context. new_rustfunc( PyFloat :: new_float) ,
382
- "__mod__" => context. new_rustfunc( PyFloat :: mod_) ,
383
- "__neg__" => context. new_rustfunc( PyFloat :: neg) ,
384
- "__pow__" => context. new_rustfunc( PyFloat :: pow) ,
385
- "__sub__" => context. new_rustfunc( PyFloat :: sub) ,
386
- "__rsub__" => context. new_rustfunc( PyFloat :: rsub) ,
387
- "__repr__" => context. new_rustfunc( PyFloat :: repr) ,
388
424
"__doc__" => context. new_str( float_doc. to_string( ) ) ,
389
- "__truediv__" => context. new_rustfunc( PyFloat :: truediv) ,
390
- "__rtruediv__" => context. new_rustfunc( PyFloat :: rtruediv) ,
391
- "__mul__" => context. new_rustfunc( PyFloat :: mul) ,
392
- "__rmul__" => context. new_rustfunc( PyFloat :: mul) ,
393
- "real" => context. new_property( PyFloat :: real) ,
394
- "is_integer" => context. new_rustfunc( PyFloat :: is_integer) ,
395
- "as_integer_ratio" => context. new_rustfunc( PyFloat :: as_integer_ratio)
396
425
} ) ;
397
426
}
0 commit comments