5
5
6
6
use crate :: algebraic_numbers:: RealAlgebraicNumber ;
7
7
use num_bigint:: BigInt ;
8
+ use num_bigint:: Sign ;
9
+ use num_traits:: ToPrimitive ;
8
10
use num_traits:: Zero ;
9
11
use pyo3:: prelude:: * ;
12
+ use pyo3:: types:: IntoPyDict ;
10
13
use pyo3:: types:: PyAny ;
14
+ use pyo3:: types:: PyBytes ;
11
15
use pyo3:: types:: PyInt ;
16
+ use pyo3:: types:: PyType ;
17
+ use pyo3:: PyNativeType ;
18
+ use pyo3:: PyObjectProtocol ;
12
19
13
20
// TODO: Switch to using BigInt's python conversions once they are implemented
14
21
// see https://github.com/PyO3/pyo3/issues/543
@@ -17,15 +24,44 @@ pub struct PyBigInt(pub BigInt);
17
24
18
25
impl ToPyObject for PyBigInt {
19
26
fn to_object ( & self , py : Python ) -> PyObject {
20
- // FIXME: implement
21
- unimplemented ! ( )
27
+ if let Some ( value) = self . 0 . to_i64 ( ) {
28
+ value. to_object ( py)
29
+ } else {
30
+ let ( sign, bytes) = self . 0 . to_bytes_le ( ) ;
31
+ let int_type: & PyType = py. get_type :: < PyInt > ( ) ;
32
+ let retval = int_type
33
+ . call_method1 ( "from_bytes" , ( bytes, "little" ) )
34
+ . unwrap ( )
35
+ . downcast_ref :: < PyInt > ( )
36
+ . unwrap ( ) ;
37
+ if sign == Sign :: Minus {
38
+ retval. call_method0 ( "__neg__" ) . unwrap ( ) . to_object ( py)
39
+ } else {
40
+ retval. to_object ( py)
41
+ }
42
+ }
22
43
}
23
44
}
24
45
25
46
impl FromPyObject < ' _ > for PyBigInt {
26
47
fn extract ( ob : & PyAny ) -> PyResult < Self > {
27
- // FIXME: implement
28
- unimplemented ! ( )
48
+ let value = ob. downcast_ref :: < PyInt > ( ) ?;
49
+ if let Ok ( value) = value. extract :: < i64 > ( ) {
50
+ Ok ( PyBigInt ( value. into ( ) ) )
51
+ } else {
52
+ let mut len = 32 ;
53
+ let bytes = loop {
54
+ match value. call_method (
55
+ "to_bytes" ,
56
+ ( len, "little" ) ,
57
+ Some ( [ ( "signed" , true ) ] . into_py_dict ( ob. py ( ) ) ) ,
58
+ ) {
59
+ Ok ( bytes) => break bytes. downcast_ref :: < PyBytes > ( ) ?,
60
+ Err ( _) => len *= 2 ,
61
+ }
62
+ } ;
63
+ Ok ( PyBigInt ( BigInt :: from_signed_bytes_le ( bytes. as_bytes ( ) ) ) )
64
+ }
29
65
}
30
66
}
31
67
@@ -34,25 +70,30 @@ struct RealAlgebraicNumberPy {
34
70
value : RealAlgebraicNumber ,
35
71
}
36
72
37
- #[ pymethods]
73
+ #[ pymethods( PyObjectProtocol ) ]
38
74
impl RealAlgebraicNumberPy {
39
75
#[ new]
40
- fn new ( obj : & PyRawObject , value : Option < & PyInt > ) {
41
- match value {
42
- None => obj. init ( RealAlgebraicNumberPy {
43
- value : RealAlgebraicNumber :: zero ( ) ,
44
- } ) ,
45
- Some ( value) => {
46
- // FIXME: implement
47
- unimplemented ! ( ) ;
48
- }
49
- }
76
+ fn pynew ( obj : & PyRawObject , value : Option < & PyInt > ) -> PyResult < ( ) > {
77
+ let value = match value {
78
+ None => RealAlgebraicNumber :: zero ( ) ,
79
+ Some ( value) => RealAlgebraicNumber :: from ( value. extract :: < PyBigInt > ( ) ?. 0 ) ,
80
+ } ;
81
+ obj. init ( RealAlgebraicNumberPy { value } ) ;
82
+ Ok ( ( ) )
50
83
}
51
84
// FIXME: implement rest of methods
52
85
}
53
86
87
+ #[ pyproto]
88
+ impl PyObjectProtocol for RealAlgebraicNumberPy {
89
+ fn __repr__ ( & self ) -> PyResult < String > {
90
+ Ok ( format ! ( "{:?}" , self . value) )
91
+ }
92
+ }
93
+
54
94
#[ pymodule]
55
- fn algebraics ( py : Python , m : & PyModule ) -> PyResult < ( ) > {
95
+ fn algebraics ( _py : Python , m : & PyModule ) -> PyResult < ( ) > {
56
96
// FIXME: add module members
97
+ m. add_class :: < RealAlgebraicNumberPy > ( ) ?;
57
98
Ok ( ( ) )
58
99
}
0 commit comments