Skip to content

Commit c442d85

Browse files
constructor works
1 parent d64edb3 commit c442d85

File tree

1 file changed

+57
-16
lines changed

1 file changed

+57
-16
lines changed

src/python.rs

Lines changed: 57 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,17 @@
55

66
use crate::algebraic_numbers::RealAlgebraicNumber;
77
use num_bigint::BigInt;
8+
use num_bigint::Sign;
9+
use num_traits::ToPrimitive;
810
use num_traits::Zero;
911
use pyo3::prelude::*;
12+
use pyo3::types::IntoPyDict;
1013
use pyo3::types::PyAny;
14+
use pyo3::types::PyBytes;
1115
use pyo3::types::PyInt;
16+
use pyo3::types::PyType;
17+
use pyo3::PyNativeType;
18+
use pyo3::PyObjectProtocol;
1219

1320
// TODO: Switch to using BigInt's python conversions once they are implemented
1421
// see https://github.com/PyO3/pyo3/issues/543
@@ -17,15 +24,44 @@ pub struct PyBigInt(pub BigInt);
1724

1825
impl ToPyObject for PyBigInt {
1926
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+
}
2243
}
2344
}
2445

2546
impl FromPyObject<'_> for PyBigInt {
2647
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+
}
2965
}
3066
}
3167

@@ -34,25 +70,30 @@ struct RealAlgebraicNumberPy {
3470
value: RealAlgebraicNumber,
3571
}
3672

37-
#[pymethods]
73+
#[pymethods(PyObjectProtocol)]
3874
impl RealAlgebraicNumberPy {
3975
#[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(())
5083
}
5184
// FIXME: implement rest of methods
5285
}
5386

87+
#[pyproto]
88+
impl PyObjectProtocol for RealAlgebraicNumberPy {
89+
fn __repr__(&self) -> PyResult<String> {
90+
Ok(format!("{:?}", self.value))
91+
}
92+
}
93+
5494
#[pymodule]
55-
fn algebraics(py: Python, m: &PyModule) -> PyResult<()> {
95+
fn algebraics(_py: Python, m: &PyModule) -> PyResult<()> {
5696
// FIXME: add module members
97+
m.add_class::<RealAlgebraicNumberPy>()?;
5798
Ok(())
5899
}

0 commit comments

Comments
 (0)