1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
//! PyFloat - Double Precision Floating Point Numbers
//!
//! ```ignore
//! float()
//! 1.23456
//! ```
//!
use std::fmt;
use std::borrow::Borrow;
use std::ops::Deref;

use num::Zero;
use num::ToPrimitive;

use runtime::Runtime;
use ::runtime::traits::{BooleanProvider, StringProvider, IntegerProvider, FloatProvider};
use ::api::result::Error;
use ::api::result::{RtResult, ObjectResult};
use api::{self, RtValue, method, typing};
use api::selfref::{self, SelfRef};

use ::system::primitives as rs;
use ::api::RtObject;
use ::modules::builtins::Type;
use objects::number::{self, FloatAdapter, IntAdapter};


#[derive(Clone)]
pub struct PyFloatType {}


impl typing::BuiltinType for PyFloatType {
    type T = PyFloat;
    type V = rs::Float;

    #[allow(unused_variables)]
    fn new(&self, rt: &Runtime, value: rs::Float) -> RtObject {
        // TODO: {T99} Investigate object interning, see the methodology in integer.rs.
        // Can that be generalized?
        PyFloatType::inject_selfref(PyFloatType::alloc(value))
    }

    fn init_type() -> Self {
        PyFloatType {}
    }

    fn inject_selfref(value: PyFloat) -> RtObject {
        let object = RtObject::new(Type::Float(value));
        let new = object.clone();

        match object.as_ref() {
            &Type::Float(ref int) => {
                int.rc.set(&object.clone());
            }
            _ => unreachable!(),
        }
        new
    }

    fn alloc(value: Self::V) -> Self::T {
        PyFloat {
            value: FloatValue(value),
            rc: selfref::RefCount::default(),
        }
    }
}


pub struct FloatValue(pub rs::Float);
pub type PyFloat = RtValue<FloatValue>;


impl fmt::Display for PyFloat {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.value.0)
    }
}

impl fmt::Debug for PyFloat {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self.value.0)
    }
}


impl api::PyAPI for PyFloat {}


impl method::Hashed for PyFloat {
    // TODO: {T87} python has its own algo for hashing floats ensure to look at that for compat.
}

impl method::StringCast for PyFloat {
    fn op_str(&self, rt: &Runtime) -> ObjectResult {
        match self.native_str() {
            Ok(string) => Ok(rt.str(string)),
            Err(_) => unreachable!(),
        }
    }

    fn native_str(&self) -> RtResult<rs::String> {
        Ok(number::format_float(&self.value.0))
    }
}


impl method::StringRepresentation for PyFloat {
    fn op_repr(&self, rt: &Runtime) -> ObjectResult {
        match self.native_repr() {
            Ok(string) => Ok(rt.str(string)),
            Err(_) => unreachable!(),
        }
    }

    fn native_repr(&self) -> RtResult<rs::String> {
        Ok(number::format_float(&self.value.0))
    }
}

impl method::Equal for PyFloat {
    fn op_eq(&self, rt: &Runtime, rhs: &RtObject) -> ObjectResult {
        match self.native_eq(rhs.as_ref()) {
            Ok(value) => Ok(rt.bool(value)),
            Err(err) => Err(err),
        }
    }

    fn native_eq(&self, other: &Type) -> RtResult<rs::Boolean> {
        match *other {
            Type::Float(ref float) => Ok(self.value.0 == float.value.0),
            Type::Int(ref int) => Ok(FloatAdapter(&self.value.0) == IntAdapter(&int.value.0)),
            _ => Ok(false),
        }
    }
}


impl method::BooleanCast for PyFloat {
    fn op_bool(&self, rt: &Runtime) -> ObjectResult {
        if self.native_bool()? {
            Ok(rt.bool(true))
        } else {
            Ok(rt.bool(false))
        }
    }

    fn native_bool(&self) -> RtResult<rs::Boolean> {
        return Ok(!self.value.0.is_zero());
    }
}

impl method::IntegerCast for PyFloat {
    fn op_int(&self, rt: &Runtime) -> ObjectResult {
        match self.native_int() {
            Ok(int) => Ok(rt.int(int)),
            _ => unreachable!()
        }
    }

    fn native_int(&self) -> RtResult<rs::Integer> {
        return Ok(rs::Integer::from(self.value.0 as i64));
    }
}

impl method::FloatCast for PyFloat {
    #[allow(unused_variables)]
    fn op_float(&self, rt: &Runtime) -> ObjectResult {
        self.rc.upgrade()
    }

    fn native_float(&self) -> RtResult<rs::Float> {
        return Ok(self.value.0);
    }
}


impl method::Add for PyFloat {
    fn op_add(&self, rt: &Runtime, rhs: &RtObject) -> ObjectResult {
        match rhs.as_ref(){
            &Type::Float(ref rhs) => {
                // TODO: {T103} Use checked arithmetic where appropriate... this is not the only
                // example. But the float (and some int) methods are likely to be the highest
                // frequency.
                Ok(rt.float(self.value.0 + rhs.value.0))
            }
            &Type::Int(ref rhs) => {
                match rhs.value.0.to_f64() {
                    Some(float) => Ok(rt.float(self.value.0 + float)),
                    None => Err(Error::overflow(&format!("{:?} + {} overflows", self.value.0, rhs.value.0))),
                }
            }
            other => Err(Error::typerr(&format!("Cannot add {} to float", other.debug_name()))),
        }
    }

}

method_not_implemented!(PyFloat,
    AbsValue   AddItem   Append   Await   
    BitwiseAnd   BitwiseOr   BytesCast   Call   
    Clear   Close   ComplexCast   Contains   
    Count   DelAttr   Delete   DeleteItem   
    DescriptorGet   DescriptorSet   DescriptorSetName   Discard   
    DivMod   Enter   Exit   Extend   
    FloorDivision   Get   GetAttr   GetAttribute   
    GetItem   GreaterOrEqual   GreaterThan   Id   
    Index   Init   InPlaceAdd   InPlaceBitwiseAnd   
    InPlaceBitwiseOr   InPlaceDivMod   InPlaceFloorDivision   InPlaceLeftShift   
    InPlaceMatrixMultiply   InPlaceModulus   InPlaceMultiply   InPlacePow   
    InPlaceRightShift   InPlaceSubtract   InPlaceTrueDivision   InPlaceXOr   
    InvertValue   Is   IsDisjoint   IsNot   
    Items   Iter   Keys   LeftShift   
    Length   LengthHint   LessOrEqual   LessThan   
    MatrixMultiply   Modulus   Multiply   NegateValue   
    New   Next   NotEqual   Pop   
    PopItem   PositiveValue   Pow   ReflectedAdd   
    ReflectedBitwiseAnd   ReflectedBitwiseOr   ReflectedDivMod   ReflectedFloorDivision   
    ReflectedLeftShift   ReflectedMatrixMultiply   ReflectedModulus   ReflectedMultiply   
    ReflectedPow   ReflectedRightShift   ReflectedSubtract   ReflectedTrueDivision   
    ReflectedXOr   Remove   Reversed   RightShift   
    Rounding   Send   SetAttr   SetDefault   
    SetItem   StringFormat   Subtract   Throw   
    TrueDivision   Update   Values   XOr
);


#[cfg(test)]
mod tests {
    use ::runtime::Runtime;

    fn setup() -> (Runtime, ) {
        (Runtime::new(), )
    }

    #[test]
    fn stub() {
        info!("stub");
    }
}